/****************************************************************************/
/*                                                                          */
/* Pick-Ups Control                                                         */
/*                                                                          */
/****************************************************************************/

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

#ifdef PSX_VERSION
#include "../spec_psx/typedefs.h"
#else
#include "../specific/stypes.h"
#include "../game/savegame.h"
#include "../game/title.h"
#endif

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "control.h"
#include "input.h"
#include "sound.h"
#include "inventry.h"
#include "invfunc.h"
#include "laramisc.h"
#include "laraflar.h"
#include "health.h"
#include "effect2.h"
#include "gameflow.h"
#include "title.h"

extern int level_complete;
extern short	rcossin_tbl[];
extern sint16 inv_keys_objects;	// ## sort these out
extern sint32 input;

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

#define MAXOFF 220
#define MAXOFF_KH 200
#define MAXOFF_PH 200

enum switch_states {
	SS_OFF,
	SS_ON,
	SS_LINK
};

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

static sint16 PickUpBounds[12] = {					// Normal Pickup bounds
	-256, 256,
	-100, 100,
	-256, 256,
	-10*ONE_DEGREE, 10*ONE_DEGREE,
	0, 0,
	0, 0
};

static PHD_VECTOR PickUpPosition = { 0, 0, -100 };

static sint16 PickUpBoundsUW[12] = {					// UnderWater pickup bounds
	-512, 512,
	-512, 512,
	-512, 512,
	-45*ONE_DEGREE, 45*ONE_DEGREE,
	-45*ONE_DEGREE, 45*ONE_DEGREE,
	-45*ONE_DEGREE, 45*ONE_DEGREE
};

static PHD_VECTOR PickUpPositionUW = { 0, -200, -350 };

static sint16 Switch1Bounds[12] = {
	-MAXOFF, +MAXOFF,				// X axis Limits
	0, 0,						// Y axis Limits
	WALL_L/2-MAXOFF, WALL_L/2,		// Z axis Limits
	-10*ONE_DEGREE, +10*ONE_DEGREE,	// X Rot Limits
	-30*ONE_DEGREE, +30*ONE_DEGREE,	// Y Rot Limits
	-10*ONE_DEGREE, +10*ONE_DEGREE	// Z Rot Limits
};
static PHD_VECTOR DetonatorPosition = { 0, 0, 0 };
static PHD_VECTOR SmallSwitchPosition = {0,0,WALL_L/2-LARA_RAD-50};	// X,Y,Z relative to Switch
static PHD_VECTOR PushSwitchPosition = {0,0,WALL_L/2-LARA_RAD-120};	// X,Y,Z relative to Switch
static PHD_VECTOR AirlockPosition = {0,0,WALL_L/2-LARA_RAD-200};

static sint16 Switch2Bounds[12] = {
	-WALL_L,WALL_L,				// X axis Limits
	-WALL_L,WALL_L,				// Y axis Limits
	-WALL_L,WALL_L/2,       			// Z axis Limits
	-80*ONE_DEGREE,+80*ONE_DEGREE,	// X Rot Limits
	-80*ONE_DEGREE,+80*ONE_DEGREE,	// Y Rot Limits
	-80*ONE_DEGREE,+80*ONE_DEGREE		// Z Rot Limits
};

static PHD_VECTOR Switch2Position = { 0,0,108 };	// X,Y,Z relative to Switch

static sint16 KeyHoleBounds[12] = {
	-MAXOFF_KH,+MAXOFF_KH,			// X axis Limits
	0,0,							// Y axis Limits
	WALL_L/2-MAXOFF_KH,WALL_L/2,		// Z axis Limits
	-10*ONE_DEGREE,+10*ONE_DEGREE,	// X Rot Limits
	-30*ONE_DEGREE,+30*ONE_DEGREE,	// Y Rot Limits
	-10*ONE_DEGREE,+10*ONE_DEGREE		// Z Rot Limits
};

static PHD_VECTOR KeyHolePosition = { 0,0,WALL_L/2-LARA_RAD-50 };

static sint16 PuzzleHoleBounds[12] = {
	-MAXOFF_PH,+MAXOFF_PH,			// X axis Limits
	0,0,							// Y axis Limits
	WALL_L/2-MAXOFF_PH,WALL_L/2,		// Z axis Limits
	-10*ONE_DEGREE,+10*ONE_DEGREE,	// X Rot Limits
	-30*ONE_DEGREE,+30*ONE_DEGREE,	// Y Rot Limits
	-10*ONE_DEGREE,+10*ONE_DEGREE		// Z Rot Limits
};

static PHD_VECTOR PuzzleHolePosition = { 0,0,WALL_L/2-LARA_RAD-85 };  // Ideal Pos of Lara rel to PuzzleHole

static int pup_x, pup_y, pup_z;

/****************************************************************************
 *			Collision with PickUpable Items
 ***************************************************************************/
void	PickUpCollision( sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll )
{
	ITEM_INFO	*item;
	sint16 x_rot, y_rot, z_rot;
#ifdef SECRET_BONUS
	int	i;
#endif

	item = &items[item_num];

/* Gav: remember the rotations, as they are fiddled with for detection purposes */
	x_rot = item->pos.x_rot;
	y_rot = item->pos.y_rot;
	z_rot = item->pos.z_rot;

	item->pos.y_rot = laraitem->pos.y_rot;
	item->pos.z_rot = 0;

	if ((lara.water_status == LARA_ABOVEWATER)
	||  (lara.water_status == LARA_WADE))
	{
		item->pos.x_rot = 0;

		if (!TestLaraPosition(PickUpBounds, item, laraitem))
		{
			item->pos.x_rot = x_rot;
			item->pos.y_rot = y_rot;
			item->pos.z_rot = z_rot;
			return;
		}

		if (laraitem->current_anim_state == AS_PICKUP)
		{
			if (((laraitem->frame_number == PICKUP_F)
			||   (laraitem->frame_number == DUCKPICKUP_F)
			||   (laraitem->frame_number == ALL4SPICKUP_F))
			&&   (item->object_number != FLARE_ITEM))
			{
#ifdef PC_VERSION
				AddDisplayPickup(item->object_number);
#endif
				Inv_AddItem(item->object_number);
#ifdef SECRET_BONUS
				if ((item->object_number == SECRET_ITEM1)
				||  (item->object_number == SECRET_ITEM2)
				||  (item->object_number == SECRET_ITEM3))
				{
					if ((i = (savegame.secrets&1) + ((savegame.secrets&2)>>1) + ((savegame.secrets&4)>>2)) >=3)
						GF_ModifyInventory(CurrentLevel, 1);
				}
#endif
				item->status = INVISIBLE;


				if ((item->object_number == ICON_PICKUP1_ITEM)
				||  (item->object_number == ICON_PICKUP2_ITEM)
				||  (item->object_number == ICON_PICKUP3_ITEM)
				||  (item->object_number == ICON_PICKUP4_ITEM))
				{
					if (CurrentLevel != LV_CHAMBER)
						level_complete = 1;
					else
						KillItem(item_num);
				}
				else
					RemoveDrawnItem(item_num);
			}

			else
			{
				item->pos.x_rot = x_rot;
				item->pos.y_rot = y_rot;
				item->pos.z_rot = z_rot;
			}
			return;	// required frame before deleting object
		}

		else if (laraitem->current_anim_state == AS_FLAREPICKUP)
		{
			if ((((laraitem->anim_number == DUCKPICKUPF_A)
			&&    (laraitem->frame_number == DUCKPICKUPF_F))
			||    (laraitem->frame_number == PICKUPF_F))
			&&    (item->object_number == FLARE_ITEM)
			&&    (lara.gun_type != LG_FLARE))
			{
				lara.request_gun_type = LG_FLARE;
				lara.gun_type = LG_FLARE;
				InitialiseNewWeapon();
				lara.gun_status = LG_SPECIAL;
				lara.flare_age = (sint32)(item->data) & 0x7fff; // the flare's flags are its age
				KillItem(item_num);
			}
			return;
		}

		else	if ((input & IN_ACTION)
			&&  (laraitem->current_anim_state == AS_ALL4S))
				laraitem->goal_anim_state = AS_DUCK;

		else	if ((input&IN_ACTION)
			&&  (!laraitem->gravity_status)
			&& (((laraitem->current_anim_state == AS_STOP)
			&&   (laraitem->anim_number == BREATH_A))
			||  ((laraitem->current_anim_state == AS_DUCK)
			&&   (laraitem->anim_number == DUCKBREATHE_A)))
			&&   (lara.gun_status == LG_ARMLESS)
			&& !(lara.gun_type == LG_FLARE && item->object_number==FLARE_ITEM))
			{
				if (item->object_number == FLARE_ITEM)
				{
					laraitem->goal_anim_state = AS_FLAREPICKUP;

					do {
						AnimateLara(laraitem);
					} while (laraitem->current_anim_state != AS_FLAREPICKUP);
				}
				else

				{
					AlignLaraPosition(&PickUpPosition, item, laraitem);
					laraitem->goal_anim_state = AS_PICKUP;
					AnimateLara(laraitem);

//##				do {
//##					AnimateLara(laraitem);
//##				} while (laraitem->current_anim_state!=AS_PICKUP);
				}

				if (lara.IsDucked)
					laraitem->goal_anim_state = AS_DUCK;
				else
					laraitem->goal_anim_state = AS_STOP;

				lara.gun_status = LG_HANDSBUSY;

				item->pos.x_rot = x_rot;
				item->pos.y_rot = y_rot;
				item->pos.z_rot = z_rot;
				return;
			}
	}

	else if ( lara.water_status==LARA_UNDERWATER )				// UNDERWATER PICKUPS
	{
		item->pos.x_rot = -25*ONE_DEGREE;

		if (!TestLaraPosition(PickUpBoundsUW, item, laraitem))
		{
			item->pos.x_rot = x_rot;
			item->pos.y_rot = y_rot;
			item->pos.z_rot = z_rot;
			return;
		}

		if ( laraitem->current_anim_state==AS_PICKUP )
		{
			if ( laraitem->frame_number==PICKUP_UW_F && item->object_number!=FLARE_ITEM)			// We are in the pickup
			{
#ifdef PC_VERSION
				AddDisplayPickup( item->object_number );
#endif
				Inv_AddItem( item->object_number );
#ifdef SECRET_BONUS
				if ( item->object_number==SECRET_ITEM1 || item->object_number==SECRET_ITEM2 || item->object_number==SECRET_ITEM3)
				{
					if ((i = (savegame.secrets&1) + ((savegame.secrets&2)>>1) + ((savegame.secrets&4)>>2)) >=3)
						GF_ModifyInventory( CurrentLevel, 1 );
				}
#endif
				item->status = INVISIBLE;
				RemoveDrawnItem( item_num );
			}
			return;
		}
		else if (laraitem->current_anim_state==AS_FLAREPICKUP)
		{
			if (laraitem->frame_number==PICKUPF_UW_F && item->object_number==FLARE_ITEM && lara.gun_type!=LG_FLARE)
			{
				lara.request_gun_type = LG_FLARE;
				lara.gun_type = LG_FLARE;
				InitialiseNewWeapon();
				lara.gun_status = LG_SPECIAL;
				lara.flare_age = (sint32)(item->data) & 0x7fff; // the flare's flags are its age
				draw_flare_meshes();
				KillItem(item_num);
			}
			return;
		}
		else if ( input&IN_ACTION && laraitem->current_anim_state==AS_TREAD &&
	 	  	lara.gun_status==LG_ARMLESS && !(lara.gun_type==LG_FLARE && item->object_number==FLARE_ITEM))

		{
			if ( !MoveLaraPosition( &PickUpPositionUW,item,laraitem) )
				return;
			if (item->object_number==FLARE_ITEM)
			{
				laraitem->fallspeed = 0;
				laraitem->current_anim_state = AS_FLAREPICKUP;
				laraitem->anim_number = PICKUPF_UW_A;
				laraitem->frame_number = anims[PICKUPF_UW_A].frame_base;
			}
			else
			{
				laraitem->goal_anim_state = AS_PICKUP;				// We want to go into
				do
				{
					AnimateLara(laraitem);                      		// the pickup animation
				} while ( laraitem->current_anim_state!=AS_PICKUP );
			}
			laraitem->goal_anim_state = AS_TREAD;
			return;
		}
	}

	/* If not in pickup then realign object to its original rotation */
	item->pos.x_rot = x_rot;
	item->pos.y_rot = y_rot;
	item->pos.z_rot = z_rot;

}


/******************************************************************************
 *				Collision Routine for Switches
 *****************************************************************************/

void	SwitchCollision(sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll)
{
	ITEM_INFO	*item;

	item = &items[item_num];

	if ((!(input & IN_ACTION))
	||  (item->status != NOT_ACTIVE)
	||  (item->flags & ONESHOT)
	||  (lara.gun_status != LG_ARMLESS)
	||  (laraitem->gravity_status))
		return;

	if ((laraitem->current_anim_state == AS_STOP)
	&&  (laraitem->anim_number == BREATH_A))
	{
		if (!TestLaraPosition(Switch1Bounds, item, laraitem))
			return;

	/* -------- align Lara to switch */

		lara.torso_x_rot = lara.torso_y_rot = lara.head_x_rot = lara.head_y_rot = 0;

		laraitem->pos.y_rot = item->pos.y_rot;

		if (item->object_number == SMALL_SWITCH)
			AlignLaraPosition(&SmallSwitchPosition, item, laraitem);

		else if (item->object_number == PUSH_SWITCH)
			AlignLaraPosition(&PushSwitchPosition, item, laraitem);

		else if (item->object_number == AIRLOCK_SWITCH)
		{
//			if (item->current_anim_state == SS_ON)
//				return;
			AlignLaraPosition(&AirlockPosition, item, laraitem);
		}

	/* -------- start switch off anim */

		if (item->current_anim_state == SS_ON)
		{
			laraitem->current_anim_state = AS_SWITCHON;

			if (item->object_number == SMALL_SWITCH)
				laraitem->anim_number = objects[LARA].anim_index + 195;

			else if (item->object_number == PUSH_SWITCH)
				laraitem->anim_number = objects[LARA].anim_index + 197;

			else if (item->object_number == AIRLOCK_SWITCH)
			{
				laraitem->anim_number = objects[LARA_EXTRA].anim_index;
				laraitem->frame_number = anims[laraitem->anim_number].frame_base;
				laraitem->current_anim_state = EXTRA_BREATH;
				laraitem->goal_anim_state = EXTRA_AIRLOCK;
				AnimateItem(laraitem);
				lara.extra_anim = 1;
			}

			else
				laraitem->anim_number = objects[LARA].anim_index + 63;

			item->goal_anim_state = SS_OFF;
		}

	/* -------- start switch on anim */

		else
		{
			laraitem->current_anim_state = AS_SWITCHOFF;

			if (item->object_number == SMALL_SWITCH)
				laraitem->anim_number = objects[LARA].anim_index + 196;

			else if (item->object_number == PUSH_SWITCH)
				laraitem->anim_number = objects[LARA].anim_index + 197;

			else if (item->object_number == AIRLOCK_SWITCH)
			{
				laraitem->anim_number = objects[LARA_EXTRA].anim_index;
				laraitem->frame_number = anims[laraitem->anim_number].frame_base;
				laraitem->current_anim_state = EXTRA_BREATH;
				laraitem->goal_anim_state = EXTRA_AIRLOCK;
				AnimateItem(laraitem);
				lara.extra_anim = 1;
			}
			else
				laraitem->anim_number = objects[LARA].anim_index + 64;

			item->goal_anim_state = SS_ON;
		}

		if (!lara.extra_anim)
		{
			laraitem->frame_number = anims[laraitem->anim_number].frame_base;
			laraitem->goal_anim_state = AS_STOP;
		}

		lara.gun_status = LG_HANDSBUSY;
		item->status = ACTIVE;
		AddActiveItem(item_num);
		AnimateItem(item);
	}
}

/*******************************************************************************
 *					UnderWater switching
 ******************************************************************************/
void	SwitchCollision2( sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll )
{
	ITEM_INFO	*item;

	item = &items[item_num];
	if ( !(input&IN_ACTION) || item->status!=NOT_ACTIVE || lara.water_status!=LARA_UNDERWATER ||
			lara.gun_status!=LG_ARMLESS)
			return;

	if ( laraitem->current_anim_state==AS_TREAD )
	{
		if ( !TestLaraPosition( Switch2Bounds, item, laraitem) )
			return;
		if ( item->current_anim_state==SS_ON || item->current_anim_state==SS_OFF )
		{
			if ( MoveLaraPosition( &Switch2Position, item, laraitem ) )
			{
				laraitem->fallspeed = 0;
				laraitem->goal_anim_state = AS_SWITCHON;			// Request for a SwitchOn animation
				do
				{
					AnimateLara( laraitem );
				} while ( laraitem->current_anim_state!=AS_SWITCHON );
				laraitem->goal_anim_state = AS_TREAD;
				lara.gun_status=LG_HANDSBUSY;
				item->status = ACTIVE;
				if ( item->current_anim_state==SS_ON )
					item->goal_anim_state = SS_OFF;
				else
					item->goal_anim_state = SS_ON;
				AddActiveItem( item_num );
				AnimateItem(item);
			}
		}
	}
}


void DetonatorCollision(sint16 item_number, ITEM_INFO *laraitem, COLL_INFO *coll)
{
	/* Special collision routine for detonator box (and gong too now) */
	ITEM_INFO *item;
	sint16 x_rot, y_rot, z_rot;

	/* If already doing this, don't bother */
	if (lara.extra_anim)
		return;

	item = &items[item_number];

	/* Remember the rotations, as they are fiddled with for detection purposes */
	x_rot = item->pos.x_rot;
	y_rot = item->pos.y_rot;
	z_rot = item->pos.z_rot;

	item->pos.y_rot = laraitem->pos.y_rot;
	item->pos.z_rot = 0;
	item->pos.x_rot = 0;

	if	(item->status != DEACTIVATED && (input&IN_ACTION) && lara.gun_status==LG_ARMLESS &&
		 !laraitem->gravity_status && laraitem->current_anim_state==AS_STOP)
	{
		if (item->object_number == DETONATOR)
		{
			if (!TestLaraPosition(PickUpBounds,item,laraitem))
				goto normal_collision;
		}
/*		else
		{
			if (!TestLaraPosition(GongBounds,item,laraitem))
				goto normal_collision;
			else
			{
				item->pos.x_rot = x_rot;
				item->pos.y_rot = y_rot;
				item->pos.z_rot = z_rot;
			}
		}*/


		/* Pull up inventory if item not currently chosen */
		if (Inventory_Chosen == -1)
			Display_Inventory(INV_KEYS_MODE);

		/* If detonator key not chosen then don't continue */
		if (Inventory_Chosen != KEY_OPTION2)
			goto normal_collision;

		Inv_RemoveItem(KEY_OPTION2);

		AlignLaraPosition(&DetonatorPosition,item,laraitem);

		/* Jump to detonator animation state in LARA_EXTRA */
		laraitem->anim_number = objects[LARA_EXTRA].anim_index;
		laraitem->frame_number = anims[laraitem->anim_number].frame_base;
		laraitem->current_anim_state = EXTRA_BREATH;
		if (item->object_number == DETONATOR)
			laraitem->goal_anim_state = EXTRA_PLUNGER;
/*		else
		{
			laraitem->goal_anim_state = EXTRA_GONGBONG;
			laraitem->pos.y_rot += -0x8000;
		}*/

		/* Jump to that animation */
		AnimateItem(laraitem);

		/* Flag that Lara is running animations from another project */
		lara.extra_anim = 1;

		lara.gun_status = LG_HANDSBUSY;

		if (item->object_number==DETONATOR)
		{
			/* Activate detonator to get it to play its side of the anim */
			item->status = ACTIVE;
			AddActiveItem(item_number);
		}
/*		else
		{
			// Create gong bonger and make it do its thing
			item_number = CreateItem();
			if (item_number != NO_ITEM)
			{
				item = &items[item_number];
				item->object_number = GONGBONGER;
				item->pos.x_pos = laraitem->pos.x_pos;
				item->pos.y_pos = laraitem->pos.y_pos;
				item->pos.z_pos = laraitem->pos.z_pos;
				item->pos.y_rot = laraitem->pos.y_rot;
				item->pos.x_rot = laraitem->pos.z_rot = 0;
				item->room_number = laraitem->room_number;

				InitialiseItem(item_number);

				AddActiveItem(item_number);
				item->status = ACTIVE;
			}
		}       */

		return;
	}

normal_collision:
	item->pos.x_rot = x_rot;
	item->pos.y_rot = y_rot;
	item->pos.z_rot = z_rot;
	ObjectCollision(item_number, laraitem, coll);
}

/*****************************************************************************
 *				Lara Has Collided With A KeyHole...
 ****************************************************************************/
void	KeyHoleCollision( sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll )
{
	int correct=0;
	ITEM_INFO	*item;

	if ((laraitem->current_anim_state == AS_STOP)
	&&  (laraitem->anim_number == BREATH_A))
	{
		item = &items[item_num];
		if ( (Inventory_Chosen==-1 && !(input&IN_ACTION)) ||
		 	lara.gun_status!=LG_ARMLESS ||
		 	laraitem->gravity_status )
				return;

		if ( !TestLaraPosition( KeyHoleBounds, item, laraitem ) )
			return;
		if ( item->status!=NOT_ACTIVE )
		{
			/* If keyhole used, say NO and remember position so she doesn't say it again */
			if ( laraitem->pos.x_pos!=pup_x ||
				 laraitem->pos.y_pos!=pup_y	||
				 laraitem->pos.z_pos!=pup_z )
			{
				pup_x = laraitem->pos.x_pos;
				pup_y = laraitem->pos.y_pos;
				pup_z = laraitem->pos.z_pos;
				SoundEffect( 2, &laraitem->pos, 0 );
			}
			return;
		}

		if ( Inventory_Chosen==-1 )
		{
			Display_Inventory(INV_KEYS_MODE);
			if ( Inventory_Chosen==-1 && inv_keys_objects )
				return;
			if ( Inventory_Chosen!=-1 )
				pup_y = laraitem->pos.y_pos-1;            // alter saved pos so enforces response
		}
		else
			pup_y = laraitem->pos.y_pos-1;            // alter saved pos so enforces response

		switch ( item->object_number )
		{
			case KEY_HOLE1:
				if ( Inventory_Chosen!=KEY_OPTION1 )
					break;
				Inv_RemoveItem( KEY_OPTION1 );
				correct = 1;
			break;

			case KEY_HOLE2:
				if ( Inventory_Chosen!=KEY_OPTION2 )
					break;
				Inv_RemoveItem( KEY_OPTION2 );
				correct = 1;
			break;

			case KEY_HOLE3:
				if ( Inventory_Chosen!=KEY_OPTION3 )
					break;
				Inv_RemoveItem( KEY_OPTION3 );
				correct = 1;
			break;

			case KEY_HOLE4:
				if ( Inventory_Chosen!=KEY_OPTION4 )
					break;
				Inv_RemoveItem( KEY_OPTION4 );
				correct = 1;
			break;

		}

		Inventory_Chosen = -1;				// reset inventory chosen item
		if ( !correct )
		{
			if ( laraitem->pos.x_pos!=pup_x ||
				 laraitem->pos.y_pos!=pup_y	||
				 laraitem->pos.z_pos!=pup_z )
			{
				SoundEffect( 2, &laraitem->pos, 0 );
				pup_x = laraitem->pos.x_pos;
				pup_y = laraitem->pos.y_pos;
				pup_z = laraitem->pos.z_pos;
			}
			return;
		}

		AlignLaraPosition( &KeyHolePosition, item, laraitem );
		laraitem->goal_anim_state = AS_USEKEY;
		do
			AnimateLara( laraitem );
		while ( laraitem->current_anim_state!=AS_USEKEY );

		laraitem->goal_anim_state=AS_STOP;          // make Lara go back to Stop
		lara.gun_status=LG_HANDSBUSY;               // Hands Are Busy for now..
		item->status = ACTIVE;						// Make keyHole Active...

		pup_x = laraitem->pos.x_pos;
		pup_y = laraitem->pos.y_pos;
		pup_z = laraitem->pos.z_pos;
	}
}


/*****************************************************************************
 *				Lara Has Collided With A Puzzle Receptacle
 ****************************************************************************/
void	PuzzleHoleCollision( sint16 item_num, ITEM_INFO *laraitem, COLL_INFO *coll )
{
	ITEM_INFO	*item;
	int			correct=0;


	item = &items[item_num];

	if ((laraitem->current_anim_state == AS_STOP)
	&&  (laraitem->anim_number == BREATH_A))
	{
		if (((Inventory_Chosen == -1)	&& (!(input&IN_ACTION)))
		||  (lara.gun_status != LG_ARMLESS)
		||  (laraitem->gravity_status))
			return;

		if (!TestLaraPosition(PuzzleHoleBounds, item, laraitem))
			return;

		if (item->status != NOT_ACTIVE)
		{
			if ((laraitem->pos.x_pos != pup_x)
			||  (laraitem->pos.y_pos != pup_y)
			||  (laraitem->pos.z_pos != pup_z))
			{
				pup_x = laraitem->pos.x_pos;
				pup_y = laraitem->pos.y_pos;
				pup_z = laraitem->pos.z_pos;
				SoundEffect( 2, &laraitem->pos, 0 );
			}
			return;
		}

		if (Inventory_Chosen == -1)
		{
			Display_Inventory(INV_KEYS_MODE);

			if ((Inventory_Chosen == -1)
			&&  (inv_keys_objects))
				return;

			if (Inventory_Chosen != -1)
				pup_y = laraitem->pos.y_pos-1;	// alter saved pos so enforces response
		}
		else
			pup_y = laraitem->pos.y_pos-1;		// alter saved pos so enforces response

		switch (item->object_number)
		{
			case PUZZLE_HOLE1:
				if (Inventory_Chosen != PUZZLE_OPTION1)
					break;
				Inv_RemoveItem( PUZZLE_OPTION1 );
				correct = 1;
				break;

			case PUZZLE_HOLE2:
				if ( Inventory_Chosen!=PUZZLE_OPTION2 )
					break;
				Inv_RemoveItem( PUZZLE_OPTION2 );
				correct = 1;
				break;

			case PUZZLE_HOLE3:
				if ( Inventory_Chosen!=PUZZLE_OPTION3 )
					break;
				Inv_RemoveItem( PUZZLE_OPTION3 );
				correct = 1;
				break;

			case PUZZLE_HOLE4:
				if ( Inventory_Chosen!=PUZZLE_OPTION4 )
					break;
				Inv_RemoveItem( PUZZLE_OPTION4 );
				correct = 1;
				break;
		}

		Inventory_Chosen = -1;				// reset inventory chosen item

		if (!correct)
		{
			if ( laraitem->pos.x_pos!=pup_x ||
				 laraitem->pos.y_pos!=pup_y	||
				 laraitem->pos.z_pos!=pup_z )
			{
				SoundEffect( 2, &laraitem->pos, 0 );
				pup_x = laraitem->pos.x_pos;
				pup_y = laraitem->pos.y_pos;
				pup_z = laraitem->pos.z_pos;
			}
			return;
		}
		AlignLaraPosition( &PuzzleHolePosition, item, laraitem );
		laraitem->goal_anim_state = AS_USEPUZZLE;
		do
		{
			AnimateLara( laraitem );
		} while ( laraitem->current_anim_state!=AS_USEPUZZLE );
		laraitem->goal_anim_state=AS_STOP;          // make Lara go back to Stop
		lara.gun_status=LG_HANDSBUSY;               // Hands Are Busy for now..
		item->status = ACTIVE;						// Make keyHole Active...
		pup_x = laraitem->pos.x_pos;
		pup_y = laraitem->pos.y_pos;
		pup_z = laraitem->pos.z_pos;
		return;
	}

	else if ( laraitem->current_anim_state==AS_USEPUZZLE )
	{
		if ( !TestLaraPosition( PuzzleHoleBounds, item, laraitem ) )
			return;
		if ( laraitem->frame_number==USEPUZZLE_F )
		{
			switch ( item->object_number )
			{
				case PUZZLE_HOLE1:
					item->object_number = PUZZLE_DONE1;
				break;

				case PUZZLE_HOLE2:
					item->object_number = PUZZLE_DONE2;
				break;

				case PUZZLE_HOLE3:
					item->object_number = PUZZLE_DONE3;
				break;

				case PUZZLE_HOLE4:
					item->object_number = PUZZLE_DONE4;
				break;

			}

			item->anim_number = objects[item->object_number].anim_index;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = item->goal_anim_state = anims[item->anim_number].current_anim_state;
			item->required_anim_state = 0;
			AddActiveItem( item_num );	//##
			item->status = ACTIVE;
			item->flags = CODE_BITS;
			AnimateItem(item);            //##
		}
	}
}


/*****************************************************************************
 *		Switch Control Routine...
 ****************************************************************************/
void	SwitchControl(sint16 item_number)
{
	ITEM_INFO *item;

	item = &items[item_number];

	item->flags |= CODE_BITS; // needed by TriggerActive()

	if (!TriggerActive(item) && !(item->flags & ONESHOT))
	{
		item->goal_anim_state = SS_ON;
		item->timer = 0; // needed to avoid dodgy effects next time switch pulled
	}

	AnimateItem(item);
}

/****************************************************************************
 *			Switch has reached Deactivate so do triggering
 *			 returns 0 if not switched yet
 *					 1 if switched
 *			Also remove from Active List if finished...
 ***************************************************************************/
int SwitchTrigger(sint16 item_num, sint16 timer)
{
	ITEM_INFO	*item;

	item = &items[item_num];
#if 0
	/* Airlock switches work differently */
	if (item->object_number == AIRLOCK_SWITCH)
	{
		if (item->status == DEACTIVATED)
		{
			RemoveActiveItem(item_num);
			item->status = NOT_ACTIVE;
			return 0;
		}
		else if ((item->flags & ONESHOT)
			||  (item->current_anim_state == SS_OFF))
				return 0;

		item->flags |= ONESHOT;
		return 1;
	}
#endif

	if (item->status == DEACTIVATED)
	{
		/* Gav: switches with timers reset automatically */
		if (item->current_anim_state == SS_OFF && timer > 0)
		{
//			printf("+");
			item->timer = timer;
			item->status = ACTIVE;

			if (timer != 1)
				item->timer *= 30;
		}
		else
		{
//			printf("Off!");
//			printf("-");
			RemoveActiveItem(item_num);
			item->status = NOT_ACTIVE;
			if (item->item_flags[0])
				item->flags |= ONESHOT;
		}
		return(1);
	}

	if (item->flags & ONESHOT)
		return(1);
	else
		return(0);
}

/****************************************************************************
 *		  Key Receptacle has reached Deactivate so if Lara has finished her
 *			Animation( Flagged by HANDS NOW FREE ) then True..
 *			 returns 0 if not triggered yet
 *					 1 if Key Triggered
 *			Also remove from Active List if finished...
 ***************************************************************************/
int		KeyTrigger( sint16 item_num )
{
	ITEM_INFO	*item;

	item = &items[item_num];
//	if ( item->status==ACTIVE && lara.gun_status==LG_ARMLESS )		//SONY BUG FIX B13 - After using detonator, you immediately drew your weapons
	if ( item->status==ACTIVE && lara.gun_status!=LG_HANDSBUSY )	//					 the flip-map wouldn't happen until you put your weapons away
	{																//					 or not at all if you went into the water with your guns still out
		item->status = DEACTIVATED;									//					 This also fixes the same bug with the doors opening.
		return(1);
	}
	return(0);
}

/****************************************************************************
 *		  If an item has Been picked up then it has to be able to trigger
 *		  			an effect. However this only happens once!!
 ***************************************************************************/
int		PickupTrigger( sint16 item_num )
{
	ITEM_INFO	*item;

	item = &items[item_num];
	if ( item->status==INVISIBLE )
	{
		item->status = DEACTIVATED;
		return(1);
	}
	return(0);
}


//void SecretControl(sint16 item_number)
//{
//	items[item_number].status = INVISIBLE;
//	RemoveDrawnItem(item_number);
//}

void BossDropIcon(sint16 item_number)
{
	sint16 pickup_number;
	ITEM_INFO *item, *pickup;

	item = &items[item_number];

	// drop any carried items
	pickup_number = item->carried_item;
	while (pickup_number != NO_ITEM)
	{
		pickup = &items[pickup_number];
		pickup->pos.x_pos = item->pos.x_pos;
		pickup->pos.y_pos = item->pos.y_pos;
		pickup->pos.z_pos = item->pos.z_pos;
		ItemNewRoom(pickup_number, item->room_number);

		AddActiveItem(pickup_number);
		item->status = ACTIVE;
		pickup_number = pickup->carried_item;
	}
}

void AnimatingPickUp(sint16 item_number)
{
	ITEM_INFO	*item;
	long		dx,dy,dz;
	long		col;

	item = &items[item_number];

	if (item->status == INVISIBLE || (item->flags & KILLED_ITEM))
		return;

	if (item->object_number == SAVEGAME_CRYSTAL_ITEM && item->item_flags[1] == 0)
	{
		item->item_flags[1] = 1;
		item->item_flags[2] = item->pos.y_pos;
	}

	item->pos.y_rot += 0x400;

	item->item_flags[0]++;
	item->item_flags[0] &= 63;

	col = abs(rcossin_tbl[item->item_flags[0]<<7]>>7);
	if (col>31)
		col = 31;

	if (item->object_number == SAVEGAME_CRYSTAL_ITEM)
	{
		dx = abs(rcossin_tbl[item->item_flags[0]<<7]>>4);
		item->pos.y_pos = item->item_flags[2] - dx - 64;
		TriggerDynamic(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,8,0,col>>2,col);
		dx = abs(item->pos.x_pos - lara_item->pos.x_pos);
		dy = abs(item->pos.y_pos - lara_item->pos.y_pos);
		dz = abs(item->pos.z_pos - lara_item->pos.z_pos);
		if (dx < 0x100 && dy < 0x400 && dz < 0x100)
		{
			SoundEffect( 212, &lara_item->pos,NULL);
			Inv_AddItem(item->object_number);
			KillItem(item_number);
		}
	}
	else
		TriggerDynamic(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,8,0,col,col>>1);

}
