/*
	HeXen INFO.c processor, by Frans P. de Vries.

Derived from:

	DooM MaP StaTistics, by Frans P. de Vries.

	You are allowed to use any parts of this code in another program, as
	long as you give credits to the authors in the documentation and in
	the program itself.  Read the file README for more information.

	This program comes with absolutely no warranty.

	PRINT.C - Print routines.
*/

#include "../common/print.h"
#include "../common/things.h"
#include "../common/maps.h"
#include "../common/stub.h"


/*
	the global variables
*/
extern sfxinfo_t S_sfx[];
extern int WeaponManaUse[][NUMWEAPONS];

/*
	the local function prototypes
*/
void PrintSound(char *, int);
char *LookupSoundTag( char *);
void PrintWpnMana( weapontype_t, pclass_t);
void PrintShotsPM( mobjinfo_t *);
void PrintWpnShotsPM( weapontype_t, pclass_t);
void PrintWpnSprites( weapontype_t, pclass_t);


/*
	the weapon print data function
*/
void PrintWeapon()
{
	if (Weap < 0 || Weap >= NUMWEAPONS)
		ProgError( "no such Weapon %d", Weap);
	if (Clss < 0 || Clss >= NUMCLASSES)
		ProgError( "no such Class %d", Clss);

	if (XWik)
	{
		tpldata = TMPL_add_var( tpldata, "NAME", Wpn2Str( Weap, Clss), NULL);
		memset(fieldlist, 0, LISTSIZE);
		memset(field2list, 0, LISTSIZE);
	}
	else
	{
		printf( "\n");
		printf( "Weapon\t\t%s\n", Wpn2Str( Weap, Clss));
	}
	PrintWpnMana( Weap, Clss);
	if (!XWik)
		printf( "\n");
	PrintWpnShotsPM( Weap, Clss);
	PrintWpnSprites( Weap, Clss);

	if (XWik)
	{
		tpldata = TMPL_add_var( tpldata, "STATELIST", fieldlist, NULL);
		if (weaponthing[Weap][Clss] != -1)
		{
			Thng = weaponthing[Weap][Clss];
			PrintData();
		}
	}
	else
		PrintSpawns();
}

/*
	the main print data function
*/
void PrintData()
{
	mobjinfo_t *MOBJ;

	if (Enum != NULL)
		Objt = Enum2Obj( Enum);
	else if (Thng != -1)
		Objt = Thg2Obj( Thng);
	else
		if (Objt < 0 || Objt >= NUMMOBJTYPES)
			ProgError( "no such Object %d", Objt);

	MOBJ = &mobjinfo[Objt];
	PrintTypeHealth( MOBJ);

	if (MOBJ->flags & MF_SPECIAL) // pick-up item
		PrintShotsPM( MOBJ);
	else
		PrintSpeed( MOBJ);

	PrintDimsTimesFlags( MOBJ);
	if (XWik)
	{
		tmpl_add_int( tpldata, "FLAGSHEX2", "%08X", MOBJ->flags2);
		tmpl_add_int( tpldata, "FLAGSDEC2", "%d", MOBJ->flags2);
	}
	else
		printf( "Flags2\t\t%08x  %d\n", MOBJ->flags2, MOBJ->flags2);
	PrintFlags2( MOBJ->flags2);

	TallyFrames( MOBJ->spawnstate, FALSE);
	TallyFrames( MOBJ->seestate, FALSE);
	TallyFrames( MOBJ->painstate, FALSE);
	TallyFrames( MOBJ->meleestate, FALSE);
	TallyFrames( MOBJ->missilestate, FALSE);
	TallyFrames( MOBJ->crashstate, FALSE);
	TallyFrames( MOBJ->deathstate, FALSE);
	TallyFrames( MOBJ->xdeathstate, FALSE);

	if (XWik)
	{
		memset(fieldlist, 0, LISTSIZE);
		memset(field2list, 0, LISTSIZE);
	}
	else
		printf( "\n");
	if (MOBJ->flags & MF_SPECIAL) // pick-up item
	{
		PrintItemSprites( MOBJ);
	}
	else
	{
		if ((MOBJ->doomednum != -1 && LookupThingClass( MOBJ->doomednum) == ThClassMnst) ||
		    Objt == MT_MINOTAUR || Objt == MT_PIG || Objt == MT_PIGPLAYER ||
		    Objt == MT_PLAYER_FIGHTER || Objt == MT_PLAYER_MAGE || Objt == MT_PLAYER_CLERIC)
			PrintMonsterSprites( MOBJ);
		else
		{
			PrintSprite( MOBJ->spawnstate, ST_NONE, FALSE);
			if (XWik)
			{
				tpldata = TMPL_add_var( tpldata, "SPRITE", fieldlist, NULL);
				tpldata = TMPL_add_var( tpldata, "FRAMES", field2list, NULL);
				memset(fieldlist, 0, LISTSIZE);
				memset(field2list, 0, LISTSIZE);
			}
			PrintSprite( MOBJ->deathstate, ST_NONE, FALSE);
			if (XWik)
			{
				tpldata = TMPL_add_var( tpldata, "SPRITE2", fieldlist, NULL);
				tpldata = TMPL_add_var( tpldata, "FRAMES2", field2list, NULL);
			}
		}

		PrintSound( "Alert", MOBJ->seesound);
		PrintSound( "Active", MOBJ->activesound);
		PrintSound( "Attack", MOBJ->attacksound);
		PrintSound( "Pain", MOBJ->painsound);
		PrintSound( "Death", MOBJ->deathsound);
	}
	PrintSpawns();
}


void PrintSound(char *type, int sound)
{
	char *name;
	char type2[8];

	// cannot run strupr on static param
	strcpy( type2, type);
	strupr( type2);
	if (!XWik)
		printf( "%s sound\t", type);
	if (sound != 0)
	{
		name = LookupSoundTag( S_sfx[sound].tagName);
		strupr( name);
		if (XWik)
			tpldata = TMPL_add_var( tpldata, type2, name, NULL);
		else
			printf( "%s\n", name);
		FreeMemory( name);
	}
	else
	{
		if (XWik)
			tpldata = TMPL_add_var( tpldata, type2, "-", NULL);
		else
			printf( "-\n");
	}
}

#define BUFSIZE 200

char *LookupSoundTag( char *tag)
{
	FILE *sndinfo;
	char buf[BUFSIZE], *ptr = NULL;

	if ((sndinfo = fopen( "sndinfo.txt", "r")) == NULL)
		ProgError( "error opening sndinfo.txt");

	while (fgets( buf, BUFSIZE, sndinfo) != NULL)
	{
		/* skip comment lines */
		if (buf[0] == ';')
			continue;

		if (strncmp(buf, tag, strlen(tag)) == 0)
		{
			ptr = strrchr( buf, ' ') + 1;
			/* erase newline */
			buf[strlen(buf)-1] = '\0';
			break;
		}
	}

	fclose( sndinfo);
	if (ptr != NULL)
		return strdup( ptr);
	else
		return strdup( "");
}

char *ManaColor( weapontype_t weapon, pclass_t class)
{
	if (WeaponInfo[weapon][class].mana == MANA_1)
		return "Blue";
	else if (WeaponInfo[weapon][class].mana == MANA_2)
		return "Green";
	else if (WeaponInfo[weapon][class].mana == MANA_BOTH)
		return "Both";
	else
		return "None";
}

void PrintWpnMana( weapontype_t weapon, pclass_t class)
{
	int mana;

	if (weapon == WP_FIRST)
	{
		if (!XWik)
			printf("Incl mana\tInfinite\n");
		return;
	}

	mana = (weapon == WP_FOURTH) ? 20 : 25; // hardcoded
	if (XWik)
	{
		tmpl_add_int( tpldata, "INCAMMO", "%d", mana);
		tmpl_add_int( tpldata, "INCAMM2", "%d", (int)(mana * 1.5));
		tpldata = TMPL_add_var( tpldata, "MANACOL", ManaColor( weapon, class), NULL);
	}
	else
		printf("Incl mana\t%d %s (%d on [[Skill level|skills]] 1 & 5)\n",
		       mana, ManaColor( weapon, class), (int)(mana * 1.5));

	mana = WeaponManaUse[class][weapon];
	if (XWik)
		tmpl_add_int( tpldata, "MANAUSE", "%d", mana);
	else
		printf("Mana use\t%d %s\n", mana, ManaColor( weapon, class));
}


void PrintShotsPM( mobjinfo_t *MOBJ)
{
	int weapon, class;

	switch (states[MOBJ->spawnstate].sprite)
	{
		case SPR_WFAX: weapon = WP_SECOND; class = PCLASS_FIGHTER; break;
		case SPR_WCSS: weapon = WP_SECOND; class = PCLASS_CLERIC; break;
		case SPR_WMCS: weapon = WP_SECOND; class = PCLASS_MAGE; break;
		case SPR_WFHM: weapon = WP_THIRD; class = PCLASS_FIGHTER; break;
		case SPR_WCFM: weapon = WP_THIRD; class = PCLASS_CLERIC; break;
		case SPR_WMLG: weapon = WP_THIRD; class = PCLASS_MAGE; break;
		case SPR_WFR1:
		case SPR_WFR2:
		case SPR_WFR3: weapon = WP_FOURTH; class = PCLASS_FIGHTER; break;
		case SPR_WCH1:
		case SPR_WCH2:
		case SPR_WCH3: weapon = WP_FOURTH; class = PCLASS_CLERIC; break;
		case SPR_WMS1:
		case SPR_WMS2:
		case SPR_WMS3: weapon = WP_FOURTH; class = PCLASS_MAGE; break;
		default: return;
	}
	PrintWpnShotsPM( weapon, class);
}

void PrintWpnShotsPM( weapontype_t weapon, pclass_t class)
{
	int percycle = 0, tics = 0;
	statenum_t state, st;

	state = st = WeaponInfo[weapon][class].holdatkstate;
	if (state != S_NULL)
		for (;;)
		{
			if (states[st].action)
				states[st].action(NULL);
			else
				funcname[0] = '\0';
			if (strncmp( funcname, "A_Fire", strlen("A_Fire")) == 0 ||
			    strcmp( funcname, "A_FPunchAttack") == 0 ||
			    strcmp( funcname, "A_FAxeAttack") == 0 ||
			    strcmp( funcname, "A_FHammerAttack") == 0 ||
			    strcmp( funcname, "A_FSwordAttack") == 0 ||
			    strcmp( funcname, "A_CMaceAttack") == 0 ||
			    strcmp( funcname, "A_CStaffAttack") == 0 ||
			    strcmp( funcname, "A_CFlameAttack") == 0 ||
			    strcmp( funcname, "A_CHolyAttack") == 0 ||
			    strcmp( funcname, "A_MWandAttack") == 0 ||
			    strcmp( funcname, "A_MLightningAttack") == 0 ||
			    strcmp( funcname, "A_MStaffAttack") == 0 ||
			    strcmp( funcname, "A_MntrFloorFire") == 0)
				percycle++;
			else if (strcmp( funcname, "A_ReFire") == 0 ||
			         st == S_FHAMMERREADY ||    // Hammer of Retribution
			         st == S_FSWORDREADY  ||    // Quietus
			         st == S_CSTAFFREADY2 ||    // Serpent Staff
			         st == S_CFLAMEREADY1 ||    // Firestorm
			         st == S_CHOLYREADY   ||    // Wraithverge
			         st == S_MLIGHTNINGREADY || // Arc of Death
			         st == S_MSTAFFREADY)       // Bloodscourge
				break;
			if (states[st].tics > 0)
				tics += states[st].tics;
			st = states[st].nextstate;
			if (tics > 100)
				ProgError( "unable to count tics for holdatkstate %d", state);
		}

	if (tics > 0)
		if (XWik)
			tmpl_add_float( tpldata, "SHOTMIN", "%.1f",
			                (float)percycle * (TICRATE * 60) / tics);
		else
			printf( "Shots / min\t%.1f\n",
			        (float)percycle * (TICRATE * 60) / tics);
}

int FrameTics( statenum_t state)
{
	if (states[state].action)
	{
		states[state].action(NULL);
		if (strcmp( funcname, "A_Chase") == 0 ||
		    strcmp( funcname, "A_PigChase") == 0 ||       // Pig
		    strcmp( funcname, "A_WraithChase") == 0 ||    // Wraith
		    strcmp( funcname, "A_MinotaurChase") == 0 ||  // Maulotaur
		    strcmp( funcname, "A_SerpentChase") == 0 ||   // Serpent
		    strcmp( funcname, "A_BishopChase") == 0 ||    // Dark Bishop
		    strcmp( funcname, "A_FiredChase") == 0 ||     // Firedemon
		    strcmp( funcname, "A_IceGuyChase") == 0 ||    // Wendigo
		    strcmp( funcname, "A_FastChase") == 0 ||      // Class boss
		    strcmp( funcname, "A_DragonFlap") == 0 ||     // Death Wyvern
		    strcmp( funcname, "A_KoraxChase") == 0)       // Korax
		{
			//printf("%s\n", funcname);
			return states[state].tics;
		}
	}

	return -1;
}


void PrintItemSprites( mobjinfo_t *MOBJ)
{
	int weapon, class;

	switch (states[MOBJ->spawnstate].sprite)
	{
		case SPR_WFAX: weapon = WP_SECOND; class = PCLASS_FIGHTER; break;
		case SPR_WCSS: weapon = WP_SECOND; class = PCLASS_CLERIC; break;
		case SPR_WMCS: weapon = WP_SECOND; class = PCLASS_MAGE; break;
		case SPR_WFHM: weapon = WP_THIRD; class = PCLASS_FIGHTER; break;
		case SPR_WCFM: weapon = WP_THIRD; class = PCLASS_CLERIC; break;
		case SPR_WMLG: weapon = WP_THIRD; class = PCLASS_MAGE; break;
		case SPR_WFR1:
		case SPR_WFR2:
		case SPR_WFR3: weapon = WP_FOURTH; class = PCLASS_FIGHTER; break;
		case SPR_WCH1:
		case SPR_WCH2:
		case SPR_WCH3: weapon = WP_FOURTH; class = PCLASS_CLERIC; break;
		case SPR_WMS1:
		case SPR_WMS2:
		case SPR_WMS3: weapon = WP_FOURTH; class = PCLASS_MAGE; break;
		default:
			PrintSprite( MOBJ->spawnstate, ST_NONE, FALSE);
			tpldata = TMPL_add_var( tpldata, "SPRITE", fieldlist, NULL);
			tpldata = TMPL_add_var( tpldata, "FRAMES", field2list, NULL);
			return;
	}
	PrintSprite( MOBJ->spawnstate, ST_PICKUP, FALSE);
	PrintWpnSprites( weapon, class);

	tpldata = TMPL_add_var( tpldata, "STATELIST", fieldlist, NULL);
}

void PrintWpnSprites( weapontype_t weapon, pclass_t class)
{
	PrintSprite( WeaponInfo[weapon][class].readystate, ST_WIELD, FALSE);
	PrintSprite( WeaponInfo[weapon][class].atkstate, ST_FIRE, TRUE);
	PrintSprite( WeaponInfo[weapon][class].holdatkstate, ST_REFIRE, FALSE);
}

void PrintMonsterSprites( mobjinfo_t *MOBJ)
{
	memset(fieldlist, 0, LISTSIZE);
	PrintSprite( MOBJ->spawnstate, ST_NONE, FALSE);
	tpldata = TMPL_add_var( tpldata, "SPRITE", fieldlist, NULL);

	memset(fieldlist, 0, LISTSIZE);
	PrintSprite( MOBJ->spawnstate, ST_SPAWN, FALSE);
	PrintSprite( MOBJ->seestate, ST_SEE, FALSE);
	PrintSprite( MOBJ->meleestate, ST_MELEE, FALSE);
	PrintSprite( MOBJ->missilestate, ST_MISSL, FALSE);
	PrintSprite( MOBJ->painstate, ST_PAIN, FALSE);
	PrintSprite( MOBJ->deathstate, ST_DEATH, FALSE);
	PrintSprite( MOBJ->crashstate, ST_CRASH, FALSE);
	PrintSprite( MOBJ->xdeathstate, ST_XDEATH, FALSE);
	tpldata = TMPL_add_var( tpldata, "STATELIST", fieldlist, NULL);
}

/* vim:set noexpandtab tabstop=2 softtabstop=2 shiftwidth=2: */
