/***********************************************************************************************************/
/*                                                                                                         */
/* Pistol Controllers                                                                                      */
/*                                                                                                         */
/***********************************************************************************************************/

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

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

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "input.h"
#include "sound.h"
#include "effect2.h"
#include "lara2gun.h"
#include "control.h"
#include "camera.h"

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

#define AIMGUNS_F	0				    	// 0-4     Pistol animation frames
#define DRAW1_F	5                       // 5-12
#define DRAW2_F	13                      // 13-23
#define RECOIL_F	24                      // 24-32

/*---------------------------------------------------------------------------
 * Locals
\*--------------------------------------------------------------------------*/

typedef struct {
	sint16 ObjectNum;
	char Draw1Anim2;
	char Draw1Anim;
	char Draw2Anim;
	char RecoilAnim;
}PISTOL_DEF;

static PISTOL_DEF PistolTable[4] = {
	{        0,  0,  0,  0,  0 },		// LG_UNARMED
	{  PISTOLS,  4,  5, 13, 24 },		// LG_PISTOLS
	{   MAGNUM,  7,  8, 15, 29 },		// LG_MAGNUMS
	{      UZI,  4,  5, 13, 24 }		// LG_UZIS
};

/*---------------------------------------------------------------------------
 * Local Functions
\*--------------------------------------------------------------------------*/
/*
 * 23/9/97: due to superpacking of anim frames, Lara's arms need more info to
 * retrieve correct frame
 */
static void set_arm_info(LARA_ARM *arm, int frame)
{
	int anim_base;
	PISTOL_DEF *p;

	p = &PistolTable[lara.gun_type];

	anim_base = objects[p->ObjectNum].anim_index;

	if (frame < p->Draw1Anim)
		arm->anim_number = anim_base;

	else if (frame < p->Draw2Anim)
		arm->anim_number = anim_base+1;

	else if (frame < p->RecoilAnim)
		arm->anim_number = anim_base+2;

	else
		arm->anim_number = anim_base+3;

	arm->frame_base = anims[arm->anim_number].frame_ptr;
	arm->frame_number = frame;
}

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

/*******************************************************************************
 *					Draw default pistols from holsters...
 ******************************************************************************/
void	draw_pistols( int weapon_type )
{
	sint16 ani;
	PISTOL_DEF *p;

	p = &PistolTable[lara.gun_type];

	ani = lara.left_arm.frame_number + 1;

	if ((ani < p->Draw1Anim) || (ani > p->RecoilAnim-1))
		ani = p->Draw1Anim;

	else if (ani == p->Draw2Anim)
	{
		draw_pistol_meshes(weapon_type);		// Put Guns In Hands..
		SoundEffect(6, &lara_item->pos, 0);	// Play DRAW sound
	}
	else if (ani == p->RecoilAnim-1)
	{
		ready_pistols(weapon_type);			// Pistols now ready to fire..
		ani = 0;
	}

	set_arm_info(&lara.right_arm, ani);
	set_arm_info(&lara.left_arm, ani);
}

/******************************************************************************
 *					Put pistols back in holsters...
 *****************************************************************************/
void	undraw_pistols( int weapon_type )
{
	PISTOL_DEF *p;
	sint16 anil,anir;

	p = &PistolTable[lara.gun_type];

// First We Do Left Arm
	anil = lara.left_arm.frame_number;

	if ( anil >= p->RecoilAnim)	// If Gun Is Recoiling we snap it
		anil = p->Draw1Anim2;

	else if ((anil > 0) && (anil < p->Draw1Anim)) 						// If Gun is Being Aimed at something..
	{
		lara.left_arm.x_rot -= lara.left_arm.x_rot/anil;    // turn arms towards forward position
		lara.left_arm.y_rot -= lara.left_arm.y_rot/anil;
		anil--;
	}

// Guns Are Unaimed so start Undraw animation
	else if (anil == 0)
	{
		lara.left_arm.x_rot = lara.left_arm.y_rot = lara.left_arm.z_rot = 0;		// Ensure no targets pointed at..
		anil = p->RecoilAnim - 1;
	}

	else if ((anil > p->Draw1Anim) && (anil < p->RecoilAnim))
	{
		anil--;

		if (anil == p->Draw2Anim - 1)
		{
			undraw_pistol_mesh_left( weapon_type );         // Put Gun back On Thigh
			SoundEffect( 7,&lara_item->pos,0 );        // Play HOLSTER Sample
		}
	}
	set_arm_info(&lara.left_arm, anil);

// Now We Do Right Arm stuff
	anir = lara.right_arm.frame_number;

	if (anir >= p->RecoilAnim)	// If Gun Is Recoiling we snap it
		anir = p->Draw1Anim2;

	else if ((anir> 0) && (anir < p->Draw1Anim)) 						// If Gun is Being Aimed at something..
	{
		lara.right_arm.x_rot -= lara.right_arm.x_rot/anir;  // turn arms towards forward position
		lara.right_arm.y_rot -= lara.right_arm.y_rot/anir;
		anir--;
	}

// Guns Are Unaimed so start Undraw animation
	else if (anir == 0)
	{
		lara.right_arm.x_rot = lara.right_arm.y_rot = lara.right_arm.z_rot = 0;		// Ensure no targets pointed at..
		anir = p->RecoilAnim - 1;
	}

	else if ((anir > p->Draw1Anim) && (anir < p->RecoilAnim))
	{
		anir--;

		if (anir == p->Draw2Anim - 1)
		{
			undraw_pistol_mesh_right(weapon_type);	// Put Gun back on thigh
			SoundEffect(7, &lara_item->pos, 0);	// Play HOLSTER Sample
		}
	}

	set_arm_info(&lara.right_arm, anir);

	if ((anil == p->Draw1Anim) && (anir == p->Draw1Anim))
	{
		lara.gun_status = LG_ARMLESS;
		lara.right_arm.frame_number = lara.left_arm.frame_number = 0;
		lara.target = NULL;
		lara.left_arm.lock = lara.right_arm.lock = 0;
	}

	if (!(input & IN_LOOK))
	{
		lara.torso_y_rot = lara.head_y_rot = (lara.left_arm.y_rot + lara.right_arm.y_rot)/4;	// Turn head to point at targets
		lara.torso_x_rot = lara.head_x_rot = (lara.left_arm.x_rot + lara.right_arm.x_rot)/4;    // If any exist
	}
}


/*****************************************************************************
 *					Ready the pistols for Use...
 ****************************************************************************/
void	ready_pistols( int weapon_type )
{
	lara.gun_status = LG_READY;				// pistols ready to fire.
	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.target = NULL;
	lara.left_arm.lock = lara.right_arm.lock = 0;
//	lara.torso_x_rot = lara.torso_y_rot = 0;
//	lara.head_x_rot = lara.head_y_rot = 0;
//##	lara.left_arm.frame_base = lara.right_arm.frame_base = objects[PISTOLS].frame_base;        // use animations in PISTOLS
	lara.left_arm.frame_base = lara.right_arm.frame_base = objects[WeaponObject(weapon_type)].frame_base;
}


/*******************************************************************************
 *				Switch On Pistol meshes please...
 ******************************************************************************/
void	draw_pistol_meshes( int weapon_type )
{
	int obj;

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

	if (weapon_type != LG_MAGNUMS)
	{
		lara.mesh_ptrs[HAND_L]  = meshes[objects[obj].mesh_index + HAND_L];
		lara.mesh_ptrs[THIGH_L] = meshes[objects[LARA].mesh_index + THIGH_L];
	}
}


/******************************************************************************
 *					Switch Off Left Pistol meshes please...
 *****************************************************************************/
void	undraw_pistol_mesh_left( int weapon_type )
{
	if (weapon_type != LG_MAGNUMS)
	{
		int obj;

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

/*****************************************************************************
 *					Switch Off Right Pistol meshes please...
 ****************************************************************************/
void	undraw_pistol_mesh_right( int weapon_type )
{
	int obj;

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

/*****************************************************************************
 *						Do ARM targeting stuff
 ****************************************************************************/
void	PistolHandler( int weapon_type )
{
	WEAPON_INFO	*winfo;

	winfo = &weapons[weapon_type];

/* Get Target Information */
	if (input & IN_ACTION)			// If ACTION pressed
		LaraTargetInfo(winfo);		// get info about current Target
	else
		lara.target = NULL;

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

/* Aim Individual Weapons */

	AimWeapon(winfo, &lara.left_arm);
	AimWeapon(winfo, &lara.right_arm);

/* Make Laras Head and Torso face towards target */
	if (lara.left_arm.lock && !lara.right_arm.lock)
	{
		lara.torso_y_rot = lara.left_arm.y_rot/2;
		lara.torso_x_rot = lara.left_arm.x_rot/2;
		if (camera.old_type != LOOK_CAMERA)
		{
			lara.head_y_rot = lara.torso_y_rot;
			lara.head_x_rot = lara.torso_x_rot;
		}
	}

	else if (lara.right_arm.lock && !lara.left_arm.lock)
	{
		lara.torso_y_rot = lara.right_arm.y_rot/2;
		lara.torso_x_rot = lara.right_arm.x_rot/2;
		if (camera.old_type != LOOK_CAMERA)
		{
			lara.head_y_rot = lara.torso_y_rot;
			lara.head_x_rot = lara.torso_x_rot;
		}
	}

	else if (lara.left_arm.lock && lara.right_arm.lock)
	{
		lara.torso_y_rot = (lara.left_arm.y_rot + lara.right_arm.y_rot)/4;
		lara.torso_x_rot = (lara.left_arm.x_rot + lara.right_arm.x_rot)/4;
		if (camera.old_type != LOOK_CAMERA)
		{
			lara.head_y_rot = lara.torso_y_rot;
			lara.head_x_rot = lara.torso_x_rot;
		}
	}

	AnimatePistols( weapon_type );

// Make flash of light each time Lara fires her guns
	if (lara.left_arm.flash_gun || lara.right_arm.flash_gun)
	{
		int falloff;
		PHD_VECTOR pos;

		if (weapon_type == LG_UZIS)
		{
			falloff = 10;
			VIBRATE(0x1000, 0x1000, 1, 0x400, 1);
		}

		else
		{
			falloff = 10;
			VIBRATE(0xc00, 0xc00, 3, 0x800, 3);
		}


		pos.x = (GetRandomControl()&255)-128;
		pos.y = (GetRandomControl()&127)-63;
		pos.z = (GetRandomControl()&255)-128;
		GetLaraHandAbsPosition(&pos, (lara.left_arm.flash_gun) ? 0 : 1);

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

/******************************************************************************
 *			Animate the Pistols please
 *****************************************************************************/
void	AnimatePistols( int weapon_type )
{
	PISTOL_DEF *p;
	WEAPON_INFO *winfo;
	PHD_ANGLE	angles[2];
	static int uzi_left=0, uzi_right=0;
	sint16 anil, anir, sound_already=0;

/* -------- trigger gun smoke */

	if (SmokeCountL)
	{
  		PHD_VECTOR pos;

		if (SmokeWeapon == LG_PISTOLS)
		{
			pos.x = 4;
			pos.y = PISTOLS_YOFF;
			pos.z = PISTOLS_ZOFF;
		}
		else if (SmokeWeapon == LG_MAGNUMS)
		{
			pos.x = 16;
			pos.y = MAGNUMS_YOFF;
			pos.z = MAGNUMS_ZOFF;
		}
		else if (SmokeWeapon == LG_UZIS)
		{
			pos.x = 8;
			pos.y = UZIS_YOFF;
			pos.z = UZIS_ZOFF;
		}
		GetLaraHandAbsPosition(&pos, 0);	// Left gun.
		TriggerGunSmoke(pos.x, pos.y, pos.z, 0,0,0,0,SmokeWeapon,SmokeCountL);
	}

	if (SmokeCountR)
	{
  		PHD_VECTOR pos;

		if (SmokeWeapon == LG_PISTOLS)
		{
			pos.x = -16;
			pos.y = PISTOLS_YOFF;
			pos.z = PISTOLS_ZOFF;
		}
		else if (SmokeWeapon == LG_MAGNUMS)
		{
			pos.x = -32;
			pos.y = MAGNUMS_YOFF;
			pos.z = MAGNUMS_ZOFF;
		}
		else if (SmokeWeapon == LG_UZIS)
		{
			pos.x = -16;
			pos.y = UZIS_YOFF;
			pos.z = UZIS_ZOFF;
		}
		GetLaraHandAbsPosition(&pos, 1);	// Right gun.
		TriggerGunSmoke(pos.x, pos.y, pos.z, 0,0,0,0,SmokeWeapon,SmokeCountR);
	}

	winfo = &weapons[weapon_type];
	p = &PistolTable[lara.gun_type];

/* -------- process right arm */

	anir = lara.right_arm.frame_number;										// Now Handle Animation

	if ( lara.right_arm.lock || (input&IN_ACTION && !lara.target) )
	{
		if ((anir >= 0) && (anir < p->Draw1Anim2))
			anir++;

		else if (anir == p->Draw1Anim2)
		{
			if (input & IN_ACTION)
			{
				if (weapon_type != LG_MAGNUMS)
				{
					angles[0] = lara.right_arm.y_rot + lara_item->pos.y_rot;
					angles[1] = lara.right_arm.x_rot;

					if (FireWeapon(weapon_type, lara.target, lara_item, angles))
					{
						SmokeCountR = 28;
						SmokeWeapon = weapon_type;
						TriggerGunShell(RIGHT_HAND,GUNSHELL,weapon_type);

						lara.right_arm.flash_gun = winfo->flash_time;

//## could do some volume shit here....
						SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x2000000);
						SoundEffect(winfo->sample_num, &lara_item->pos, 0);
						sound_already = 1;

						if (weapon_type == LG_UZIS)
							uzi_right = 1;

#if defined(PC_VERSION) && defined(GAMEDEBUG)
						level.ammo_used += winfo->damage;
#endif
					}
				}
				anir = p->RecoilAnim;
			}

			else if (uzi_right)
			{
				SoundEffect(winfo->sample_num+1, &lara_item->pos, 0);
				uzi_right = 0;
			}
		}

		else if (anir >= p->RecoilAnim)
		{
			if (weapon_type == LG_UZIS)
			{
				SoundEffect( winfo->sample_num,&lara_item->pos,0 );
				uzi_right = 1;
			}
			anir++;

			if (anir == (p->RecoilAnim+winfo->recoil_frame))
				anir = p->Draw1Anim2;
		}
	}
	else       													// Havent GOT a LOCK ON..
	{
		if (anir >= p->RecoilAnim) 									// If Gun is Recoiling Stop it now...
			anir = p->Draw1Anim2;

		else if ((anir > 0) && (anir <= p->Draw1Anim2))
			anir--;												// UnLock ARM

		if (uzi_right)
		{
			SoundEffect(winfo->sample_num+1, &lara_item->pos, 0);
			uzi_right = 0;
		}
	}
	set_arm_info(&lara.right_arm, anir);

/* -------- process left arm */

	anil = lara.left_arm.frame_number;

	if ( lara.left_arm.lock || (input&IN_ACTION && !lara.target) )
	{
		if ((anil >= 0) && (anil < p->Draw1Anim2))
			anil++;

		else if (anil == p->Draw1Anim2)
		{
			if (input & IN_ACTION)
			{
				angles[0] = lara.left_arm.y_rot + lara_item->pos.y_rot;
				angles[1] = lara.left_arm.x_rot;

				if (FireWeapon(weapon_type, lara.target, lara_item, angles))
				{
					if (weapon_type == LG_MAGNUMS)
					{
						SmokeCountR = 28;
						SmokeWeapon = weapon_type;
						TriggerGunShell(RIGHT_HAND,GUNSHELL,weapon_type);

						lara.right_arm.flash_gun = winfo->flash_time;
					}
					else
					{
						SmokeCountL = 28;
						SmokeWeapon = weapon_type;
						TriggerGunShell(LEFT_HAND,GUNSHELL,weapon_type);

						lara.left_arm.flash_gun = winfo->flash_time;
					}

					if (!sound_already)
					{
						SoundEffect(105, &lara_item->pos, PITCH_SHIFT|0x2000000);
						SoundEffect( winfo->sample_num,&lara_item->pos,0 );
					}

					if (weapon_type == LG_UZIS)
						uzi_left = 1;
#if defined(PC_VERSION) && defined(GAMEDEBUG)
					level.ammo_used += winfo->damage;
#endif
				}
				anil = p->RecoilAnim;
			}

			else if (uzi_left)
			{
				SoundEffect(winfo->sample_num+1, &lara_item->pos, 0);
				uzi_left = 0;
			}
		}

		else if (anil >= p->RecoilAnim)
		{
			if (weapon_type == LG_UZIS)
			{
				SoundEffect( winfo->sample_num,&lara_item->pos,0 );
				uzi_left = 1;
			}

			anil++;

			if (anil == (p->RecoilAnim+winfo->recoil_frame))
				anil = p->Draw1Anim2;
		}
	}
	else       														// Havent GOT a LOCK ON..
	{
		if (anil >= p->RecoilAnim) 									// If Gun is Recoiling Stop it now...
			anil = p->Draw1Anim2;

		else if ((anil > 0) && (anil <= p->Draw1Anim2))
			anil--;													// UnLock ARM

		if (uzi_left)
		{
			SoundEffect(winfo->sample_num+1, &lara_item->pos, 0);
			uzi_left = 0;
		}
	}

	set_arm_info(&lara.left_arm, anil);
}

