/***********************************************************************************************************/
/*                                                                                                         */
/* Rifle Controllers                                                                                    	  */
/*                                                                                                         */
/***********************************************************************************************************/

/*---------------------------------------------------------------------------
 *	Import Headers
\*--------------------------------------------------------------------------*/

#ifdef PSX_VERSION
#include "../spec_psx/typedefs.h"
#include "../spec_psx/psxinput.h"
#include "../spec_psx/file.h"
#else
#include "../specific/standard.h"
#include "../specific/input.h"
#endif

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "control.h"
#include "input.h"
#include "sound.h"
#include "savegame.h"
#include "effect2.h"
#include "traps.h"
#include "lara1gun.h"
#include "triboss.h"
#include "title.h"
#include "camera.h"

extern short rcossin_tbl[];

sint16 FuckYou=0;

/*---------------------------------------------------------------------------
 *	Constants
\*--------------------------------------------------------------------------*/

#define HARPOON_DRAW_ANIM 1
#define ROCKET_DRAW_ANIM  0

#define 	PELLET_SCATTER  		(20*ONE_DEGREE)        // Scatter of pellets
#define 	HARPOON_SPEED			256
#define 	HARPOON_TIME			256
#define 	ROCKET_SPEED 			512
#define 	GRENADE_SPEED 			128
#define	MAX_GRENADE_FALLSPEED	128

#if defined(PSX_VERSION) && defined(JAPAN)
#define PISTOL_DAMAGE	2		// Everything relates to pistol damage
#else
#define PISTOL_DAMAGE	1		// Everything relates to pistol damage
#endif

enum weapon_anim {
	W_AIM,
	W_DRAW,
	W_RECOIL,
	W_UNDRAW,
	W_UNAIM,
	W_RELOAD,
	W_UAIM,
	W_UUNAIM,
	W_URECOIL,
	W_SURF_UNDRAW
};

/*---------------------------------------------------------------------------
 * Public Functions
\*--------------------------------------------------------------------------*/

/******************************************************************************
 *						Draw ShotGun Meshes
 *****************************************************************************/
void	draw_shotgun_meshes( int weapon_type )
{
	int obj;

	obj = WeaponObject(weapon_type);
	lara.mesh_ptrs[HAND_R]  = meshes[objects[obj].mesh_index + HAND_R];
	lara.back_gun = 0;
}

/******************************************************************************
 *						UnDraw ShotGun Meshes
 *****************************************************************************/
void	undraw_shotgun_meshes( int weapon_type )
{
	int obj;

	obj = WeaponObject(weapon_type);
	lara.mesh_ptrs[HAND_R]  = meshes[objects[LARA].mesh_index + HAND_R];
	lara.back_gun = obj;
}

/******************************************************************************
 *						Make ShotGun ready
 *****************************************************************************/
void	ready_shotgun( int weapon_type )
{
	lara.gun_status = LG_READY;
	lara.left_arm.x_rot = lara.left_arm.y_rot = lara.left_arm.z_rot = 0;
	lara.right_arm.x_rot = lara.right_arm.y_rot = lara.right_arm.z_rot = 0;
	lara.left_arm.frame_number = lara.right_arm.frame_number = 0;
	lara.left_arm.lock = lara.right_arm.lock = 0;
	lara.target = NULL;
	lara.left_arm.frame_base = lara.right_arm.frame_base = objects[WeaponObject(weapon_type)].frame_base;
//	lara.torso_x_rot = lara.torso_y_rot = 0;
//	lara.head_x_rot = lara.head_y_rot = 0;
}

/*****************************************************************************
 *        Put Shotgun back in its Holster
 ****************************************************************************/
void	RifleHandler( int weapon_type )
{
	WEAPON_INFO	*winfo;

	winfo = &weapons[weapon_type];

	/* Get Target Information */
	if ( input&IN_ACTION )
		LaraTargetInfo( winfo );
	else
		lara.target = NULL;

	if ( lara.target==NULL )					// If No Targets are Locked
		LaraGetNewTarget( winfo );            	// attempt to find new target

	/* Aim Shotgun where-ever*/
	AimWeapon( winfo,&lara.left_arm );

	/* Make Lara look at Target */
	if ( lara.left_arm.lock )
	{
		lara.torso_y_rot = lara.left_arm.y_rot;
		lara.torso_x_rot = lara.left_arm.x_rot;
		if (camera.old_type != LOOK_CAMERA)
			lara.head_x_rot = lara.head_y_rot = 0;
	}

	lara.torso_x_rot += FuckYou;
	lara.left_arm.x_rot += FuckYou;

	/* Animate Shotgun */
	if (weapon_type == LG_MAGNUMS)
		AnimatePistols(weapon_type);
	else
		AnimateShotgun(weapon_type);

	// Make flash of light each time Lara fires her guns
	if (lara.right_arm.flash_gun)
	{
		if (weapon_type == LG_SHOTGUN || weapon_type == LG_M16)
		{
			TriggerDynamic(
				lara_item->pos.x_pos + (phd_sin(lara_item->pos.y_rot) >> (W2V_SHIFT-10)) + ((GetRandomControl()&255)-128),
				lara_item->pos.y_pos - WALL_L/2 + ((GetRandomControl()&127)-63),
				lara_item->pos.z_pos + (phd_cos(lara_item->pos.y_rot) >> (W2V_SHIFT-10)) + ((GetRandomControl()&255)-128),
				(weapon_type == LG_SHOTGUN) ? 12 : 11,
				(GetRandomControl()&7)+24,
				(GetRandomControl()&3)+16,
				GetRandomControl()&7
			);
		}

		else if (weapon_type == LG_MAGNUMS)
		{
			PHD_VECTOR pos;

			VIBRATE(0x1000, 0x1000, 2, 0x800, 2);

			pos.x = (GetRandomControl()&255)-128;
			pos.y = (GetRandomControl()&127)-63;
			pos.z = (GetRandomControl()&255)-128;
			GetLaraHandAbsPosition(&pos, 1);

			TriggerDynamic(
				pos.x,
				pos.y,
				pos.z,
				12,
				(GetRandomControl()&7)+24,
				(GetRandomControl()&3)+16,
				GetRandomControl()&7
			);
		}
	}
}

/******************************************************************************
 *			Actually Fire ShotGun please
 *****************************************************************************/

void	FireShotgun( void )
{
	int			i,r,fired,x,y,z,lp;
	PHD_VECTOR pos;
	PHD_ANGLE	angles[2];
	PHD_ANGLE	dangles[2];

	angles[0] = lara.left_arm.y_rot + lara_item->pos.y_rot;
	angles[1] = lara.left_arm.x_rot;

	if (!lara.left_arm.lock)
	{
		angles[0] += lara.torso_y_rot;
	 	angles[1] += lara.torso_x_rot;
	}

	fired = 0;

	for ( i=0; i<SHOTGUN_AMMO_CLIP; i++ )
	{
		r = (int)((GetRandomControl()-16384)*PELLET_SCATTER)/65536;
		dangles[0] = angles[0] + r;
		r = (int)((GetRandomControl()-16384)*PELLET_SCATTER)/65536;
		dangles[1] = angles[1] + r;
		if ( FireWeapon( LG_SHOTGUN, lara.target, lara_item, dangles ) )
			fired=1;
	}

	if ( fired )
	{
		pos.x = 0;
		pos.y = SHOTGUN_YOFF;
		pos.z = SHOTGUN_ZOFF;
		GetLaraHandAbsPosition(&pos, 1);
		x = pos.x;
		y = pos.y;
		z = pos.z;
		pos.x = 0;
		pos.y = SHOTGUN_YOFF+1280;
		pos.z = SHOTGUN_ZOFF;
		GetLaraHandAbsPosition(&pos, 1);

		SmokeCountL = 32;
		SmokeWeapon = LG_SHOTGUN;
		for (lp=0;lp<7;lp++)
			TriggerGunSmoke(x, y, z, pos.x-x, pos.y-y, pos.z-z, 1, SmokeWeapon, 32);
		for (lp=0;lp<12;lp++)
			TriggerShotgunSparks(x, y, z, (pos.x-x)<<1, (pos.y-y)<<1, (pos.z-z)<<1);

		lara.right_arm.flash_gun = weapons[LG_SHOTGUN].flash_time;

		SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x1400000);
		SoundEffect(weapons[LG_SHOTGUN].sample_num, &lara_item->pos,0 );

#if defined(GAMEDEBUG) && defined(PC_VERSION)
		level.ammo_used += 18;
#endif

		VIBRATE(0x1000, 0x1000, 2, 0x600, 5);

	}
}


void FireM16(int running)
{
	PHD_ANGLE angles[2];

	angles[0] = lara.left_arm.y_rot + lara_item->pos.y_rot;
	angles[1] = lara.left_arm.x_rot;

	if (!lara.left_arm.lock)
	{
		angles[0] += lara.torso_y_rot;
	 	angles[1] += lara.torso_x_rot;
	}

	// If running, reduce accuracy and damage
	if (running)
	{
		weapons[M16].shot_accuracy = ONE_DEGREE*12;
		weapons[M16].damage = 1;
	}
	else
	{
		weapons[M16].shot_accuracy = ONE_DEGREE*4;
		weapons[M16].damage = 3;
	}

	if (FireWeapon(LG_M16, lara.target, lara_item, angles))
	{
		SmokeCountL = 24;
		SmokeWeapon = LG_M16;
		TriggerGunShell(RIGHT_HAND,GUNSHELL,LG_M16);
		lara.right_arm.flash_gun = weapons[LG_M16].flash_time;

		VIBRATE(0x1000, 0x1000, 2, 0x1000, 2);

#if defined(GAMEDEBUG) && defined(PC_VERSION)
		level.ammo_used += 3; // this is what it is counted as, though may be wasted if running
#endif
	}
}


void FireHarpoon(void)
{
	sint16 item_number;
	ITEM_INFO *item;
	GAME_VECTOR pos;
	int distance;

	if (lara.harpoon.ammo <= 0)
		return;

	/* Create a harpoon object and launch it on its way */
	item_number = CreateItem();
	if (item_number != NO_ITEM)
	{
		item = &items[item_number];

		item->shade = 0x4210|0x8000;

		item->object_number = HARPOON_BOLT;		// Harpoon.
		item->room_number = lara_item->room_number;
		pos.x = -2;
		pos.y = 273 + 100;
		pos.z = 77;
		GetLaraHandAbsPosition((PHD_VECTOR *)&pos, RIGHT_HAND);
		item->pos.x_pos = pos.x;
		item->pos.y_pos = pos.y;
		item->pos.z_pos = pos.z;

		InitialiseItem(item_number);

		/* Choose angle */
		if (lara.target)
		{
			find_target_point(lara.target, &pos);

			item->pos.y_rot = phd_atan(pos.z - item->pos.z_pos, pos.x - item->pos.x_pos);
			distance = phd_sqrt(SQUARE(pos.z - item->pos.z_pos) + SQUARE(pos.x - item->pos.x_pos));
			item->pos.x_rot = -phd_atan(distance, pos.y - item->pos.y_pos);
		}
		else
		{
			item->pos.x_rot = lara_item->pos.x_rot + lara.torso_x_rot;
			item->pos.y_rot = lara_item->pos.y_rot + lara.torso_y_rot;
		}
		item->pos.z_rot = 0;

		item->fallspeed = (sint16)(-HARPOON_SPEED * phd_sin(item->pos.x_rot) >> W2V_SHIFT);
		item->speed = (sint16)(HARPOON_SPEED * phd_cos(item->pos.x_rot) >> W2V_SHIFT);
		item->hit_points = HARPOON_TIME;

		AddActiveItem(item_number);

		if (!savegame.bonus_flag)
			lara.harpoon.ammo--;
		savegame.ammo_used++;

		VIBRATE(0x1000, 0x1000, 2, 0x1000, 2);
	}
}

void ControlHarpoonBolt(sint16 item_number)
{
	ITEM_INFO *item, *target;
	FLOOR_INFO *floor;
	sint32 c, s, x, z, rx, rz, ox, oz, sx, sz, old_x, old_z, old_y, oldroom;
	sint16 room_number, target_number;
	sint16 *bounds;

	item = &items[item_number];

	old_x = item->pos.x_pos;
	old_y = item->pos.y_pos;
	old_z = item->pos.z_pos;
	oldroom = item->room_number;

//	if (!(room[item->room_number].flags & UNDERWATER))
//		item->fallspeed += GRAVITY/2;

	item->pos.z_pos += item->speed * phd_cos(item->pos.y_rot) >> W2V_SHIFT;
	item->pos.x_pos += item->speed * phd_sin(item->pos.y_rot) >> W2V_SHIFT;
	item->pos.y_pos += item->fallspeed;

	room_number = item->room_number;
	floor = GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
	item->floor = GetHeight(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);

	if (item->room_number != room_number)
		ItemNewRoom(item_number, room_number);

	/* Has it hit a beastie? Check ones in same room as bolt TODO: should test surrounding rooms too? */
	for (target_number = room[item->room_number].item_number; target_number!=NO_ITEM; target_number=target->next_item)
	{
		target = &items[target_number];
		if (target == lara_item || !target->collidable || target->object_number == UPV)
			continue;

		if (	target->object_number==SMASH_WINDOW ||
			target->object_number==SMASH_OBJECT1 ||
			target->object_number==SMASH_OBJECT2 ||
			target->object_number==SMASH_OBJECT3 ||
			target->object_number==CARCASS ||
			target->object_number==EXTRAFX6 ||
			(target->status != INVISIBLE && objects[target->object_number].collision))
		{
			// check against bounds of target for collision
			bounds = GetBestFrame(target);
			if (item->pos.y_pos < target->pos.y_pos + bounds[2] || item->pos.y_pos > target->pos.y_pos + bounds[3])
				continue;

			// get vector from target to bolt and check against x,z bounds
			c = phd_cos(target->pos.y_rot);
			s = phd_sin(target->pos.y_rot);

			x = item->pos.x_pos - target->pos.x_pos;
			z = item->pos.z_pos - target->pos.z_pos;
			rx = (c*x - s*z) >> W2V_SHIFT;

			ox = old_x - target->pos.x_pos;
			oz = old_z - target->pos.z_pos;
			sx = (c*ox - s*oz) >> W2V_SHIFT;

			if ((rx < bounds[0] && sx < bounds[0]) || (rx > bounds[1] && sx > bounds[1]))
				continue;

			rz = (c*z + s*x) >> W2V_SHIFT;
			sz = (c*oz + s*ox) >> W2V_SHIFT;

			if ((rz < bounds[4] && sz < bounds[4]) || (rz > bounds[5] && sz > bounds[5]))
				continue;

			if (target->object_number==SMASH_OBJECT1 && CurrentLevel != LV_CRASH)
			{
				SmashWindow(target_number);
			}
			else if (target->object_number==SMASH_WINDOW ||
				target->object_number==SMASH_OBJECT2 ||
				target->object_number==SMASH_OBJECT3)
			{
				SmashWindow(target_number);
			}
			else if (target->object_number==CARCASS || target->object_number==EXTRAFX6)
			{
				if (item->status != ACTIVE)
				{
					item->status = ACTIVE;
					AddActiveItem(target_number);
				}
			}
			else if (target->object_number!=SMASH_OBJECT1)
			{
				if (objects[target->object_number].intelligent)
				{
					if (target->object_number != TRIBEBOSS || !TribeBossShieldOn)	//## TRIBEBOSS!!
					{
						if (target->object_number != TRIBEBOSS && target->object_number != LON_BOSS)
							DoLotsOfBlood(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, 0, 0, item->room_number, 3);
						HitTarget(target, NULL, weapons[LG_HARPOON].damage<<item->item_flags[0]);
						savegame.ammo_hit++;
					}
					else
						FindClosestShieldPoint(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, target);
				}
				KillItem(item_number);
				return;
			}
		}
	}

	/* Has it hit a wall or the floor? */
	if (item->pos.y_pos >= item->floor || item->pos.y_pos <= GetCeiling(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos))
	{
		if (item->hit_points == HARPOON_TIME)
		{
			item->current_anim_state = item->pos.x_rot;
		}

		if (item->hit_points >= 192)
		{
			item->pos.x_rot = item->current_anim_state+((((rcossin_tbl[((item->hit_points-192)<<9)&4095]>>1)-1024)*(item->hit_points-192))>>6);
			item->hit_points--;
		}

		item->hit_points--;
		if (!item->hit_points)
		{
			KillItem(item_number);
			return;
		}
		item->speed = item->fallspeed = 0;
	}
	else
	{
		item->pos.z_rot += (35*ONE_DEGREE);
		if (!(room[item->room_number].flags & UNDERWATER))
		{
			item->pos.x_rot -= (1*ONE_DEGREE);
			if (item->pos.x_rot < -16384)
				item->pos.x_rot = -16384;
			item->fallspeed = (sint16)(-HARPOON_SPEED * phd_sin(item->pos.x_rot) >> W2V_SHIFT);
			item->speed = (sint16)(HARPOON_SPEED * phd_cos(item->pos.x_rot) >> W2V_SHIFT);
		}
		else
		{
			/* Create bubbles in its wake if underwater */
			if ((wibble&15)==0)
				CreateBubble(&item->pos, item->room_number, 2, 8);
			TriggerRocketSmoke(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,64);
			item->fallspeed = (sint16)(-(HARPOON_SPEED>>1) * phd_sin(item->pos.x_rot) >> W2V_SHIFT);
			item->speed = (sint16)((HARPOON_SPEED>>1) * phd_cos(item->pos.x_rot) >> W2V_SHIFT);
		}
	}


	room_number = item->room_number;
	floor = GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
	GetHeight(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
	if (item->room_number != room_number)
		ItemNewRoom(item_number, room_number);

}

long	tbx,tby,tbz;

void FireRocket(void)
{
	sint16 item_number,lp;
	ITEM_INFO *item;
	PHD_VECTOR pos;
	long	x,y,z,wx,wy,wz,xv,yv,zv;

	if (lara.rocket.ammo <= 0)
		return;

	lara.has_fired = 1;

	/* Create a rocket object and launch it on its way */
	item_number = CreateItem();
	if (item_number != NO_ITEM)
	{
		item = &items[item_number];

		item->object_number = ROCKET;
		item->room_number = lara_item->room_number;
		pos.x = 0;
		pos.y = ROCKET_YOFF;
		pos.z = ROCKET_ZOFF;

		GetLaraHandAbsPosition(&pos, 1);
		item->pos.x_pos = x = pos.x;
		item->pos.y_pos = y = pos.y;
		item->pos.z_pos = z = pos.z;
		pos.x = 0;
		pos.y = ROCKET_YOFF+1024;
		pos.z = ROCKET_ZOFF;
		GetLaraHandAbsPosition(&pos, 1);

		SmokeCountL = 32;
		SmokeWeapon = LG_ROCKET;
		for (lp=0;lp<5;lp++)
			TriggerGunSmoke(x, y, z, pos.x-x, pos.y-y, pos.z-z, 1, LG_ROCKET, 32);

		InitialiseItem(item_number);

		item->pos.x_rot = lara_item->pos.x_rot + lara.left_arm.x_rot;
		item->pos.y_rot = lara_item->pos.y_rot + lara.left_arm.y_rot;
		item->pos.z_rot = 0;

		if (!lara.left_arm.lock)
		{
			item->pos.x_rot += lara.torso_x_rot;
	 		item->pos.y_rot += lara.torso_y_rot;
		}

//		item->pos.x_rot = lara_item->pos.x_rot + lara.left_arm.x_rot + lara.torso_x_rot;
//		item->pos.y_rot = lara_item->pos.y_rot + lara.left_arm.y_rot + lara.torso_y_rot;
//		item->pos.z_rot = 0;

		item->speed = ROCKET_SPEED>>5;
		item->item_flags[0] = 0;

		AddActiveItem(item_number);

#if !defined(GAMEDEBUG) && !defined(EZORAY)
		if (!savegame.bonus_flag)
			lara.rocket.ammo--;
#endif
		savegame.ammo_used++;

		phd_PushUnitMatrix();
#ifdef PSX_VERSION
		mSetTrans(0, 0, 0);
#else
		*(phd_mxptr+M03) = 0;
		*(phd_mxptr+M13) = 0;
		*(phd_mxptr+M23) = 0;
#endif
		phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);
		phd_PushMatrix();
		phd_TranslateRel( 0, 0, -128);
#ifdef PSX_VERSION
		wx = Matrix->tx;
		wy = Matrix->ty;
		wz = Matrix->tz;
#else
		wx = (*(phd_mxptr+M03)>>W2V_SHIFT);
		wy = (*(phd_mxptr+M13)>>W2V_SHIFT);
		wz = (*(phd_mxptr+M23)>>W2V_SHIFT);
#endif
		phd_PopMatrix();

		for (lp=0;lp<8;lp++)
		{
			phd_PushMatrix();
			phd_TranslateRel( 0, 0, -(GetRandomControl()&2047));
#ifdef PSX_VERSION
			xv = Matrix->tx;
			yv = Matrix->ty;
			zv = Matrix->tz;
#else
			xv = (*(phd_mxptr+M03)>>W2V_SHIFT);
			yv = (*(phd_mxptr+M13)>>W2V_SHIFT);
			zv = (*(phd_mxptr+M23)>>W2V_SHIFT);
#endif
			phd_PopMatrix();
			TriggerRocketFlame(wx,wy,wz,xv-wx,yv-wy,zv-wz,item_number);
		}
		phd_PopMatrix();

#if defined(PC_VERSION) && defined(GAMEDEBUG)
		level.ammo_used += 30;
#endif

		SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x2000000);
	}
}

#define ROCKET_BLAST_RADIUS (WALL_L)

void ControlRocket(sint16 item_number)
{
	sint16 *bounds;
	FLOOR_INFO *floor;
	long	wx,wy,wz,xv,yv,zv,lp;
	ITEM_INFO *item, *target;
	sint32 old_x, old_y, old_z;
	sint16 room_number, target_number, oldroom;
	sint32 speed, c, s, x, z, rx, rz, ox, oz, sx, sz, explode, radius, abovewater;

	item = &items[item_number];

	oldroom = item->room_number;
	old_x = item->pos.x_pos;
	old_y = item->pos.y_pos;
	old_z = item->pos.z_pos;

	if (room[item->room_number].flags & UNDERWATER)
	{
		if (item->speed > ROCKET_SPEED>>2)
			item->speed -= (item->speed>>2);
		else
		{
			item->speed += (item->speed>>2)+4;
			if (item->speed > ROCKET_SPEED>>2)
				item->speed = ROCKET_SPEED>>2;
		}

		item->pos.z_rot+=(((item->speed>>3)+3)*ONE_DEGREE);
		abovewater = 0;
	}
	else
	{
		if (item->speed < ROCKET_SPEED)
			item->speed += (item->speed>>2)+4;
		item->pos.z_rot+=(((item->speed>>2)+7)*ONE_DEGREE);
	 	abovewater = 1;
	}

	item->shade = 0x4210|0x8000;

	phd_PushUnitMatrix();
#ifdef PSX_VERSION
	mSetTrans(0, 0, 0);
#else
	*(phd_mxptr+M03) = 0;
	*(phd_mxptr+M13) = 0;
	*(phd_mxptr+M23) = 0;
#endif
	phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);
	phd_PushMatrix();
	phd_TranslateRel( 0, 0, -128);
#ifdef PSX_VERSION
	wx = Matrix->tx;
	wy = Matrix->ty;
	wz = Matrix->tz;
#else
	wx = (*(phd_mxptr+M03)>>W2V_SHIFT);
	wy = (*(phd_mxptr+M13)>>W2V_SHIFT);
	wz = (*(phd_mxptr+M23)>>W2V_SHIFT);
#endif
	phd_PopMatrix();
	phd_TranslateRel( 0, 0, -1536-(GetRandomControl()&511));
#ifdef PSX_VERSION
	xv = Matrix->tx;
	yv = Matrix->ty;
	zv = Matrix->tz;
#else
	xv = (*(phd_mxptr+M03)>>W2V_SHIFT);
	yv = (*(phd_mxptr+M13)>>W2V_SHIFT);
	zv = (*(phd_mxptr+M23)>>W2V_SHIFT);
#endif
	phd_PopMatrix();
	if (wibble & 4)
		TriggerRocketFlame(wx,wy,wz,xv-wx,yv-wy,zv-wz,item_number);
	TriggerRocketSmoke(wx+item->pos.x_pos, wy+item->pos.y_pos, wz+item->pos.z_pos, -1);
	if (room[item->room_number].flags & UNDERWATER)
	{
		PHD_3DPOS pos;

		pos.x_pos = wx+item->pos.x_pos;
		pos.y_pos = wy+item->pos.y_pos;
		pos.z_pos = wz+item->pos.z_pos;
		CreateBubble(&pos,item->room_number,4,8);
	}
	TriggerDynamic(wx+item->pos.x_pos+(GetRandomControl()&15)-8, wy+item->pos.y_pos+(GetRandomControl()&15)-8, wz+item->pos.z_pos+(GetRandomControl()&15)-8,14,28+(GetRandomControl()&3),16+(GetRandomControl()&7),(GetRandomControl()&7));

	speed = (item->speed * phd_cos(item->pos.x_rot)) >> W2V_SHIFT;
	item->pos.z_pos += (speed * phd_cos(item->pos.y_rot)) >> W2V_SHIFT;
	item->pos.x_pos += (speed * phd_sin(item->pos.y_rot)) >> W2V_SHIFT;
	item->pos.y_pos += -((item->speed * phd_sin(item->pos.x_rot)) >> W2V_SHIFT);

	room_number = item->room_number;
	floor = GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
	item->floor = GetHeight(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);

	if (item->room_number != room_number)
		ItemNewRoom(item_number, room_number);

	/* Has it hit a wall or the floor? If so, explodes with blast radius */
	if (item->pos.y_pos >= item->floor || item->pos.y_pos <= GetCeiling(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos))
	{
		radius = ROCKET_BLAST_RADIUS<<item->item_flags[0];	// << for biggun rockets.
		explode = 1;
	}
	else
		radius = explode = 0; // no radius, so must hit bad guy

	if (room[item->room_number].flags & UNDERWATER && abovewater)	// Just broken water surface ?
	{
		splash_setup.x = item->pos.x_pos;

#ifdef PC_VERSION
		splash_setup.y = room[item->room_number].maxceiling;
#else
		splash_setup.y = room[item->room_number].y;
#endif

		splash_setup.z = item->pos.z_pos;
		splash_setup.InnerXZoff = 16;
		splash_setup.InnerXZsize = 12;
		splash_setup.InnerYsize = -96;
		splash_setup.InnerXZvel = 0xa0;
		splash_setup.InnerYvel = -(128<<7);
		splash_setup.InnerGravity = 0x80;
		splash_setup.InnerFriction = 7;
		splash_setup.MiddleXZoff = 24;
		splash_setup.MiddleXZsize = 24;
		splash_setup.MiddleYsize = -64;
		splash_setup.MiddleXZvel = 0xe0;
		splash_setup.MiddleYvel = -(128<<6);
		splash_setup.MiddleGravity = 0x48;
		splash_setup.MiddleFriction = 8;
		splash_setup.OuterXZoff = 32;
		splash_setup.OuterXZsize = 32;
		splash_setup.OuterXZvel = 0x110;
		splash_setup.OuterFriction = 9;
		SetupSplash(&splash_setup);
	}

	// Has it hit a beastie?

	GetNearByRooms(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,radius<<2,radius<<2,item->room_number);

	for (lp=0;lp<number_draw_rooms;lp++)
	{
		for (target_number = room[draw_rooms[lp]].item_number; target_number!=NO_ITEM; target_number=target->next_item)
		{
			target = &items[target_number];
			if (target == lara_item || !target->collidable)
				continue;

			if (target->object_number==SMASH_WINDOW ||
				target->object_number==SMASH_OBJECT1 ||
				target->object_number==SMASH_OBJECT2 ||
				target->object_number==SMASH_OBJECT3 ||
				target->object_number==CARCASS ||
				target->object_number==EXTRAFX6 ||
				target->object_number==FLYING_MUTANT_EMITTER ||
				(objects[target->object_number].intelligent && target->status != INVISIBLE && objects[target->object_number].collision))
			{
				// check against bounds of target for collision
				bounds = GetBestFrame(target);
				if (item->pos.y_pos+radius < target->pos.y_pos + bounds[2] || item->pos.y_pos-radius > target->pos.y_pos + bounds[3])
					continue;

				// get vector from target to bolt and check against x,z bounds
				c = phd_cos(target->pos.y_rot);
				s = phd_sin(target->pos.y_rot);

				x = item->pos.x_pos - target->pos.x_pos;
				z = item->pos.z_pos - target->pos.z_pos;
				rx = (c*x - s*z) >> W2V_SHIFT;

				ox = old_x - target->pos.x_pos;
				oz = old_z - target->pos.z_pos;
				sx = (c*ox - s*oz) >> W2V_SHIFT;

				if ((rx+radius < bounds[0] && sx+radius < bounds[0]) ||
				 	(rx-radius > bounds[1] && sx-radius > bounds[1]))
					continue;

				rz = (c*z + s*x) >> W2V_SHIFT;
				sz = (c*oz + s*ox) >> W2V_SHIFT;

				if ((rz+radius < bounds[4] && sz+radius < bounds[4]) ||
				 	(rz-radius > bounds[5] && sz-radius > bounds[5]))
					continue;

				if ( target->object_number==SMASH_OBJECT1 && CurrentLevel == LV_CRASH)
				{
				 	if(item->item_flags[0] == 1)
						SmashWindow(target_number);
					if (explode == 0)
					{
						explode = 1;
						radius = ROCKET_BLAST_RADIUS<<item->item_flags[0];
						lp=-1;
						break;
					}
				}
				else if (target->object_number==SMASH_OBJECT1 && CurrentLevel != LV_CRASH)
				{
					SmashWindow(target_number);
				}
				else if (target->object_number==SMASH_WINDOW ||
					target->object_number==SMASH_OBJECT2 ||
					target->object_number==SMASH_OBJECT3)
				{
					SmashWindow(target_number);
				}
				else if (target->object_number==CARCASS || target->object_number==EXTRAFX6)
				{
					if (item->status != ACTIVE)
					{
						item->status = ACTIVE;
						AddActiveItem(target_number);
					}
				}
				else if (target->object_number!=SMASH_OBJECT1)
				{
					// Kaboom! take that evil bad guy
					if (target->object_number != TRIBEBOSS || !TribeBossShieldOn)	//## TRIBEBOSS!!
						HitTarget(target, NULL, (30*PISTOL_DAMAGE)<<item->item_flags[0]);
					else
						FindClosestShieldPoint(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, target);

					savegame.ammo_hit++;

					// if dead, then blast them to bits
					if (target->hit_points <= 0)
					{
						savegame.kills++;
						if (target->object_number != TRIBEBOSS && target->object_number != WILLARD_BOSS &&
							target->object_number != TONY && target->object_number != LON_BOSS && target->object_number != ELECTRIC_CLEANER
							&& target->object_number!=WHALE && target->object_number!=FLYING_MUTANT_EMITTER)	// Can't explode bosses.
						{
							if (target->object_number == LIZARD_MAN && lizard_man_active)
								lizard_man_active = 0;
							CreatureDie(target_number, 1);
						}
					}

					if (explode == 0)
					{
						explode = 1;
						radius = ROCKET_BLAST_RADIUS<<item->item_flags[0];
						lp=-1;
						break;
					}
				}
			}
		}
	}

	if (explode)
	{
		if (room[oldroom].flags & UNDERWATER)
		{
			item->pos.x_pos = old_x;
			item->pos.y_pos = old_y;
			item->pos.z_pos = old_z;
			ItemNewRoom(item_number, oldroom);
			TriggerUnderwaterExplosion(item);
		}
		else
		{
			TriggerExplosionSparks(old_x, old_y, old_z,3,-2,0,item->room_number);	// -2 = Set off a dynamic light controller.
			for (x=0;x<2;x++)
				TriggerExplosionSparks(old_x, old_y, old_z,3,-1,0, item->room_number);
		}

	/* -------- determine how far Lara is away from the explosion */

#ifdef PSX_VERSION
		{
			long dist, x, y, z;

			x = old_x - lara_item->pos.x_pos;
			y = old_y - lara_item->pos.y_pos;
			z = old_z - lara_item->pos.z_pos;
			dist = SQUARE(x) + SQUARE(y) + SQUARE(z);

			if (dist < 0x1900000)
			{
				dist = 0xff00 - ((dist>>9) & 0xff00);
				RUMBLE(dist>>4, dist, 20, 0x100, 40);
			}
		}
#endif
		AlertNearbyGuards(item);
		SoundEffect(105, &item->pos, PITCH_SHIFT|0x1800000);
		SoundEffect(106, &item->pos, 0);	// Explosion ?
		KillItem(item_number);
	}
}


void FireGrenade(void)
{
	sint16 item_number,lp;
	ITEM_INFO *item;
	PHD_VECTOR pos;
	FLOOR_INFO	*floor;
	long	x,y,z;

	if (lara.grenade.ammo <= 0)
		return;

	lara.has_fired = 1;

	/* Create a grenade object and launch it on its way */
	item_number = CreateItem();
	if (item_number != NO_ITEM)
	{
		item = &items[item_number];

		item->shade = 0x4210|0x8000;

		item->object_number = GRENADE;
		item->room_number = lara_item->room_number;
		pos.x = 0;
		pos.y = GRENADE_YOFF+96;
		pos.z = GRENADE_ZOFF;
		GetLaraHandAbsPosition(&pos, 1);
		item->pos.x_pos = x = pos.x;
		item->pos.y_pos = y = pos.y;
		item->pos.z_pos = z = pos.z;
		floor = GetFloor(pos.x, pos.y, pos.z, &item->room_number);
		if (GetHeight(floor, pos.x, pos.y, pos.z) < pos.y)
		{
			item->pos.x_pos = lara_item->pos.x_pos;
			item->pos.y_pos = pos.y;
			item->pos.z_pos = lara_item->pos.z_pos;
			item->room_number = lara_item->room_number;
		}

		pos.x = 0;
		pos.y = GRENADE_YOFF+1024;
		pos.z = GRENADE_ZOFF;
		GetLaraHandAbsPosition(&pos, 1);

		SmokeCountL = 32;
		SmokeWeapon = LG_GRENADE;
		for (lp=0;lp<5;lp++)
			TriggerGunSmoke(x, y, z, pos.x-x, pos.y-y, pos.z-z, 1, LG_GRENADE, 32);

		InitialiseItem(item_number);

		item->pos.x_rot = lara_item->pos.x_rot + lara.left_arm.x_rot;
		item->pos.y_rot = lara_item->pos.y_rot + lara.left_arm.y_rot;
		item->pos.z_rot = 0;

		if (!lara.left_arm.lock)
		{
			item->pos.x_rot += lara.torso_x_rot;
	 		item->pos.y_rot += lara.torso_y_rot;
		}

		item->speed = GRENADE_SPEED;
		item->fallspeed = (-item->speed * phd_sin(item->pos.x_rot)) >> W2V_SHIFT;
		item->current_anim_state = item->pos.x_rot;	// Current anim state is X rotation so the object can rotate in X axis
											// without affecting velocites.
		item->goal_anim_state = item->pos.y_rot;	// Goal anim state is Y rotation so the object can rotate in Y axis blah blah
		item->required_anim_state = 0;	// Flag to say if rolling on floor.
		item->hit_points = 4*30;	// Explode after 3 seconds.

		AddActiveItem(item_number);

#if !defined(GAMEDEBUG) && !defined(EZORAY)
		if (!savegame.bonus_flag)
			lara.grenade.ammo--;
#endif
		savegame.ammo_used++;

#if defined(PC_VERSION) && defined(GAMEDEBUG)
		level.ammo_used += 30;
#endif
	}
}

#define GRENADE_BLAST_RADIUS (WALL_L)

void ControlGrenade(sint16 item_number)
{
	sint16 *bounds;
	long	wx,wy,wz,xv,yv,zv,lp;
	ITEM_INFO *item, *target;
	sint32 old_x, old_y, old_z;
	sint16 target_number;
	sint32 c, s, x, z, rx, rz, ox, oz, sx, sz, explode, radius, abovewater;
	long	syrot;

	item = &items[item_number];

	old_x = item->pos.x_pos;
	old_y = item->pos.y_pos;
	old_z = item->pos.z_pos;

	item->shade = 0x4210|0x8000;
	// Fall more slowly in water.

	if (room[item->room_number].flags & UNDERWATER)
	{
		abovewater = 0;
		item->fallspeed += (5 - item->fallspeed)>>1;
		item->speed -= item->speed>>2;
		if (item->speed)
		{
			item->pos.z_rot+=(((item->speed>>4)+3)*ONE_DEGREE);
			if (item->required_anim_state)
				item->pos.y_rot+=(((item->speed>>2)+3)*ONE_DEGREE);
			else
				item->pos.x_rot+=(((item->speed>>2)+3)*ONE_DEGREE);
		}
	}
	else
	{
		abovewater = 1;
		item->fallspeed += GRAVITY>>1;
		if (item->speed)
		{
			item->pos.z_rot+=(((item->speed>>2)+7)*ONE_DEGREE);
			if (item->required_anim_state)
				item->pos.y_rot+=(((item->speed>>1)+7)*ONE_DEGREE);
			else
				item->pos.x_rot+=(((item->speed>>1)+7)*ONE_DEGREE);

		}
	}

	phd_PushUnitMatrix();
#ifdef PSX_VERSION
	mSetTrans(0, 0, 0);
#else
	*(phd_mxptr+M03) = 0;
	*(phd_mxptr+M13) = 0;
	*(phd_mxptr+M23) = 0;
#endif
	phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);
	phd_TranslateRel( 0, 0, -64);
#ifdef PSX_VERSION
	wx = Matrix->tx;
	wy = Matrix->ty;
	wz = Matrix->tz;
#else
	wx = (*(phd_mxptr+M03)>>W2V_SHIFT);
	wy = (*(phd_mxptr+M13)>>W2V_SHIFT);
	wz = (*(phd_mxptr+M23)>>W2V_SHIFT);
#endif
	phd_PopMatrix();

	if (item->speed && abovewater)
   		TriggerRocketSmoke(wx+item->pos.x_pos, wy+item->pos.y_pos, wz+item->pos.z_pos, -1);

	item->pos.z_pos += (zv = ((item->speed * phd_cos(item->goal_anim_state)) >> W2V_SHIFT));
	item->pos.x_pos += (xv = ((item->speed * phd_sin(item->goal_anim_state)) >> W2V_SHIFT));
	item->pos.y_pos += (yv = item->fallspeed);

	syrot = item->pos.y_rot;
	item->pos.y_rot = item->goal_anim_state;
	DoProperDetection(item_number, old_x, old_y, old_z, xv, yv, zv);
	item->goal_anim_state = item->pos.y_rot;
	item->pos.y_rot = syrot;

	if (room[item->room_number].flags & UNDERWATER && abovewater)	// Just broken water surface ?
	{
		splash_setup.x = item->pos.x_pos;

#ifdef PC_VERSION
		splash_setup.y = room[item->room_number].maxceiling;
#else
		splash_setup.y = room[item->room_number].y;
#endif

		splash_setup.z = item->pos.z_pos;
		splash_setup.InnerXZoff = 16;
		splash_setup.InnerXZsize = 12;
		splash_setup.InnerYsize = -96;
		splash_setup.InnerXZvel = 0xa0;
		splash_setup.InnerYvel = -(item->fallspeed<<5) - (64<<5);
		splash_setup.InnerGravity = 0x80;
		splash_setup.InnerFriction = 7;
		splash_setup.MiddleXZoff = 24;
		splash_setup.MiddleXZsize = 24;
		splash_setup.MiddleYsize = -64;
		splash_setup.MiddleXZvel = 0xe0;
		splash_setup.MiddleYvel = -(item->fallspeed<<4) - (64<<4);
		splash_setup.MiddleGravity = 0x48;
		splash_setup.MiddleFriction = 8;
		splash_setup.OuterXZoff = 32;
		splash_setup.OuterXZsize = 32;
		splash_setup.OuterXZvel = 0x110;
		splash_setup.OuterFriction = 9;
		SetupSplash(&splash_setup);
	}

	// Has the timer ran out ? If so, explodes with blast radius.

	radius = explode = 0; // no radius, so must hit bad guy
	if (item->hit_points)
	{
		item->hit_points--;
		if (!item->hit_points)
		{
			radius = GRENADE_BLAST_RADIUS;
			explode = 1;
		}
	}

	// Has it hit a beastie? Check ones in surrounding rooms.

	GetNearByRooms(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,radius<<2,radius<<2,item->room_number);

	for (lp=0;lp<number_draw_rooms;lp++)
	{
		for (target_number = room[draw_rooms[lp]].item_number; target_number!=NO_ITEM; target_number=target->next_item)
		{
			target = &items[target_number];
			if (target == lara_item || !target->collidable)
				continue;

			if (	target->object_number==SMASH_WINDOW ||
				target->object_number==SMASH_OBJECT1 ||
				target->object_number==SMASH_OBJECT2 ||
				target->object_number==SMASH_OBJECT3 ||
				target->object_number==CARCASS ||
				target->object_number==EXTRAFX6 ||
				target->object_number==FLYING_MUTANT_EMITTER ||
				(objects[target->object_number].intelligent && target->status != INVISIBLE && objects[target->object_number].collision))
			{
				// check against bounds of target for collision
				bounds = GetBestFrame(target);
				if (item->pos.y_pos+radius < target->pos.y_pos + bounds[2] || item->pos.y_pos-radius > target->pos.y_pos + bounds[3])
					continue;

				// get vector from target to bolt and check against x,z bounds
				c = phd_cos(target->pos.y_rot);
				s = phd_sin(target->pos.y_rot);

				x = item->pos.x_pos - target->pos.x_pos;
				z = item->pos.z_pos - target->pos.z_pos;
				rx = (c*x - s*z) >> W2V_SHIFT;

				ox = old_x - target->pos.x_pos;
				oz = old_z - target->pos.z_pos;
				sx = (c*ox - s*oz) >> W2V_SHIFT;

				if ((rx+radius < bounds[0] && sx+radius < bounds[0]) ||
				 	(rx-radius > bounds[1] && sx-radius > bounds[1]))
					continue;

				rz = (c*z + s*x) >> W2V_SHIFT;
				sz = (c*oz + s*ox) >> W2V_SHIFT;

				if ((rz+radius < bounds[4] && sz+radius < bounds[4]) ||
				 	(rz-radius > bounds[5] && sz-radius > bounds[5]))
					continue;

				if (target->object_number==SMASH_OBJECT1 && CurrentLevel != LV_CRASH)
				{
					SmashWindow(target_number);
				}
				else if (	target->object_number==SMASH_WINDOW ||
					target->object_number==SMASH_OBJECT2 ||
					target->object_number==SMASH_OBJECT3)
				{
					SmashWindow(target_number);
				}
				else if (target->object_number==CARCASS || target->object_number==EXTRAFX6)
				{
					if (item->status != ACTIVE)
					{
						item->status = ACTIVE;
						AddActiveItem(target_number);
					}
				}
				else if (target->object_number!=SMASH_OBJECT1)
				{
					// Kaboom! take that evil bad guy
					if (target->object_number != TRIBEBOSS || !TribeBossShieldOn)	//## TRIBEBOSS!!
						HitTarget(target, NULL, 20*PISTOL_DAMAGE);
					else
						FindClosestShieldPoint(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, target);

					savegame.ammo_hit++;

					// if dead, then blast them to bits
					if (target->hit_points <= 0)
					{
						savegame.kills++;
						if (target->object_number != TRIBEBOSS && target->object_number!=WHALE && target->object_number != WILLARD_BOSS && target->object_number != TONY && target->object_number != LON_BOSS && target->object_number != ELECTRIC_CLEANER &&  target->object_number != FLYING_MUTANT_EMITTER)
						{
							if (target->object_number == LIZARD_MAN && lizard_man_active)
								lizard_man_active = 0;
							CreatureDie(target_number, 1);
						}
					}

					if (explode == 0)
					{
						explode = 1;
						radius = GRENADE_BLAST_RADIUS;
						lp=-1;
						break;
					}
				}
			}
		}
	}

	if (explode)
	{
		if (room[item->room_number].flags & UNDERWATER)	// Just broken water surface ?
			TriggerUnderwaterExplosion(item);
		else
		{
			TriggerExplosionSparks(old_x, old_y, old_z,3,-2,0,item->room_number);	// -2 = Set off a dynamic light controller.
			for (x=0;x<2;x++)
				TriggerExplosionSparks(old_x, old_y, old_z,3,-1,0,item->room_number);
		}

	/* -------- determine how far Lara is away from the explosion */

#ifdef PSX_VERSION
		{
			long dist, x, y, z;

			x = old_x - lara_item->pos.x_pos;
			y = old_y - lara_item->pos.y_pos;
			z = old_z - lara_item->pos.z_pos;
			dist = SQUARE(x) + SQUARE(y) + SQUARE(z);

			if (dist < 0x1900000)
			{
				dist = 0xff00 - ((dist>>9) & 0xff00);
				RUMBLE(dist>>4, dist, 20, 0x100, 40);
			}
		}
#endif
		AlertNearbyGuards(item);
		SoundEffect(105, &item->pos, PITCH_SHIFT|0x1800000);
		SoundEffect(106, &item->pos, 0);	// Explosion ?
		KillItem(item_number);
	}
}


void draw_shotgun(int weapon_type)
{
	ITEM_INFO *item;

	if (lara.weapon_item == NO_ITEM)
	{
		lara.weapon_item = CreateItem();
		item = &items[lara.weapon_item];
		item->object_number = WeaponObject(weapon_type);

		if (weapon_type == LG_ROCKET)
			item->anim_number = objects[ROCKET_GUN].anim_index + 1;

		else if (weapon_type == LG_GRENADE)
			item->anim_number = objects[GRENADE_GUN].anim_index + ROCKET_DRAW_ANIM;
		else
			item->anim_number = objects[item->object_number].anim_index + HARPOON_DRAW_ANIM; // M16 too

		item->frame_number = anims[item->anim_number].frame_base;
		item->current_anim_state = item->goal_anim_state = W_DRAW;
		item->status = ACTIVE;
		item->room_number = NO_ROOM; // needed to stop KillItem() throwing a wobbly
		lara.left_arm.frame_base = lara.right_arm.frame_base = objects[item->object_number].frame_base;
	}
	else
		item = &items[lara.weapon_item];

	AnimateItem(item);

	if (item->current_anim_state == W_AIM || item->current_anim_state == W_UAIM)
		ready_shotgun(weapon_type);

	else if ((item->frame_number - anims[item->anim_number].frame_base) == weapons[weapon_type].draw_frame)
		draw_shotgun_meshes(weapon_type);

	else if (lara.water_status == LARA_UNDERWATER)
		item->goal_anim_state = W_UAIM;

	lara.left_arm.frame_base = lara.right_arm.frame_base = anims[item->anim_number].frame_ptr;
	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.anim_number = lara.right_arm.anim_number = item->anim_number;
}


void undraw_shotgun(int weapon_type)
{
	ITEM_INFO *item;

	item = &items[lara.weapon_item];
	if (lara.water_status == LARA_SURFACE)
		item->goal_anim_state = W_SURF_UNDRAW;
	else
		item->goal_anim_state = W_UNDRAW;

	AnimateItem(item);

	if (item->status == DEACTIVATED)
	{
		lara.gun_status = LG_ARMLESS;
		lara.target = NULL;
		lara.left_arm.lock = lara.right_arm.lock = 0;
		KillItem(lara.weapon_item);
		lara.weapon_item = NO_ITEM;
		lara.left_arm.frame_number = lara.right_arm.frame_number = 0;
	}
	else if (item->current_anim_state == W_UNDRAW && item->frame_number - anims[item->anim_number].frame_base == 21)
		undraw_shotgun_meshes(weapon_type);

//	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number;

	lara.left_arm.frame_base = lara.right_arm.frame_base = anims[item->anim_number].frame_ptr;
	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.anim_number = lara.right_arm.anim_number = item->anim_number;
}


void AnimateShotgun(int weapon_type)
{
	/* Do readied state of harpoon. Needs to switch between underwater and above water aiming when
		Lara passes in and out of water with the harpoon out */
	ITEM_INFO *item;
	int running;
	static int m16_firing = 0, harpoon_fired = 0;

	if (SmokeCountL)
	{
  		PHD_VECTOR pos;

		if (SmokeWeapon == LG_ROCKET)
		{
			pos.x = 0;
			pos.y = ROCKET_YOFF-96;
			pos.z = ROCKET_ZOFF;
		}
		else if (SmokeWeapon == LG_GRENADE)
		{
			pos.x = 0;
			pos.y = GRENADE_YOFF;
			pos.z = GRENADE_ZOFF;
		}
		else if (SmokeWeapon == LG_SHOTGUN)
		{
			pos.x = -16;
			pos.y = SHOTGUN_YOFF;
			pos.z = SHOTGUN_ZOFF;
		}
		else if (SmokeWeapon == LG_M16)
		{
			pos.x = 0;
			pos.y = M16_YOFF;
			pos.z = M16_ZOFF;
		}
		GetLaraHandAbsPosition(&pos, 1);
		TriggerGunSmoke(pos.x, pos.y, pos.z, 0,0,0,0,SmokeWeapon, SmokeCountL);
	}

	item = &items[lara.weapon_item];

	if (weapon_type == LG_M16 && lara_item->speed != 0)
		running = 1;
	else
		running = 0;

	switch (item->current_anim_state)
	{
	case W_AIM:
		m16_firing = 0; // for M16 sounds

		if (harpoon_fired)
		{
			item->goal_anim_state = W_RELOAD;
			harpoon_fired = 0;
		}
		else if (lara.water_status == LARA_UNDERWATER || running)		// switch to underwater aim if Lara falls in
			item->goal_anim_state = W_UAIM;
		else if (((input & IN_ACTION) && !lara.target) || lara.left_arm.lock)
			item->goal_anim_state = W_RECOIL;
		else // loops on first frame if user not pressing fire and no lock
			item->goal_anim_state = W_UNAIM;
		break;

	case W_UAIM:
		m16_firing = 0;

		if (harpoon_fired)
		{
			item->goal_anim_state = W_RELOAD;
			harpoon_fired = 0;
		}
		else if (lara.water_status != LARA_UNDERWATER && !running)
			item->goal_anim_state = W_AIM;
		else if (((input & IN_ACTION) && !lara.target) || lara.left_arm.lock)
			item->goal_anim_state = W_URECOIL;
		else
			item->goal_anim_state = W_UUNAIM;
		break;

	case W_RECOIL:
		/* Fire on second frame */
		//if (item->frame_number - anims[item->anim_number].frame_base == 0)
		if (item->frame_number == anims[item->anim_number].frame_base)
		{
			item->goal_anim_state = W_UNAIM;

			if (lara.water_status != LARA_UNDERWATER && !running && !harpoon_fired)
			{
				if ((input & IN_ACTION) && (!lara.target || lara.left_arm.lock))
				{
					if (weapon_type == LG_HARPOON)
					{
						FireHarpoon();
						if (!(lara.harpoon.ammo&3)) // reload every 4 bolts
							harpoon_fired = 1;
					}
					else if (weapon_type == LG_ROCKET)
					{
						FireRocket();
					}
					else if (weapon_type == LG_GRENADE)
					{
						FireGrenade();
					}
					else if (weapon_type == LG_M16)
					{
						FireM16(0);
						SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x5000000);
						SoundEffect(78, &lara_item->pos, 0);
						m16_firing = 1;
					}
					else
						FireShotgun();

					item->goal_anim_state = W_RECOIL;
				}
				else if (lara.left_arm.lock)
					item->goal_anim_state = W_AIM; // loop on first frame
			}

			if (item->goal_anim_state != W_RECOIL && m16_firing)
			{
				SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x5000000);
				m16_firing = 0;
			}
		}
		else if (m16_firing)
		{
			SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x5000000);
			SoundEffect(78, &lara_item->pos, 0);
		}
		else if (weapon_type == LG_SHOTGUN && !(input & IN_ACTION) && !lara.left_arm.lock)
			item->goal_anim_state = W_UNAIM;

		if ((item->frame_number - anims[item->anim_number].frame_base) == 12 && weapon_type == LG_SHOTGUN)
			TriggerGunShell(RIGHT_HAND,SHOTGUNSHELL,LG_SHOTGUN);
		break;

	case W_URECOIL:
		/* Underwater for harpoon; running for M16 */
		if (item->frame_number - anims[item->anim_number].frame_base == 0)
		{
			item->goal_anim_state = W_UUNAIM;
			if ((lara.water_status == LARA_UNDERWATER || running) && !harpoon_fired)
			{
				if ((input & IN_ACTION) && (!lara.target || lara.left_arm.lock))
				{
					if (weapon_type == LG_HARPOON)
					{
						FireHarpoon();
						if (!(lara.harpoon.ammo&3))
							harpoon_fired = 1;
					}
					else
						FireM16(1);
					item->goal_anim_state = W_URECOIL;
				}
				else if (lara.left_arm.lock)
					item->goal_anim_state = W_UAIM; // loop on first frame
			}
		}
		if (weapon_type == LG_M16 && item->goal_anim_state == W_URECOIL)
		{
			SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x4000000);
			SoundEffect(78, &lara_item->pos, 0);
		}
		break;
	}
	AnimateItem(item);

//	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number;


	lara.left_arm.frame_base = lara.right_arm.frame_base = anims[item->anim_number].frame_ptr;
	lara.left_arm.frame_number = lara.right_arm.frame_number = item->frame_number - anims[item->anim_number].frame_base;
	lara.left_arm.anim_number = lara.right_arm.anim_number = item->anim_number;
}

void TriggerUnderwaterExplosion(ITEM_INFO *item)
{
	long	wh,hfw,lp;

	TriggerExplosionBubble(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,item->room_number);
	TriggerExplosionSparks(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos,2,-2,1,item->room_number);	// -2 = Set off a dynamic light controller.
	for (lp=0;lp<3;lp++)
		TriggerExplosionSparks(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos,2,-1,1,item->room_number);

	wh = GetWaterHeight( item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, item->room_number );
	if ( wh != NO_HEIGHT )
	{
		hfw = item->pos.y_pos - wh;
		if (hfw < 2048)
		{
			hfw = 2048-hfw;
			splash_setup.x = item->pos.x_pos;

#ifdef PC_VERSION
			splash_setup.y = room[item->room_number].maxceiling;
#else
			splash_setup.y = room[item->room_number].y;
#endif

			splash_setup.z = item->pos.z_pos;
			splash_setup.InnerXZoff = 16+(hfw>>6);
			splash_setup.InnerXZsize = 12+(hfw>>6);
			splash_setup.InnerYsize = -96;
			splash_setup.InnerXZvel = 0xa0;
			splash_setup.InnerYvel = (-hfw<<3)-4096;
			splash_setup.InnerGravity = 0x60;
			splash_setup.InnerFriction = 7;
			splash_setup.MiddleXZoff = 24+(hfw>>6);
			splash_setup.MiddleXZsize = 24+(hfw>>6);
			splash_setup.MiddleYsize = -64;
			splash_setup.MiddleXZvel = 0xe0;
			splash_setup.MiddleYvel = (-hfw<<2) - 3072;
			splash_setup.MiddleGravity = 0x38;
			splash_setup.MiddleFriction = 8;
			splash_setup.OuterXZoff = 32+(hfw>>6);
			splash_setup.OuterXZsize = 32+(hfw>>6);
			splash_setup.OuterXZvel = 0x110;
			splash_setup.OuterFriction = 9;
			SetupSplash(&splash_setup);
		}
	}
}


