#include "weapon.h"
#include "globals.h"
#include "qav.h"
#include "debug4g.h"
#include "actor.h"
#include "db.h"
#include "actor.h"
#include "gameutil.h"
#include "trig.h"
#include "view.h"
#include "options.h"
#include "names.h"
#include "triggers.h"
#include "error.h"
#include "misc.h"
#include "screen.h"
#include "tile.h"
#include "ai.h"		// lackey support
#include "sound.h"
#include "sfx.h"

#define kShotgunBarrels		2
#define kVectorsPerBarrel	16
#define kMaxShotgunVectors	(kShotgunBarrels * kVectorsPerBarrel)

enum {
	kVoodooStabChest	= 1,
	kVoodooStabShoulder,
	kVoodooStabEye,
	kVoodooStabGroin,
	kVoodooStabSelf,
};

// Weapon States
enum {
	kFindWeapon			= -1,	// flag to find a loaded weapon

	kForkIdle			= 0,

	kBicOpen			= 0,
	kBicIdle,
	kBicSwitch,
	kBicNext,

	kCanIdle			= kBicNext,
	kCanFire,

	kTNTStickIdle		= kBicNext,
	kTNTStickFuse1,
	kTNTStickFuse2,
	kTNTStickThrow,
	kTNTBundleIdle,
	kTNTBundleFuse1,
	kTNTBundleFuse2,
	kTNTBundleThrow,
	kTNTProxIdle,
	kTNTProxEmpty,
	kTNTProxThrow,
	kTNTRemoteIdle1,			// bundle and detonator
	kTNTRemoteIdle2,			// detonator only
	kTNTRemoteEmpty,
	kTNTRemoteThrow,

	kShotInitialize		= 0,	// indicates first-time reload required
	kShotIdle0,
	kShotIdle1,
 	kShotIdle2,
	kShotFire1,
	kShotFire2,
	kShotLower,

	kFlareInitialize	= 0,
	kFlareRaise,
	kFlareIdle,
	kFlareFire,
	kFlareReload,
	kFlareLower,

	kTommyIdle			= 0,

	kSpearInitialize	= 0,
	kSpearRaise,
	kSpearIdle1,
	kSpearIdle2,
	kSpearFire,
	kSpearReload,
	kSpearLower,

	kShadowInitialize	= 0,
	kShadowRaise,
	kShadowIdle,
	kShadowFire,
	kShadowLower,

	kBeastInitialize	= 0,
	kBeastRaise,
	kBeastIdle,
	kBeastAttack,
	kBeastLower,

	kDollInitialize	= 0,
	kDollRaise,
	kDollIdle,
	kDollStab1,
	kDollStab2,
	kDollStab3,
	kDollStab4,
	kDollStab5,
	kDollLower,
	kDollSpell,
};

// Weapon Modes
enum {
	kForkModeNormal		= 0,
	kForkModeMax,

	kSprayModeNormal	= 0,
	kSprayModeMax,

	kTNTModeStick		= 0,
	kTNTModeBundle,
	kTNTModeProximity,
	kTNTModeRemote,
	kTNTModeMax,

	kShotgunModeNormal	= 0,
	kShotgunModeMax,

	kTommyModeNormal	= 0,
	kTommyModeAP,
	kTommyModeMax,

	kFlareModeNormal	= 0,
	kFlareModeSB,
	kFlareModeMax,

	kVoodooModeNormal	= 0,
	kVoodooModeMax,

	kSpearModeNormal	= 0,
	kSpearModeXP,
	kSpearModeMax,

	kShadowModeNormal	= 0,
	kShadowModeMax,

	kBeastModeNormal	= 0,
	kBeastModeMax,
};

enum {
	kQAVForkUp = 0,
	kQAVForkIdle,
	kQAVForkStab,
	kQAVForkDown,

	kQAVBicUp,				// raise lighter and open
	kQAVBicFlame,			// light lighter
	kQAVBicIdle,			// burning lighter
	kQAVBicDown,			// lower and close burning lighter

	kQAVSprayUp,
	kQAVSprayIdle,
	kQAVSprayFire,
	kQAVSprayDown,

	kQAVStickUp,			// raise just stick
	kQAVStickDown,			// lower just stick
	kQAVStickUp2,			// raise lighter and stick
	kQAVStickDown2,			// lower lighter and stick
	kQAVStickIdle,
	kQAVStickFuse,
	kQAVStickDrop,
	kQAVStickThrow,

	kQAVBundleUp,			// raise just bundle
	kQAVBundleDown,			// lower just bundle
	kQAVBundleUp2,			// raise lighter and bundle
	kQAVBundleDown2,		// lower lighter and bundle
	kQAVBundleIdle,
	kQAVBundleFuse,
	kQAVBundleDrop,
	kQAVBundleThrow,

	kQAVTNTExplode,

	kQAVProxUp,
	kQAVProxDown,
	kQAVProxIdle,
	kQAVProxDrop,
	kQAVProxThrow,

	kQAVRemoteUp1,			// detonator present, raise bundle
	kQAVRemoteUp2,			// raise both bundle and detonator
	kQAVRemoteUp3,			// raise detonator only
	kQAVRemoteDown1,		// both present, lower bundle
	kQAVRemoteDown2,		// lower both bundle and detonator
	kQAVRemoteDown3,		// lower detonator only
	kQAVRemoteIdle1,		// both bundle and detonator
	kQAVRemoteIdle2,		// detonator only
	kQAVRemoteDrop,
	kQAVRemoteThrow,
	kQAVRemoteFire,

	kQAVFlareUp,
	kQAVFlareIdle,
	kQAVFlareFire,
//	kQAVFlareReload,
	kQAVFlareDown,

	kQAVShotUp,
	kQAVShotIdle0,
	kQAVShotIdle1,
	kQAVShotIdle2,
	kQAVShotFireL,
	kQAVShotFireR,
	kQAVShotReload,
	kQAVShotDown,

	kQAVTommyUp,
	kQAVTommyIdle,
	kQAVTommyFire1,
 	kQAVTommyDown,

	kQAVSpearUp,
	kQAVSpearIdle1,
	kQAVSpearIdle2,
	kQAVSpearFire,
	kQAVSpearDown,

	kQAVShadowUp,
	kQAVShadowIdle,
	kQAVShadowFire,
	kQAVShadowDown,

	kQAVBeastUp,
	kQAVBeastIdle,
	kQAVBeastAttack1,
	kQAVBeastAttack2,
 	kQAVBeastAttack3,
 	kQAVBeastAttack4,
	kQAVBeastDown,

	kQAVDollUp,
	kQAVDollIdleStill,
	kQAVDollIdleMoving,
	kQAVDollStab1,
	kQAVDollStab2,
	kQAVDollStab3,
	kQAVDollStab4,
	kQAVDollStab5,
	kQAVDollDown,
	kQAVDollSpell,

	kQAVEnd
};

static char * weaponQAVNames[kQAVEnd] =
{
	"FORKUP",  		//kQAVForkUp = 0,
	"FORKIDLE",     //kQAVForkIdle,
	"PFORK",        //kQAVForkStab,
	"FORKDOWN",     //kQAVForkDown,

	"LITEOPEN",     //kQAVBicUp,
	"LITEFLAM",     //kQAVBicFlame,
	"LITEIDLE",     //kQAVBicIdle,
	"LITECLO2",     //kQAVBicDown,

	"CANPREF",      //kQAVSprayUp,
	"CANIDLE",      //kQAVSprayIdle,
	"CANFIRE",		//kQAVSprayFire,
	"CANDOWN",      //kQAVSprayDown,

	"DYNUP",		//kQAVStickUp,
	"DYNDOWN",		//kQAVStickDown,
	"DYNUP2",		//kQAVStickUp2,
	"DYNDOWN2",		//kQAVStickDown2,
	"DYNIDLE",		//kQAVStickIdle,
	"DYNFUSE",		//kQAVStickFuse,
	"DYNDROP",		//kQAVStickDrop,
	"DYNTHRO",		//kQAVStickThrow,

	"BUNUP",		//kQAVBundleUp,
	"BUNDOWN",		//kQAVBundleDown,
	"BUNUP2",		//kQAVBundleUp2,
	"BUNDOWN2",		//kQAVBundleDown2,
	"BUNIDLE",		//kQAVBundleIdle,
	"BUNFUSE",		//kQAVBundleFuse,
	"BUNDROP",		//kQAVBundleDrop,
	"BUNTHRO",		//kQAVBundleThrow,

	"DYNEXPLO",		//kQAVExplode,

	"PROXUP",		//kQAVProxUp,
	"PROXDOWN",		//kQAVProxDown,
	"PROXIDLE",		//kQAVProxIdle,
	"PROXDROP",		//kQAVProxDrop,
	"PROXTHRO",		//kQAVProxThrow,

	"REMUP1",   	//kQAVRemoteUp1,
	"REMUP2",   	//kQAVRemoteUp2,
	"REMUP3",   	//kQAVRemoteUp3,
	"REMDOWN1", 	//kQAVRemoteDown1,
	"REMDOWN2", 	//kQAVRemoteDown2,
	"REMDOWN3", 	//kQAVRemoteDown3,
	"REMIDLE1", 	//kQAVRemoteIdle1,
	"REMIDLE2", 	//kQAVRemoteIdle2,
	"REMDROP",  	//kQAVRemoteDrop,
	"REMTHRO",  	//kQAVRemoteThrow,
	"REMFIRE",  	//kQAVRemoteFire,

	"FLARUP",
	"FLARIDLE",
	"FLARFIR2",
//	"FLARLOAD",
	"FLARDOWN",

	"SHOTUP",		//kQAVShotUp,
	"SHOTI3",       //kQAVShotIdle0,
	"SHOTI2",       //kQAVShotIdle1,
	"SHOTI1",       //kQAVShotIdle2,
	"SHOTF1",       //kQAVShotFireL,
	"SHOTF2",       //kQAVShotFireR,
	"SHOTL1",       //kQAVShotReload,
	"SHOTDOWN",     //kQAVShotDown,

	"TOMUP",        //kQAVTommyUp,
	"TOMIDLE",      //kQAVTommyIdle,
	"TOMFIRE",		//kQAVTommyFire1,
	"TOMDOWN",      //kQAVTommyDown,

	"SGUNUP",		//kQAVSpearUp,
	"SGUNIDL1",		//kQAVSpearIdle1,
	"SGUNIDL2",		//kQAVSpearIdle2,
	"SGUNFIRE",		//kQAVSpearFire,
	"SGUNDOWN",		//kQAVSpearDown,

	"DARKUP",       //kQAVShadowUp,
	"DARKIDLE",     //kQAVShadowIdle,
	"DARKFIRE",     //kQAVShadowFire,
	"DARKDOWN",     //kQAVShadowDown,

	"BSTUP",		//kQAVBeastUp
	"BSTIDLE",		//kQAVBeastIdle,
	"BSTATAK1",     //kQAVBeastAttack1,
	"BSTATAK2",     //kQAVBeastAttack2,
	"BSTATAK3",     //kQAVBeastAttack3,
	"BSTATAK4",     //kQAVBeastAttack4,
	"BSTDOWN",

	"VDUP",			//kQAVDollUp
	"VDIDLE1",		//kQAVDollIdleStill	(PLAYER IS STILL)
	"VDIDLE2",		//kQAVDollIdleMoving	(PLAYER IS WALKING/RUNNING)
	"VDFIRE1",		//kQAVDollStab1
	"VDFIRE2",		//kQAVDollStab2
	"VDFIRE3",		//kQAVDollStab3
	"VDFIRE4",		//kQAVDollStab4
	"VDFIRE5",		//kQAVDollStab5
	"VDDOWN", 		//kQAVDollDown
	"VDSPEL1", 		//kQAVDollSpell
};


static modeMax[kWeaponMax + 1] =
{
	0,
	kForkModeMax,
	kSprayModeMax,
	kTNTModeMax,
	kShotgunModeMax,
	kTommyModeMax,
	kFlareModeMax,
	kVoodooModeMax,
	kSpearModeMax,
	kShadowModeMax,
	kBeastModeMax,
};


static QAV *weaponQAV[kQAVEnd];


/****************************************************************************
** LOCAL callback prototypes
****************************************************************************/

static void FireReanimator( int /* nTrigger */, PLAYER *pPlayer );


/****************************************************************************
** function calls
****************************************************************************/

static BOOL CheckAmmo( PLAYER *pPlayer, int nAmmo )
{
	if ( gInfiniteAmmo )
		return TRUE;

	if ( nAmmo == kAmmoNone )
		return TRUE;

	return pPlayer->ammoCount[nAmmo] > 0;
}


static void UseAmmo( PLAYER *pPlayer, int nAmmo, int nCount )
{
	if ( gInfiniteAmmo )
		return;

	if ( nAmmo == kAmmoNone )
		return;

	pPlayer->ammoCount[nAmmo] = ClipLow(pPlayer->ammoCount[nAmmo] - nCount, 0);
}


void WeaponInit( void )
{
	// get pointers to all the QAV resources
	for (int i = 0; i < kQAVEnd; i++)
	{
		RESHANDLE hQAV = gSysRes.Lookup(weaponQAVNames[i], ".QAV");
		if (hQAV == NULL)
		{
			dprintf("Could not load %s.QAV\n", weaponQAVNames[i]);
			ThrowError("Missing Weapon QAV file", ES_ERROR);
		}
		weaponQAV[i] = (QAV *)gSysRes.Lock(hQAV);
	}

	dprintf("Preload weapon QAV tiles\n");
	for (i = 0; i < kQAVEnd; i++)
	{
		if (weaponQAV[i] != NULL )
			weaponQAV[i]->Preload();
	}
}


void WeaponDraw( PLAYER *pPlayer, int shade, int x, int y )
{
	dassert(pPlayer != NULL);
	QAV *pQAV = pPlayer->pWeaponQAV;
	ulong t;

	if ( pQAV == NULL )
		return;

	if (pPlayer->weaponTimer == 0)	// playing idle QAV?
		t = gGameClock % pQAV->duration;
	else
		t = pQAV->duration - pPlayer->weaponTimer;

	pQAV->origin.x = x;
	pQAV->origin.y = y;

	int nPowerRemaining = powerupCheck( pPlayer, kItemLtdInvisibility - kItemBase );
	int nFlags = kQFrameScale;

	if ( nPowerRemaining >= (kTimerRate * 8) || nPowerRemaining && ( gGameClock & 32 ) )
	{
		nFlags |= kQFrameTranslucent;
		shade = -128;
	}

	pQAV->Draw(t, shade, nFlags);
}


void WeaponPlay( PLAYER *pPlayer )
{
	dassert(pPlayer != NULL);
	QAV *pQAV = pPlayer->pWeaponQAV;

	if ( pQAV == NULL )
		return;

	ulong t = pQAV->duration - pPlayer->weaponTimer;

	pQAV->Play(t - kFrameTicks, t, pPlayer->weaponCallback, pPlayer);
}


static void StartQAV( PLAYER *pPlayer, int weaponIndex, QAVCALLBACK callback = NULL, BOOL fLoop = FALSE)
{
	pPlayer->pWeaponQAV = weaponQAV[weaponIndex];
	pPlayer->weaponTimer = pPlayer->pWeaponQAV->duration;
	pPlayer->weaponCallback = callback;
	pPlayer->fLoopQAV = fLoop;
}


#define kAimMaxDist 	M2X(100)
#define kAimMaxAngle	kAngle15
#define kAimMaxSlope	9459			// tan(30) << 14

#define kTrackRate		0x2000			// 0x10000 tracks instantly, 0 takes forever

static void UpdateAimVector( PLAYER *pPlayer )
{
	dassert(pPlayer != NULL);
	SPRITE *pSprite = pPlayer->sprite;

	int x = pSprite->x;
	int y = pSprite->y;
	int z = pSprite->z - pPlayer->weaponAboveZ;

	VECTOR3D aim;

	aim.dx = Cos(pSprite->ang) >> 16;
	aim.dy = Sin(pSprite->ang) >> 16;
	aim.dz = pPlayer->slope;

	int nAimSprite = -1;

	if ( gAutoAim )
	{
		int closest = 0x7FFFFFFF;
		for (short nTarget = headspritestat[kStatDude]; nTarget >= 0; nTarget = nextspritestat[nTarget] )
		{
			SPRITE *pTarget = &sprite[nTarget];

			// don't target yourself!
			if ( pTarget == pSprite )
				continue;

			int dx, dy, dz;

			dx = pTarget->x - x;
			dy = pTarget->y - y;
			dz = pTarget->z - z;

			int dist = qdist(dx, dy);
			if ( dist > closest || dist > kAimMaxDist )
				continue;

			int ang = getangle(dx, dy);
			if ( qabs(((ang - pSprite->ang + kAngle180) & kAngleMask) - kAngle180) > kAimMaxAngle )
				continue;

			int z1 = z + mulscale(pPlayer->slope, dist, 10);
			int z2 = mulscale(kAimMaxSlope, dist, 10);
			if ( (pTarget->z < z1 - z2) || (pTarget->z > z1 + z2) )
				continue;

			if ( cansee(x, y, z, pSprite->sectnum, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum) )
			{
				closest = dist;

				aim.dx = Cos(ang) >> 16;
				aim.dy = Sin(ang) >> 16;
				aim.dz = divscale(dz, dist, 10);
				nAimSprite = nTarget;
			}
		}

		// barrels
		for (nTarget = headspritestat[kStatThing]; nTarget >= 0; nTarget = nextspritestat[nTarget] )
		{
			SPRITE *pTarget = &sprite[nTarget];

			if (pTarget->type != kThingTNTBarrel )
				continue;

			int dx, dy, dz;

			dx = pTarget->x - x;
			dy = pTarget->y - y;
			dz = pTarget->z - z;

			int dist = qdist(dx, dy);
			if ( dist > closest || dist > kAimMaxDist )
				continue;

			int ang = getangle(dx, dy);
			if ( qabs(((ang - pSprite->ang + kAngle180) & kAngleMask) - kAngle180) > kAimMaxAngle )
				continue;

			int z1 = z + mulscale(pPlayer->slope, dist, 10);
			int z2 = mulscale(kAimMaxSlope, dist, 10);
			if ( (pTarget->z < z1 - z2) || (pTarget->z > z1 + z2) )
				continue;

			if ( cansee(x, y, z, pSprite->sectnum, pTarget->x, pTarget->y, pTarget->z, pTarget->sectnum) )
			{
				closest = dist;

				aim.dx = Cos(ang) >> 16;
				aim.dy = Sin(ang) >> 16;
				aim.dz = divscale(dz, dist, 10);
				nAimSprite = nTarget;
			}
		}

	}

	VECTOR3D relAim = aim;
	RotateVector(&relAim.dx, &relAim.dy, -pSprite->ang);

	pPlayer->relAim.dx = dmulscale16r(pPlayer->relAim.dx, 0x10000 - kTrackRate, relAim.dx, kTrackRate);
	pPlayer->relAim.dy = dmulscale16r(pPlayer->relAim.dy, 0x10000 - kTrackRate, relAim.dy, kTrackRate);
	pPlayer->relAim.dz = dmulscale16r(pPlayer->relAim.dz, 0x10000  -kTrackRate, relAim.dz, kTrackRate);

	pPlayer->aim = pPlayer->relAim;
	RotateVector(&pPlayer->aim.dx, &pPlayer->aim.dy, pSprite->ang);

	pPlayer->aimSprite = nAimSprite;
}


void WeaponRaise( PLAYER *pPlayer, INPUT *pInput )
{
	dassert( pPlayer != 0 );

	pPlayer->weapon = pInput->newWeapon;
	pInput->newWeapon = 0;
	dprintf("WeaponRaise:  weapon = %d, mode = %d\n",
		pPlayer->weapon, pPlayer->weaponMode[pPlayer->weapon]);

	switch( pPlayer->weapon )
	{
		case kWeaponPitchfork:
			StartQAV(pPlayer, kQAVForkUp);
			pPlayer->weaponState = kForkIdle;
			pPlayer->weaponAmmo = kAmmoNone;
			break;

		case kWeaponSprayCan:
			StartQAV(pPlayer, kQAVBicUp);
			pPlayer->weaponState = kBicOpen;
			pPlayer->weaponAmmo = kAmmoSprayCan;
			break;

		case kWeaponTNT:
			switch ( pPlayer->weaponMode[kWeaponTNT] )
			{
				case kTNTModeStick:
					StartQAV(pPlayer, kQAVStickUp2);
					pPlayer->weaponState = kTNTStickIdle;
					pPlayer->weaponAmmo = kAmmoTNTStick;
					break;

				case kTNTModeBundle:
					StartQAV(pPlayer, kQAVBundleUp2);
					pPlayer->weaponState = kTNTBundleIdle;
					pPlayer->weaponAmmo = kAmmoTNTStick;
					break;

				case kTNTModeProximity:
					StartQAV(pPlayer, kQAVProxUp);
					pPlayer->weaponState = kTNTProxIdle;
					pPlayer->weaponAmmo = kAmmoTNTProximity;
					break;

				case kTNTModeRemote:
					StartQAV(pPlayer, kQAVRemoteUp2);
					pPlayer->weaponState = kTNTRemoteIdle1;
					pPlayer->weaponAmmo = kAmmoTNTRemote;
					break;
			}
			break;

		case kWeaponShotgun:
			StartQAV(pPlayer, kQAVShotUp);
			if ( gInfiniteAmmo || pPlayer->ammoCount[kAmmoShell] > 1 )
				pPlayer->weaponState = kShotIdle2;
			else if ( pPlayer->ammoCount[kAmmoShell] > 0 )
				pPlayer->weaponState = kShotIdle1;
			else
				pPlayer->weaponState = kShotIdle0;
			pPlayer->weaponAmmo = kAmmoShell;
			break;

		case kWeaponTommy:
			StartQAV(pPlayer, kQAVTommyUp);
			pPlayer->weaponState = kTommyIdle;
			pPlayer->weaponAmmo = kAmmoBullet;
			break;

		case kWeaponVoodoo:
			StartQAV(pPlayer, kQAVDollUp);
			pPlayer->weaponState = kDollIdle;
			pPlayer->weaponAmmo = kAmmoVoodoo;
			break;

		case kWeaponFlare:
			StartQAV(pPlayer, kQAVFlareUp);
			pPlayer->weaponState = kFlareIdle;
			pPlayer->weaponAmmo = kAmmoFlare;
			break;

		case kWeaponSpear:
			StartQAV(pPlayer, kQAVSpearUp);
			if ( pPlayer->ammoCount[kAmmoSpear] > 0 || pPlayer->ammoCount[kAmmoSpearXP] > 0 )
				pPlayer->weaponState = kSpearIdle1;
			else
				pPlayer->weaponState = kSpearIdle2;
			pPlayer->weaponAmmo = kAmmoSpear;
			break;

		case kWeaponShadow:
			StartQAV(pPlayer, kQAVShadowUp);
			pPlayer->weaponState = kShadowIdle;
			pPlayer->weaponAmmo = kAmmoNone;
			break;

		case kWeaponBeast:
			StartQAV(pPlayer, kQAVBeastUp);
			pPlayer->weaponState = kBeastIdle;
			pPlayer->weaponAmmo = kAmmoNone;
			break;
	}
}


void WeaponLower( PLAYER *pPlayer, INPUT *pInput )
{
	dprintf("WeaponLower()\n");
	dassert( pPlayer != 0 );

	int nWeapon = pPlayer->weapon;
	int nState = pPlayer->weaponState;

	switch( nWeapon )
	{
		case kWeaponPitchfork:
			StartQAV(pPlayer, kQAVForkDown);
			break;

		case kWeaponSprayCan:
			switch( nState )
			{
				case kBicIdle:
			        StartQAV(pPlayer, kQAVBicDown);
					break;

				case kBicSwitch:
					pPlayer->weapon = pInput->newWeapon;
					pPlayer->weaponState = kBicIdle;
					pInput->newWeapon = 0;
					return;

				default:
				    StartQAV(pPlayer, kQAVSprayDown);
					if ( pInput->newWeapon == kWeaponTNT )
						pPlayer->weaponState = kBicSwitch;
					else
						pPlayer->weaponState = kBicIdle;
					return;

			}
			break;

		case kWeaponTNT:
		{
			switch( nState )
			{
				case kBicSwitch:
					pPlayer->weapon = pInput->newWeapon;
					pInput->newWeapon = 0;
					return;

				case kBicIdle:
			        StartQAV(pPlayer, kQAVBicDown);
					break;

				case kTNTStickIdle:
					if ( pInput->newWeapon == kWeaponSprayCan )
					{
						StartQAV(pPlayer, kQAVStickDown);
						pPlayer->weaponState = kBicSwitch;
						return;
					}
					StartQAV(pPlayer, kQAVStickDown2);
					break;

				case kTNTBundleIdle:
					if ( pInput->newWeapon == kWeaponSprayCan )
					{
						StartQAV(pPlayer, kQAVBundleDown);
						pPlayer->weaponState = kBicSwitch;
						return;
					}
					StartQAV(pPlayer, kQAVBundleDown2);
					break;

				case kTNTProxIdle:
					StartQAV(pPlayer, kQAVProxDown);
					break;

				case kTNTRemoteIdle1:
					StartQAV(pPlayer, kQAVRemoteDown2);
					break;

				case kTNTRemoteIdle2:
					StartQAV(pPlayer, kQAVRemoteDown3);
					break;
			}
			break;
		}

		case kWeaponShotgun:
	        StartQAV(pPlayer, kQAVShotDown);
			break;

		case kWeaponTommy:
	        StartQAV(pPlayer, kQAVTommyDown);
			break;

		case kWeaponFlare:
			StartQAV(pPlayer, kQAVFlareDown);
			break;

		case kWeaponVoodoo:
			StartQAV(pPlayer, kQAVDollDown);
			break;

		case kWeaponSpear:
	        StartQAV(pPlayer, kQAVSpearDown);
			break;

		case kWeaponShadow:
	        StartQAV(pPlayer, kQAVShadowDown);
			break;

		case kWeaponBeast:
	        StartQAV(pPlayer, kQAVBeastDown);
			break;
	}

	if (pInput->newWeapon == pPlayer->weapon)
	{
		if ( ++pPlayer->weaponMode[pPlayer->weapon] == modeMax[pPlayer->weapon] )
		{
			pPlayer->weaponMode[pPlayer->weapon] = 0;
			pInput->newWeapon = 0;
		}
	}

	pPlayer->weapon = 0;
}


void WeaponUpdateState( PLAYER *pPlayer)
{
	SPRITE *pSprite		= pPlayer->sprite;
	XSPRITE *pXSprite	= pPlayer->xsprite;

	int nWeapon = pPlayer->weapon;
	int nState = pPlayer->weaponState;

	switch( nWeapon )
	{
		case kWeaponPitchfork:
			pPlayer->pWeaponQAV = weaponQAV[kQAVForkIdle];
			break;

		case kWeaponSprayCan:
			switch( nState )
			{
				case kBicOpen:
					StartQAV(pPlayer, kQAVBicFlame);
					pPlayer->weaponState = kBicIdle;
					break;

				case kBicIdle:
					if ( CheckAmmo(pPlayer, kAmmoSprayCan) )
					{
						StartQAV(pPlayer, kQAVSprayUp);
						pPlayer->weaponState = kCanIdle;
					}
					else
						pPlayer->pWeaponQAV = weaponQAV[kQAVBicIdle];
					break;

				case kCanIdle:
					pPlayer->pWeaponQAV = weaponQAV[kQAVSprayIdle];
					break;

				case kCanFire:
					if ( CheckAmmo(pPlayer, kAmmoSprayCan) )
					{
						pPlayer->pWeaponQAV = weaponQAV[kQAVSprayIdle];
						pPlayer->weaponState = kCanIdle;
					}
					else
					{
						StartQAV(pPlayer, kQAVSprayDown);
						pPlayer->weaponState = kBicIdle;
					}
					break;
			}
			break;

		case kWeaponTNT:
			switch( nState )
			{
				case kBicIdle:
					switch ( pPlayer->weaponMode[kWeaponTNT] )
					{
						case kTNTModeStick:
							StartQAV(pPlayer, kQAVStickUp);
							pPlayer->weaponState = kTNTStickIdle;
							break;

						case kTNTModeBundle:
							StartQAV(pPlayer, kQAVBundleUp);
							pPlayer->weaponState = kTNTBundleIdle;
							break;
					}
					break;

				case kBicOpen:
					StartQAV(pPlayer, kQAVBicFlame);
					pPlayer->weaponState = kBicIdle;
					break;

				case kBicSwitch:
					if ( pPlayer->ammoCount[kAmmoTNTStick] > 0)
					{
						StartQAV(pPlayer, kQAVStickUp);
						pPlayer->weaponState = kTNTStickIdle;
					}
					else
						pPlayer->pWeaponQAV = weaponQAV[kQAVBicIdle];
					break;

				case kTNTStickIdle:
					pPlayer->pWeaponQAV = weaponQAV[kQAVStickIdle];
					break;

				case kTNTBundleIdle:
					pPlayer->pWeaponQAV = weaponQAV[kQAVBundleIdle];
					break;

				case kTNTProxIdle:
					pPlayer->pWeaponQAV = weaponQAV[kQAVProxIdle];
					break;

				case kTNTProxEmpty:
					StartQAV(pPlayer, kQAVProxUp);
					pPlayer->weaponState = kTNTProxIdle;
					break;

				case kTNTRemoteIdle1:
					pPlayer->pWeaponQAV = weaponQAV[kQAVRemoteIdle1];
					break;

				case kTNTRemoteIdle2:
					pPlayer->pWeaponQAV = weaponQAV[kQAVRemoteIdle2];
					break;

				case kTNTRemoteEmpty:
					StartQAV(pPlayer, kQAVRemoteUp2);
					pPlayer->weaponState = kTNTRemoteIdle1;
					break;
			}
			break;

		case kWeaponShotgun:
			switch ( nState )
			{
				case kShotIdle0:
					if ( CheckAmmo(pPlayer, kAmmoShell) )
					{
				    	StartQAV(pPlayer, kQAVShotReload);
						if ( gInfiniteAmmo || pPlayer->ammoCount[kAmmoShell] > 1 )
							pPlayer->weaponState = kShotIdle2;
						else
							pPlayer->weaponState = kShotIdle1;
					}
					else
						pPlayer->pWeaponQAV = weaponQAV[kQAVShotIdle0];
					break;

				case kShotIdle1:
					pPlayer->pWeaponQAV = weaponQAV[kQAVShotIdle1];
					break;

				case kShotIdle2:
					pPlayer->pWeaponQAV = weaponQAV[kQAVShotIdle2];
					break;

			}
			break;

		case kWeaponTommy:
			pPlayer->pWeaponQAV = weaponQAV[kQAVTommyIdle];
			break;

		case kWeaponFlare:
			if (nState == kFlareIdle)
				pPlayer->pWeaponQAV = weaponQAV[kQAVFlareIdle];
			break;

		case kWeaponVoodoo:
	 		switch ( pXSprite->moveState )
			{
				case kMoveWalk:
					if ( qabs(pPlayer->swayHeight) > (3 << 8) )
						pPlayer->pWeaponQAV = weaponQAV[kQAVDollIdleMoving];
					else
						pPlayer->pWeaponQAV = weaponQAV[kQAVDollIdleStill];
					break;

				case kMoveLand:
					pPlayer->pWeaponQAV = weaponQAV[kQAVDollIdleMoving];
					break;

				default:
					pPlayer->pWeaponQAV = weaponQAV[kQAVDollIdleStill];
					break;
			}
			break;

		case kWeaponSpear:
			switch ( nState )
			{
				case kSpearIdle1:
					pPlayer->pWeaponQAV = weaponQAV[kQAVSpearIdle1];
					break;

				case kSpearIdle2:
					pPlayer->pWeaponQAV = weaponQAV[kQAVSpearIdle2];
					break;
			}
			break;

		case kWeaponShadow:
			pPlayer->pWeaponQAV = weaponQAV[kQAVShadowIdle];
			break;

		case kWeaponBeast:
			pPlayer->pWeaponQAV = weaponQAV[kQAVBeastIdle];
			break;
	}
}


static void FirePitchfork( int /* nTrigger */, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;

	int z = pSprite->z - pPlayer->weaponAboveZ;

	for ( int i = 0; i < 4; i++ )
	{
		// dispersal modifiers
		int ddx = BiRandom(2000);
		int ddy = BiRandom(2000);
		int ddz = BiRandom(2000);

		actFireVector(pPlayer->nSprite, z,
			pPlayer->aim.dx + ddx, pPlayer->aim.dy + ddy, pPlayer->aim.dz + ddz,
			kVectorTine);
	}
}


static void FireSpray( int /* nTrigger */, PLAYER *pPlayer )
{
	playerFireMissile(pPlayer, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
		kMissileSprayFlame);
	UseAmmo(pPlayer, kAmmoSprayCan, kFrameTicks);
}


#define kMaxThrowTime 	(3 * kTimerRate)	// how long to hold fire to get farthest throw
#define kMinThrowVel	((M2X(8.0) << 4) / kTimerRate)
#define kMaxThrowVel	((M2X(30.0) << 4) / kTimerRate)
#define kSlopeThrow		-8192	// tan(26)

static void ThrowStick( int /* nTrigger */, PLAYER *pPlayer )
{
	pPlayer->throwTime = ClipHigh(pPlayer->throwTime, kMaxThrowTime);
	int velocity = muldiv(pPlayer->throwTime, kMaxThrowVel - kMinThrowVel, kMaxThrowTime) + kMinThrowVel;
	int nThing = playerFireThing(pPlayer, kSlopeThrow, kThingTNTStick, velocity);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	if ( pPlayer->fuseTime < 0 )
		pXSprite->triggerProximity = 1;
	else
		evPost(nThing, SS_SPRITE, pPlayer->fuseTime);
	UseAmmo(pPlayer, kAmmoTNTStick, 1);
}


static void DropStick( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTStick, 0);
	evPost(nThing, SS_SPRITE, pPlayer->fuseTime);
	UseAmmo(pPlayer, kAmmoTNTStick, 1);
}


static void ExplodeStick( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTStick, 0);
	evPost(nThing, SS_SPRITE, 0);	// trigger it immediately
	UseAmmo(pPlayer, kAmmoTNTStick, 1);
	StartQAV(pPlayer, kQAVTNTExplode);
	pPlayer->weapon = 0;	// drop the hands
}


static void ThrowBundle( int /* nTrigger */, PLAYER *pPlayer )
{
	pPlayer->throwTime = ClipHigh(pPlayer->throwTime, kMaxThrowTime);
	int velocity = muldiv(pPlayer->throwTime, kMaxThrowVel - kMinThrowVel, kMaxThrowTime) + kMinThrowVel;
	int nThing = playerFireThing(pPlayer, kSlopeThrow, kThingTNTBundle, velocity);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	if ( pPlayer->fuseTime < 0 )
		pXSprite->triggerProximity = 1;
	else
		evPost(nThing, SS_SPRITE, pPlayer->fuseTime);
	UseAmmo(pPlayer, kAmmoTNTStick, 7);
}


static void DropBundle( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTBundle, 0);
	evPost(nThing, SS_SPRITE, pPlayer->fuseTime);
	UseAmmo(pPlayer, kAmmoTNTStick, 7);
}


static void ExplodeBundle( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTBundle, 0);
	evPost(nThing, SS_SPRITE, 0);	// trigger it immediately
	UseAmmo(pPlayer, kAmmoTNTStick, 7);
	StartQAV(pPlayer, kQAVTNTExplode);
	pPlayer->weapon = 0;	// drop the hands
}


static void ThrowProx( int /* nTrigger */, PLAYER *pPlayer )
{
	pPlayer->throwTime = ClipHigh(pPlayer->throwTime, kMaxThrowTime);
	int velocity = muldiv(pPlayer->throwTime, kMaxThrowVel - kMinThrowVel, kMaxThrowTime) + kMinThrowVel;
	int nThing = playerFireThing(pPlayer, kSlopeThrow, kThingTNTBundle, velocity);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	pXSprite->triggerProximity = 1;
	UseAmmo(pPlayer, kAmmoTNTProximity, 1);
}


static void DropProx( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTProxArmed, 0);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	evPost(nThing, SS_SPRITE, 2 * kTimerRate);	// arm it after 2 seconds
	UseAmmo(pPlayer, kAmmoTNTProximity, 1);
}


static void ThrowRemote( int /* nTrigger */, PLAYER *pPlayer )
{
	pPlayer->throwTime = ClipHigh(pPlayer->throwTime, kMaxThrowTime);
	int velocity = muldiv(pPlayer->throwTime, kMaxThrowVel - kMinThrowVel, kMaxThrowTime) + kMinThrowVel;
	int nThing = playerFireThing(pPlayer, kSlopeThrow, kThingTNTBundle, velocity);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	pXSprite->triggerProximity = 1;
	UseAmmo(pPlayer, kAmmoTNTRemote, 1);
}


static void DropRemote( int /* nTrigger */, PLAYER *pPlayer )
{
	int nThing = playerFireThing(pPlayer, 0, kThingTNTRemArmed, 0);
	XSPRITE *pXSprite = &xsprite[sprite[nThing].extra];
	pXSprite->rxID = kChannelRemoteFire1 + pPlayer->sprite->type - kDudePlayer1;
	UseAmmo(pPlayer, kAmmoTNTRemote, 1);
	//sndStartSample( "tnt_prox", 64 );
}


static void FireRemote( int /* nTrigger */, PLAYER *pPlayer )
{
	evSend(0, 0, kChannelRemoteFire1 + pPlayer->sprite->type - kDudePlayer1, kCommandOn);
}


static void FireShotgun( PLAYER *pPlayer, int nBarrels )
{
	dassert(nBarrels > 0 && nBarrels <= kShotgunBarrels);

	int nVectors = nBarrels * kVectorsPerBarrel;

	SPRITE *pSprite = pPlayer->sprite;

	int z = pSprite->z - pPlayer->weaponAboveZ;

	for ( int i = 0; i < nVectors; i++ )
	{
		// dispersal modifiers
		int ddx = BiRandom2(2000);
		int ddy = BiRandom2(2000);
		int ddz = BiRandom2(2000);

		actFireVector(pPlayer->nSprite, z,
			pPlayer->aim.dx + ddx, pPlayer->aim.dy + ddy, pPlayer->aim.dz + ddz,
			kVectorShell);
	}
	if (nBarrels == 1)
		sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxShotFire);
	else
		sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxShotFire2);
}


static void FireTommy( int /* nTrigger */, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;

	int z = pSprite->z - pPlayer->weaponAboveZ;

	UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);

	// dispersal modifiers
	int ddx = BiRandom(1000);
	int ddy = BiRandom(1000);
	int ddz = BiRandom(1000);

	actFireVector(pPlayer->nSprite, z,
		pPlayer->aim.dx + ddx, pPlayer->aim.dy + ddy, pPlayer->aim.dz + ddz,
		kVectorBullet);
	sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxTomFire);
}


static void FireFlare( int /* nTrigger */, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;

	playerFireMissile(pPlayer, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
		kMissileFlare);
	UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);
	sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxFlareFire);
}


// this is a hack to fire a starburst flare
static void FireFlare2( int /* nTrigger */, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;

	playerFireMissile(pPlayer, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
		kMissileStarburstFlare);
	UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);
	sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxFlareFire);
}


static void FireVoodoo( int nStabType, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;
	SPRITE *pTarget = NULL;
	int nSelfSprite = pPlayer->nSprite;
	int z = pSprite->z - pPlayer->weaponAboveZ;

	if ( nStabType == kVoodooStabSelf )
	{
		actDamageSprite(nSelfSprite, pPlayer->nSprite, kDamageStab, 2 << 4);
		if (pPlayer == gMe)
			viewSetMessage("Ouch!");
		return;
	}

	dassert(pPlayer->aimSprite >= 0);
	pTarget = &sprite[pPlayer->aimSprite];

	switch( nStabType )
	{
		case kVoodooStabChest:
			sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxVoodooHit);
			actSpawnEffect(pTarget->sectnum, pTarget->x, pTarget->y, pTarget->z,
				ET_Squib1);
			actDamageSprite(nSelfSprite, pPlayer->aimSprite, kDamageVoodoo, 10 << 4);
			break;

		case kVoodooStabShoulder:
			sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxVoodooHit2);
			actSpawnEffect(pTarget->sectnum, pTarget->x, pTarget->y, pTarget->z,
				ET_Squib1);
			actDamageSprite(nSelfSprite, pPlayer->aimSprite, kDamageVoodoo, 20 << 4);
			if ( pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8 )
			{
				int nPlayerHit = pTarget->type - kDudePlayer1;
				WeaponLower(&gPlayer[nPlayerHit], &gPlayerInput[nPlayerHit]);
			}
			break;

		case kVoodooStabGroin:
			sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxPlayLaugh);
			actSpawnEffect(pTarget->sectnum, pTarget->x, pTarget->y, pTarget->z,
				ET_Squib1);
			actDamageSprite(nSelfSprite, pPlayer->aimSprite, kDamageVoodoo, 50 << 4);
			break;

		case kVoodooStabEye:
			sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxVoodooHit4);
			actSpawnEffect(pTarget->sectnum, pTarget->x, pTarget->y, pTarget->z,
				ET_Squib1);
			actDamageSprite(nSelfSprite, pPlayer->aimSprite, kDamageVoodoo, 25 << 4);
			if ( pTarget->type >= kDudePlayer1 && pTarget->type <= kDudePlayer8 )
			{
				PLAYER *pPlayerHit = &gPlayer[pTarget->type - kDudePlayer1];
				if (pPlayerHit == gView)	// change to gMe later!
				   	scrDacRelEffect(-96, -96, -96);
			}
			break;
	}
}


static void FireSpear( int /* nTrigger */, PLAYER *pPlayer )
{
	playerFireMissile(pPlayer, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
		kMissileSpear);
	UseAmmo(pPlayer, pPlayer->weaponAmmo, 1);
}


static void FireShadow( int /* nTrigger */, PLAYER *pPlayer )
{
	playerFireMissile(pPlayer, pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
		kMissileEctoSkull);

	if ( !gInfiniteAmmo )
		actDamageSprite(pPlayer->nSprite, pPlayer->nSprite, kDamageSpirit, 10 << 4);
}


static void FireReanimator( int /* nTrigger */, PLAYER *pPlayer )
{
	SPRITE *pSprite = pPlayer->sprite;

	int z = pSprite->z - pPlayer->weaponAboveZ;

	sfxCreate3DSound(pSprite->x, pSprite->y, pSprite->z, kSfxVoodooChant);

	for ( int i = 0; i < 4; i++ )
	{
		// dispersal modifiers
		int ddx = BiRandom(2000);
		int ddy = BiRandom(2000);
		int ddz = BiRandom(2000);

		HITINFO hitInfo;

		int hitCode = HitScan( pPlayer->sprite, z,
			pPlayer->aim.dx + ddx, pPlayer->aim.dy + ddy, pPlayer->aim.dz + ddz, &hitInfo );

		// ADD: limit distance of reanimator voodoo

		switch ( hitCode )
		{
			case SS_SPRITE:
			{
				SPRITE *pSprite = &sprite[hitInfo.hitsprite];
				if (pSprite->type == kDudeAxeZombie && pSprite->owner == -1)
				{
					//dprintf("calling playerAddLackey\n");
					if (playerAddLackey(pPlayer, hitInfo.hitsprite))
						aiSetTarget( &xsprite[pSprite->extra], pPlayer->sprite->x, pPlayer->sprite->y, pPlayer->sprite->z );
				}
				break;
			}
		}
	}
}


uchar WeaponFindLoaded( PLAYER *pPlayer )
{
	dprintf("WeaponFindLoaded\n");

	// see if it just needs to switch to a different type of ammo
	switch ( pPlayer->weapon )
	{
		case kWeaponTNT:
			if ( pPlayer->ammoCount[kAmmoTNTStick] || pPlayer->ammoCount[kAmmoTNTProximity] ||
				pPlayer->ammoCount[kAmmoTNTRemote] )
				return kWeaponTNT;
			break;

		case kWeaponTommy:
			if ( pPlayer->ammoCount[kAmmoBullet] || pPlayer->ammoCount[kAmmoBulletAP] )
				return kWeaponTommy;
			break;

		case kWeaponFlare:
			if ( pPlayer->ammoCount[kAmmoFlare] || pPlayer->ammoCount[kAmmoFlareSB] )
				return kWeaponFlare;
			break;

		case kWeaponSpear:
			if ( pPlayer->ammoCount[kAmmoSpear] || pPlayer->ammoCount[kAmmoSpearXP] )
				return kWeaponSpear;
			break;
	}

	// switch to a new weapon based on available ammo
	if ( pPlayer->hasWeapon[ kWeaponShadow ] && powerupCheck(pPlayer, kItemInvulnerability - kItemBase) )
		return kWeaponShadow;
	else if ( pPlayer->hasWeapon[kWeaponTommy] && CheckAmmo(pPlayer, kAmmoBullet) )
		return kWeaponTommy;
	else if ( pPlayer->hasWeapon[kWeaponTommy] && CheckAmmo(pPlayer, kAmmoBulletAP) )
		return kWeaponTommy;
	else if ( pPlayer->hasWeapon[kWeaponShotgun] && CheckAmmo( pPlayer, kAmmoShell) )
		return kWeaponShotgun;
	else if ( pPlayer->hasWeapon[kWeaponFlare] && CheckAmmo(pPlayer, kAmmoFlareSB) )
		return kWeaponFlare;
	else if ( pPlayer->hasWeapon[kWeaponFlare] && CheckAmmo(pPlayer, kAmmoFlare) )
		return kWeaponFlare;
	else if ( pPlayer->hasWeapon[kWeaponSpear] && CheckAmmo(pPlayer, kAmmoSpearXP) )
		return kWeaponSpear;
	else if ( pPlayer->hasWeapon[kWeaponSpear] && CheckAmmo(pPlayer, kAmmoSpear) )
		return kWeaponSpear;
	else if ( pPlayer->hasWeapon[kWeaponSprayCan] && CheckAmmo(pPlayer, kAmmoSprayCan) )
		return kWeaponSprayCan;
	else if ( pPlayer->hasWeapon[kWeaponTNT] && CheckAmmo(pPlayer, kAmmoTNTStick) )
		return kWeaponTNT;
	else if ( pPlayer->hasWeapon[kWeaponTNT] && CheckAmmo(pPlayer, kAmmoTNTProximity) )
		return kWeaponTNT;
	else if ( pPlayer->hasWeapon[kWeaponTNT] && CheckAmmo(pPlayer, kAmmoTNTRemote) )
		return kWeaponTNT;
	else if ( pPlayer->hasWeapon[kWeaponVoodoo] && CheckAmmo(pPlayer, kAmmoVoodoo) )
		return kWeaponVoodoo;
	else if ( pPlayer->hasWeapon[kWeaponShadow] && pPlayer->xsprite->health > 75 )
		return kWeaponShadow;

	return kWeaponPitchfork;
}


/*
;[Weapon#]
;Name            = "WeaponNameMax24"
;SelectKey       = [ None | scancode ]
;UseByDefault    = [ TRUE | FALSE ]
;HasByDefault    = [ TRUE | FALSE ]
;RequiresWeapon  = [ None | 0..9 ]
;
;Type            = [ NonWeapon | Melee | Thrown | Projectile | Vector ]
;Type            = NonWeapon
;
;Type            = Melee
;MaxDistance     = [ Infinite | 0..max ]
;
;Type            = Thrown
;MaxDistance     = [ Infinite | 0..max ]
;
;Type            = Projectile
;MaxDistance     = [ Infinite | 0..max ]
;
;Type            = Vector (uses hitscan)
;MaxDistance     = [ Infinite | 0..max ]
;Richochet       = [ TRUE | FALSE ]
;UsesNightScope  = [ TRUE | FALSE ]
;
;Shots           = [ 0..max shots or projectiles ]
;Dispersion      = [ 0..100% ]
;Accuracy        = [ 0..100% ]
;
;AmmoStyle       = [ Infinite, Rechargable, Expendable, Health ]
;AmmoStyle       = Infinite
;
;AmmoStyle       = Rechargable
;RechargeRate    = [ 0 | ammo/second (?) ]
;MaxAmmo         = [ 0..max ]
;
;AmmoStyle       = Expendable
;MaxAmmo         = [ 0..max ]
;AmmoType        = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 ]
;
;AmmoStyle       = Health
;HealthPerShot   = [ 0..usedpershot ]
;
;JamFrequency    = [ 0..100% ]
;JamSingleFire   = [ TRUE | FALSE ]
;JamRapidFire    = [ TRUE | FALSE ]
;
;[Ammo#]
;Name            = "AmmoNameMax24"
;Velocity        = [ ? ]
;DamageTypes     = [ Explosion, Burn, Bullet, Stab, Pummel, Cleave, Ecto]
;DamageRates     = [ 0,         0,    0,      0,    0,      0,      0 ]
*/

void WeaponProcess( PLAYER *pPlayer, INPUT *pInput )
{
	WeaponPlay(pPlayer);

	// decrement weapon ready timer
	pPlayer->weaponTimer -= kFrameTicks;

	if ( pPlayer->fLoopQAV )
	{
		if ( pInput->buttonFlags.shoot && pPlayer->ammoCount[pPlayer->weaponAmmo] )
		{
			while ( pPlayer->weaponTimer <= 0 )
				pPlayer->weaponTimer += pPlayer->pWeaponQAV->duration;
			UpdateAimVector(pPlayer);
			return;
		}
		pPlayer->weaponTimer = 0;
		pPlayer->fLoopQAV = FALSE;
	}
	else
		pPlayer->weaponTimer = ClipLow(pPlayer->weaponTimer, 0);

	// special processing for TNT
	if ( pPlayer->weapon == kWeaponTNT )
	{
		switch ( pPlayer->weaponState )
		{
			case kTNTStickFuse1:
				// player released alt fire key?
				if ( !pInput->buttonFlags.shoot2 )
					pPlayer->weaponState = kTNTStickFuse2;
				return;

			case kTNTStickFuse2:
				// dropping?
				if ( pInput->buttonFlags.shoot2 )
				{
					pPlayer->fuseTime = pPlayer->weaponTimer;
					StartQAV(pPlayer, kQAVStickDrop, (QAVCALLBACK)DropStick);
					pPlayer->weaponState = kBicIdle;
					return;
				}
				// throwing?
				if ( pInput->buttonFlags.shoot )
				{
					pPlayer->weaponState = kTNTStickThrow;
					pPlayer->fuseTime = 0;
					pPlayer->throwTime = gFrameClock;
				}
				return;

			case kTNTStickThrow:
				// releasing?
				if ( !pInput->buttonFlags.shoot )
				{
					if ( pPlayer->fuseTime == 0 )
						pPlayer->fuseTime = pPlayer->weaponTimer;
					pPlayer->throwTime = gFrameClock - pPlayer->throwTime;
					sfxCreate3DSound(pPlayer->sprite->x, pPlayer->sprite->y, pPlayer->sprite->z,
						kSfxTNTToss);
					StartQAV(pPlayer, kQAVStickThrow, (QAVCALLBACK)ThrowStick);
					pPlayer->weaponState = kBicIdle;
				}
				return;

			case kTNTBundleFuse1:
				// player released alt fire key?
				if ( !pInput->buttonFlags.shoot2 )
					pPlayer->weaponState = kTNTBundleFuse2;
				return;

			case kTNTBundleFuse2:
				// dropping?
				if ( pInput->buttonFlags.shoot2 )
				{
					pPlayer->fuseTime = pPlayer->weaponTimer;
					StartQAV(pPlayer, kQAVBundleDrop, (QAVCALLBACK)DropBundle);
					pPlayer->weaponState = kBicIdle;
					return;
				}

				// throwing?
				if ( pInput->buttonFlags.shoot )
				{
					pPlayer->weaponState = kTNTBundleThrow;
					pPlayer->fuseTime = 0;
					pPlayer->throwTime = gFrameClock;
				}
				return;

			case kTNTBundleThrow:
				// releasing?
				if ( !pInput->buttonFlags.shoot )
				{
					if ( pPlayer->fuseTime == 0 )
						pPlayer->fuseTime = pPlayer->weaponTimer;
					pPlayer->throwTime = gFrameClock - pPlayer->throwTime;
					StartQAV(pPlayer, kQAVBundleThrow, (QAVCALLBACK)ThrowBundle);
					pPlayer->weaponState = kBicIdle;
				}
				return;

			case kTNTProxThrow:
				// releasing?
				if ( !pInput->buttonFlags.shoot )
				{
					pPlayer->throwTime = gFrameClock - pPlayer->throwTime;
					StartQAV(pPlayer, kQAVBundleThrow, (QAVCALLBACK)ThrowProx);
					pPlayer->weaponState = kTNTProxEmpty;
				}
				return;

			case kTNTRemoteThrow:
				// releasing?
				if ( !pInput->buttonFlags.shoot )
				{
					pPlayer->throwTime = gFrameClock - pPlayer->throwTime;
					StartQAV(pPlayer, kQAVBundleThrow, (QAVCALLBACK)ThrowRemote);
					pPlayer->weaponState = kTNTRemoteEmpty;
				}
				return;
		}
	}

	// return if weapon is busy
	if (pPlayer->weaponTimer > 0)
		return;

	pPlayer->pWeaponQAV = NULL;

	// pPlayer->weapon is set to kMaxWeapons in the fire processing below
	if ( pPlayer->weaponState == kFindWeapon )
	{
		dprintf("Out of ammo: looking for a new weapon\n");
		pPlayer->weaponState = 0;
		pInput->newWeapon = WeaponFindLoaded( pPlayer );
	}

	// weapon select
	if ( pInput->newWeapon )
	{
		if ( pPlayer->xsprite->health == 0 || !pPlayer->hasWeapon[ pInput->newWeapon ] )
		{
			pInput->newWeapon = 0;
			return;
		}

		if (pPlayer->weapon != 0)
			WeaponLower(pPlayer, pInput);	// lower the old weapon
		else
			WeaponRaise(pPlayer, pInput);	// raise new weapon
		return;
	}

	if ( pPlayer->weapon == 0 )
		return;		// no weapon drawn, do nothing

	UpdateAimVector(pPlayer);

	// fire key
	if ( pInput->buttonFlags.shoot )
	{
		if ( CheckAmmo(pPlayer, pPlayer->weaponAmmo) )
		{
			// firing weapon (primary)
			switch ( pPlayer->weapon )
			{
				case kWeaponPitchfork:
					StartQAV(pPlayer, kQAVForkStab, (QAVCALLBACK)FirePitchfork, FALSE);
					return;

				case kWeaponSprayCan:
					if ( pPlayer->weaponState == kCanIdle )
					{
						StartQAV(pPlayer, kQAVSprayFire, (QAVCALLBACK)FireSpray, TRUE);
						pPlayer->weaponState = kCanFire;
						return;
					}
					break;

				case kWeaponTNT:
					switch ( pPlayer->weaponState )
					{
						case kTNTStickIdle:
							StartQAV(pPlayer, kQAVStickFuse, (QAVCALLBACK)ExplodeStick);
		 					pPlayer->weaponState = kTNTStickThrow;
							pPlayer->throwTime = gFrameClock;
							pPlayer->fuseTime = -1;
							return;

						case kTNTBundleIdle:
							StartQAV(pPlayer, kQAVBundleFuse, (QAVCALLBACK)ExplodeBundle);
		 					pPlayer->weaponState = kTNTBundleThrow;
							pPlayer->throwTime = gFrameClock;
							pPlayer->fuseTime = -1;
							return;

						case kTNTProxIdle:
		 					pPlayer->weaponState = kTNTProxThrow;
							pPlayer->throwTime = gFrameClock;
							return;

						case kTNTRemoteIdle1:
		 					pPlayer->weaponState = kTNTRemoteThrow;
							pPlayer->throwTime = gFrameClock;
							return;

						case kTNTRemoteIdle2:
							StartQAV(pPlayer, kQAVRemoteFire, (QAVCALLBACK)FireRemote);
							pPlayer->weaponState = kTNTRemoteEmpty;
							return;
					}
					break;

			    case kWeaponShotgun:
					switch ( pPlayer->weaponState )
					{
						case kShotIdle2:
							StartQAV(pPlayer, kQAVShotFireL);
							pPlayer->weaponState = kShotIdle1;
							UseAmmo(pPlayer, kAmmoShell, 1);
							FireShotgun(pPlayer, 1);
							return;

						case kShotIdle1:
							StartQAV(pPlayer, kQAVShotFireR);
						    pPlayer->weaponState = kShotIdle0;
							UseAmmo(pPlayer, kAmmoShell, 1);
							FireShotgun(pPlayer, 1);
							return;
					}
					break;

				case kWeaponTommy:
					StartQAV(pPlayer, kQAVTommyFire1, (QAVCALLBACK)FireTommy, TRUE);
					return;

				case kWeaponFlare:
					StartQAV(pPlayer, kQAVFlareFire, (QAVCALLBACK)FireFlare);
					return;

				case kWeaponVoodoo:
				{
					int nStabType = Random(4);
					if ( pPlayer->aimSprite == -1 )
						nStabType = 4;

					StartQAV(pPlayer, kQAVDollStab1 + nStabType, (QAVCALLBACK)FireVoodoo);
					return;
				}

			    case kWeaponSpear:
					StartQAV(pPlayer, kQAVSpearFire, (QAVCALLBACK)FireSpear);
					return;

				case kWeaponShadow:
					StartQAV(pPlayer, kQAVShadowFire, (QAVCALLBACK)FireShadow);
					return;

				case kWeaponBeast:
					StartQAV(pPlayer, kQAVBeastAttack1 + Random(4));
					pPlayer->weaponState = kBeastIdle;
					return;
			}
		}
		else
		{
			dprintf("Primary out of ammo: setting weapon state to kFindWeapon\n");
			pPlayer->weaponState = kFindWeapon;
			return;
		}
	}

	// alternate fire key
	if ( pInput->buttonFlags.shoot2 )
	{
		if ( CheckAmmo(pPlayer, pPlayer->weaponAmmo) )
		{
			// firing weapon (alternate)
			switch ( pPlayer->weapon )
			{
				case kWeaponPitchfork:
					playerFireMissile(pPlayer,
						pPlayer->aim.dx, pPlayer->aim.dy, pPlayer->aim.dz,
						kMissileFireball);
					pPlayer->weaponTimer = 20;
					return;

				case kWeaponSprayCan:
					if ( pPlayer->weaponState == kCanIdle )
					{
						StartQAV(pPlayer, kQAVSprayFire, (QAVCALLBACK)FireSpray, TRUE);
						pPlayer->weaponState = kCanFire;
						return;
					}
					break;

				case kWeaponTNT:
					switch ( pPlayer->weaponState )
					{
						case kTNTStickIdle:
							StartQAV(pPlayer, kQAVStickFuse, (QAVCALLBACK)ExplodeStick);
							pPlayer->weaponState = kTNTStickFuse1;
							return;

						case kTNTBundleIdle:
							StartQAV(pPlayer, kQAVBundleFuse, (QAVCALLBACK)ExplodeBundle);
							pPlayer->weaponState = kTNTBundleFuse1;
							return;

						case kTNTProxIdle:
							StartQAV(pPlayer, kQAVProxDrop, (QAVCALLBACK)DropProx);
							pPlayer->weaponState = kTNTProxEmpty;
							return;

						case kTNTRemoteIdle1:
							StartQAV(pPlayer, kQAVRemoteDrop, (QAVCALLBACK)DropRemote);
							pPlayer->weaponState = kTNTRemoteIdle2;
							return;

						case kTNTRemoteIdle2:
							// raise another bundle
							StartQAV(pPlayer, kQAVRemoteUp1);
							pPlayer->weaponState = kTNTRemoteIdle1;
							return;
					}
					break;

				case kWeaponShotgun:
					switch ( pPlayer->weaponState )
					{
						case kShotIdle2:
							StartQAV(pPlayer, kQAVShotFireR);
							pPlayer->weaponState = kShotIdle0;
							UseAmmo(pPlayer, kAmmoShell, 2);
							FireShotgun(pPlayer, 2);
							return;
						case kShotIdle1:
							StartQAV(pPlayer, kQAVShotFireR);
							pPlayer->weaponState = kShotIdle0;
							UseAmmo(pPlayer, kAmmoShell, 1);
							FireShotgun(pPlayer, 1);
							return;
					}
					break;

				case kWeaponTommy:
					StartQAV(pPlayer, kQAVTommyFire1, (QAVCALLBACK)FireTommy, TRUE);
					return;

				case kWeaponFlare:
					StartQAV(pPlayer, kQAVFlareFire, (QAVCALLBACK)FireFlare2);
					return;

				case kWeaponVoodoo:
					StartQAV(pPlayer, kQAVDollSpell, (QAVCALLBACK)FireReanimator, FALSE);
					return;

			    case kWeaponSpear:
					StartQAV(pPlayer, kQAVSpearFire, (QAVCALLBACK)FireSpear);
					return;

				case kWeaponShadow:
					StartQAV(pPlayer, kQAVShadowFire, (QAVCALLBACK)FireShadow);
					return;
			}
		}
		else
		{
			dprintf("Alternate out of ammo: setting weapon state to kFindWeapon\n");
			pPlayer->weaponState = kFindWeapon;
			return;
		}
	}

	WeaponUpdateState(pPlayer);
}
