#include "game.h"

#ifdef GAMEDEBUG
char	*states[] = {
	"WALK",
	"RUN",
	"STOP",
	"F_JUMP",
	"POSE",
	"FASTBACK",
	"TURN_R",
	"TURN_L",
	"DEATH",
	"FASTFALL",
	"HANG",
	"REACH",
	"SPLAT",
	"TREAD",
	"LAND",
	"COMPRESS",
	"BACK",
	"SWIM",
	"GLIDE",
	"NULL",
	"FAST_TURN",
	"STEP_RIGHT",
	"STEP_LEFT",
	"ROLL2",
	"SLIDE",
	"B_JUMP",
	"R_JUMP",
	"L_JUMP",
	"UP_JUMP",
	"FALL_BACK",
	"HANG_LEFT",
	"HANG_RIGHT",
	"SLIDE_BACK",
	"SURF_TREAD",
	"SURF_SWIM",
	"DIVE",
	"PUSHBLOCK",
	"PULLBLOCK",
	"PPREADY",
	"PICKUP",
	"SWITCHON",
	"SWITCHOFF",
	"USE-KEY",
	"USE-PUZZLE",
	"UW_DEATH",
	"ROLL",
	"SPECIAL",
	"SURFBACK",
	"SURFLEFT",
	"SURFRIGHT",
	"USE-MIDAS",
	"DIE-MIDAS",
	"SWAN-DIVE",
	"FAST-DIVE",
	"GYMNAST",
	"WATER-OUT",
	"CLIMB STANCE",
	"CLIMBING",
	"CLIMB-LEFT",
	"CLIMB-END",
	"CLIMB-RIGHT",
	"CLIMB-DOWN",
	"LARATEST1",
	"LARATEST2",
	"LARATEST3",
	"WADE",
	"WATER-ROLL",
	"PICKUP",
	"TWIST",
	"LAST"
};

char	*quadrant_names[] = {
	"NORTH",
	"EAST",
	"SOUTH",
	"WEST" };

char	*gunstates[] = {
	"ARMLESS",
	"HANDSBUSY",
	"DRAW",
	"UNDRAW",
	"READY",
	"SPECIAL"
};

char	*waterstates[] = {
	"ABOVEWATER",
	"UNDERWATER",
	"SURFACE",
	"CHEAT",
	"WADE"
};

char	*guntypes[] = {
	"UNARMED",
	"PISTOLS",
	"MAGNUMS",
	"UZIS",
	"SHOTGUN",
	"M16",
	"ROCKET",
	"HARPOON",
	"FLARE"
};

char	*coll_typess[] = {
	"NONE",
	"FRONT",
	"LEFT",
	"RIGHT",
	"TOP",
	"TOPBOTTOM",
	"TOPFRONT",
	"CLAMP"
};

char	*htypes[] = {
	"WALL",
	"SMALL_SLOPE",
	"BIG_SLOPE"
};
#endif

#define WADE_DEPTH (STEP_L*3/2)
#define SWIM_DEPTH 730

extern int outside;

/***********************************************************************************************
 *						Everything to do with Lara Control is Here
 **********************************************************************************************/
void	LaraControl( sint16 item_number )
{
	int		wh,wd,hfw,room_water_state;
	ITEM_INFO	*item;
	COLL_INFO	mycoll,*coll = &mycoll;

#if !defined(NO_FLY_CHEAT) || defined(ALWAYS_ENABLE_DOZY_CHEAT)
	if (gameflow.cheat_enable || gameflow.dozy_cheat_enabled)
		LaraCheatyBits();
#endif
/*
#ifdef GAMEDEBUG
	// Weapon states
	sprintf( exit_message, "X:%d Y:%d Z:%d",lara_item->pos.x_pos, lara_item->pos.y_pos, lara_item->pos.z_pos);
	PrintDbug(4,1, exit_message);
	sprintf( exit_message, "XR:%x YR:%x ZR:%x",(uint16)lara_item->pos.x_rot, (uint16)lara_item->pos.y_rot, (uint16)lara_item->pos.z_rot);
	PrintDbug(4,2, exit_message);
	if (lara.water_surface_dist>=0 || lara.water_surface_dist==NO_HEIGHT)
		PrintDbug(4,5,"ABOVE WATER");
	else
		PrintDbug(4,5,"IN WATER");
	if (lara.climb_status)
		PrintDbug(15,5,"CLIMB");
	else
		PrintDbug(15,5,"NOCLIMB");

	sprintf( exit_message, "WaterState: %s",waterstates[lara.water_status]);
	PrintDbug(4,7, exit_message);
#endif
*/
	item = lara_item;



	room_water_state = room[item->room_number].flags & UNDERWATER;

#if (defined(PC_VERSION) && defined(GAMEDEBUG)) || defined(SHOW_ROOM_INFO)
/*
	strcpy(exit_message, GF_Level_Names[CurrentLevel]);
	PrintDbug(2,2,exit_message);
	sprintf(exit_message, "Room%d x%d y%d", item->room_number, item->pos.z_pos - room[item->room_number].z >> WALL_SHIFT, item->pos.x_pos - room[item->room_number].x >> WALL_SHIFT);
	PrintDbug(2,3,exit_message);
	if (outside>0)
		PrintDbug(2,4,"Sky drawn");
	else if (outside<0)
		PrintDbug(2,4,"Clear screen");
*/
#endif

#ifdef GAMEDEBUG
#ifdef PC_VERSION
//	sprintf( exit_message, "Gun: %s Req: %s State: %s",guntypes[lara.gun_type],guntypes[lara.request_gun_type],gunstates[lara.gun_status]);
//	PrintDbug(2,4, exit_message);
//	sprintf( exit_message, "WaterState: %s",waterstates[lara.water_status]);
//	PrintDbug(2,5, exit_message);
//	sprintf(exit_message, "R%d x%d y%d", lara_item->room_number, lara_item->pos.z_pos-room[lara_item->room_number].z >> WALL_SHIFT, lara_item->pos.x_pos - room[lara_item->room_number].x >> WALL_SHIFT);
//	PrintDbug(2,2,exit_message);
//	Log(exit_message);
//	Log("WaterState: %s", waterstates[lara.water_status]);
//	Log("(%d:f%d) %s G:%s (%d)", lara_item->anim_number, lara_item->frame_number-anims[lara_item->anim_number].frame_base, states[lara_item->current_anim_state], states[lara_item->goal_anim_state], lara.extra_anim);
//	Log("Speed %d f%d x%d z%d", lara_item->speed, lara_item->fallspeed, item->pos.x_pos, item->pos.z_pos);
// GF_NoFloor = 4608;
#endif
#endif

	wd = GetWaterDepth(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, 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;
	else
		hfw = NO_HEIGHT;
	lara.water_surface_dist = -hfw;
//Log("%s h%d d%d", waterstates[lara.water_status], hfw, wd);

	WadeSplash(item, wh);

	if (lara.skidoo == NO_ITEM && !lara.extra_anim)
	{
		switch ( lara.water_status )
		{
			case LARA_ABOVEWATER:
				if (hfw==NO_HEIGHT || hfw < WADE_DEPTH)
					break;

				if (wd > SWIM_DEPTH - STEP_L)
				{
					if (room_water_state)
					{
	   				lara.air = LARA_AIR;
	   				lara.water_status = LARA_UNDERWATER;					// Going Into UnderWater from AboveWater
	   				item->gravity_status = 0;
	   				item->pos.y_pos += 100;
	   				UpdateLaraRoom( lara_item,0 );
						StopSoundEffect(30); // stop fastfall death scream
	   				if ( item->current_anim_state==AS_SWANDIVE )			// Is Lara being Cool??
	   				{
	   					item->pos.x_rot = -45*ONE_DEGREE;
	   					item->goal_anim_state = AS_DIVE;
	   					AnimateLara( item );
	   					item->fallspeed = item->fallspeed*2;
	   				}
	   				else if ( item->current_anim_state==AS_FASTDIVE )
	   				{
	   					item->pos.x_rot = -85*ONE_DEGREE;
	   					item->goal_anim_state = AS_DIVE;
	   					AnimateLara( item );
	   					item->fallspeed = item->fallspeed*2;
	   				}
	   				else
	   				{
	   					item->pos.x_rot = -45*ONE_DEGREE;
	   					item->frame_number = JUMPIN_F;
	   					item->anim_number = JUMPIN_A;
	   					item->current_anim_state = AS_DIVE;
	   					item->goal_anim_state = AS_SWIM;
	   					item->fallspeed = (item->fallspeed*3)/2;
	   				}
	   				lara.torso_x_rot = lara.torso_y_rot = 0;
	   				lara.head_x_rot = lara.head_y_rot = 0;
	   				Splash( lara_item );
					}
				}
				else if (hfw > WADE_DEPTH)
				{
					lara.water_status = LARA_WADE;
   				if (!item->gravity_status)
						item->goal_anim_state = AS_STOP;
				}
			break;

			case LARA_WADE:
				camera.target_elevation = -22*ONE_DEGREE;

				if (hfw < WADE_DEPTH)
				{
					// WADE to ABOVEWATER
					lara.water_status = LARA_ABOVEWATER;
					if ( item->current_anim_state==AS_WADE )
						item->goal_anim_state = AS_RUN;
				}
				else if (hfw > SWIM_DEPTH)
				{
					// WADE to SURFACE
  					lara.water_status = LARA_SURFACE;
  					item->pos.y_pos = item->pos.y_pos+1 - hfw;
					if (item->current_anim_state==AS_BACK)
					{
   					item->frame_number = SURFTRD2BK_F;
  						item->anim_number = SURFTRD2BK_A;
  						item->goal_anim_state = AS_SURFBACK;
  						item->current_anim_state = AS_SURFBACK;
					}
					else if ( item->current_anim_state==AS_STEPRIGHT )
					{
   					item->frame_number = SURFRIGHT_F;
  						item->anim_number = SURFRIGHT_A;
  						item->goal_anim_state = AS_SURFRIGHT;
  						item->current_anim_state = AS_SURFRIGHT;
					}
					else if ( item->current_anim_state==AS_STEPLEFT )
					{
   					item->frame_number = SURFLEFT_F;
  						item->anim_number = SURFLEFT_A;
  						item->goal_anim_state = AS_SURFLEFT;
  						item->current_anim_state = AS_SURFLEFT;
					}
					else
					{
   					item->frame_number = SURFSWIM_F;
  						item->anim_number = SURFSWIM_A;
  						item->goal_anim_state = AS_SURFSWIM;
  						item->current_anim_state = AS_SURFSWIM;
					}
					item->gravity_status = 0;
  					item->fallspeed = 0;
  					lara.dive_count = 0;
  					item->pos.x_rot = lara_item->pos.z_rot = 0;
  					lara.torso_x_rot = lara.torso_y_rot = 0;
  					lara.head_x_rot = lara.head_y_rot = 0;
  					UpdateLaraRoom( item,-LARA_HITE/2 );
				}
			break;

			case LARA_SURFACE:
				if (!room_water_state)
				{
					if (hfw > WADE_DEPTH)
					{
						lara.water_status = LARA_WADE;
						item->anim_number = BREATH_A;
						item->frame_number = BREATH_F;
						item->current_anim_state = AS_STOP;
						if (item->current_anim_state==AS_SURFBACK)
							item->goal_anim_state = AS_BACK;
						else if (item->current_anim_state==AS_SURFLEFT)
							item->goal_anim_state = AS_STEPLEFT;
						else if (item->current_anim_state==AS_SURFRIGHT)
							item->goal_anim_state = AS_STEPRIGHT;
						else
							item->goal_anim_state = AS_WADE;
						AnimateItem(item);
					}
					else
					{
						lara.water_status = LARA_ABOVEWATER;					// Directly go to AboveWater Status..
						item->frame_number = FALLDOWN_F;                   // because there is no surface!!
						item->anim_number = FALLDOWN_A;
						item->goal_anim_state = AS_FORWARDJUMP;
						item->current_anim_state = AS_FORWARDJUMP;
						item->speed = item->fallspeed/4;
						item->gravity_status = 1;
					}
					item->fallspeed = 0;
					item->pos.x_rot = lara_item->pos.z_rot = 0;        		// Dont need any rotations
					lara.torso_x_rot = lara.torso_y_rot = 0;
					lara.head_x_rot = lara.head_y_rot = 0;
				}
			break;

			case LARA_UNDERWATER:
				if (!room_water_state) // could be done on hfw<something
				{
					if (wd != NO_HEIGHT && ABS(hfw) < STEP_L)
					{
						lara.water_status = LARA_SURFACE;                  // We are now going to Surface from UnderWater
						item->pos.y_pos = item->pos.y_pos+1 - hfw;
						item->frame_number = SURFTREAD_F;
						item->anim_number = SURFTREAD_A;
						item->goal_anim_state = AS_SURFTREAD;
						item->current_anim_state = AS_SURFTREAD;
						item->fallspeed = 0;
						lara.dive_count = DIVE_COUNT+1;					   // Counter before DiveAnim invoked
						item->pos.x_rot = lara_item->pos.z_rot = 0;        // Dont need any rotations
						lara.torso_x_rot = lara.torso_y_rot = 0;
						lara.head_x_rot = lara.head_y_rot = 0;
						UpdateLaraRoom( item,-LARA_HITE/2 );
		  				SoundEffect(36, &lara_item->pos, SFX_ALWAYS);
					}
					else
					{
						lara.water_status = LARA_ABOVEWATER;               // Directly go to AboveWater status
						item->frame_number = FALLDOWN_F;                   // because there is no surface!!
						item->anim_number = FALLDOWN_A;
						item->goal_anim_state = AS_FORWARDJUMP;
						item->current_anim_state = AS_FORWARDJUMP;
						item->speed = item->fallspeed/4;
						item->gravity_status = 1;
						item->fallspeed = 0;
						item->pos.x_rot = lara_item->pos.z_rot = 0;        // Dont need any rotations
						lara.torso_x_rot = lara.torso_y_rot = 0;
						lara.head_x_rot = lara.head_y_rot = 0;
					}
				}
			break;
		}
	}
//Log("After %s", waterstates[lara.water_status]);

	if ( item->hit_points<=0 )
	{
		item->hit_points = -1;
		if ( !lara.death_count )
			S_CDStop();
		lara.death_count++;

		// Lara blown to bits?
		if (lara_item->flags & ONESHOT)
		{
			lara.death_count++; // speed it along
			return;
		}
	}
	else if (GF_NoFloor && item->pos.y_pos >= GF_NoFloor)
	{
		item->hit_points = -1;
		lara.death_count = 9*30;
	}

	switch ( lara.water_status ) 			// Depending on what Lara is doing
	{                                       // call Relavant routine...
		case LARA_WADE:
		case LARA_ABOVEWATER:
			lara.air = LARA_AIR;
			LaraAboveWater( item,coll );
		break;

		case LARA_UNDERWATER:
			if ( item->hit_points>=0 ) 			// Only Modify air when alive
			{
				lara.air--;
				if ( lara.air<0 )
				{
					lara.air = -1;
					item->hit_points -= 5;
				}
			}
			LaraUnderWater( item,coll );
		break;

		case LARA_SURFACE:
			if ( item->hit_points>=0 ) 			// only modify air when alive
			{
				lara.air+=10;
				if ( lara.air>LARA_AIR )
					lara.air = LARA_AIR;
			}
			LaraSurface( item,coll );
		break;

		case LARA_CHEAT:
#if !defined(NO_FLY_CHEAT) || defined(ALWAYS_ENABLE_DOZY_CHEAT)
			if (gameflow.cheat_enable || gameflow.dozy_cheat_enabled)
				LaraCheat( item,coll );
#endif
		break;
	}
#ifdef PSX_VERSION
	psx_draw_flag = 0;
#endif

	/* Tot up how far Lara has moved since the last frame */
	savegame.distance_travelled += phd_sqrt(SQUARE(item->pos.x_pos - lara.last_pos.x) + SQUARE(item->pos.y_pos - lara.last_pos.y) + SQUARE(item->pos.z_pos - lara.last_pos.z));
	lara.last_pos.x = item->pos.x_pos;
	lara.last_pos.y = item->pos.y_pos;
	lara.last_pos.z = item->pos.z_pos;
}

/*****************************************************************************
 *		Swap All Laras Meshes with LARA_EXTRA
 ****************************************************************************/
void	LaraSwapMeshExtra( void )
{
	int		i;

	if ( objects[LARA_EXTRA].loaded )
	{
		for ( i=0;i<15;i++ )						// initialise Mesh pointers..
			lara.mesh_ptrs[i] = meshes[objects[LARA_EXTRA].mesh_index + i];
	}
}

/******************************************************************************
 *							Animate Lara
 *****************************************************************************/
void	AnimateLara( ITEM_INFO *item )
{
	int 		i;
	ANIM_STRUCT *anim;
	sint16 		*command;
	sint32 		speed;
	uint16		type, num;

	item->frame_number++;											// Inc Frame number
	anim = &anims[item->anim_number];

	/* Check for animation transitions */
	if (anim->number_changes > 0)
	{
		if (GetChange(item, anim))
		{
			anim = &anims[item->anim_number];
			item->current_anim_state = anim->current_anim_state;
		}
	}

	if (item->frame_number > anim->frame_end)						// If at end of Anim
	{
		if (anim->number_commands > 0)								// Do any Commands
		{
			command = &commands[anim->command_index];
			for (i=anim->number_commands; i>0; i--)
			{
				switch ( *(command++) )
				{
				case COMMAND_MOVE_ORIGIN:
					TranslateItem(item, (sint32)*(command), (sint32)*(command+1), (sint32)*(command+2));
					command += 3;
					break;

				case COMMAND_JUMP_VELOCITY:
					item->fallspeed = *(command++);					// Get Upward Velocity
					item->speed = *(command++);         			// Get Forward Velocity
					item->gravity_status = 1;           			// turn gravity ON
					if ( lara.calc_fallspeed )                      // If Upward velocity is  Pre-Calculated
					{
						item->fallspeed = lara.calc_fallspeed;      // then use that Value instead..
						lara.calc_fallspeed = 0;
					}
					break;

				case COMMAND_ATTACK_READY:
					if ( lara.gun_status!=LG_SPECIAL )
						lara.gun_status = LG_ARMLESS;
					break;

				case COMMAND_DEACTIVATE:
					break;

				case COMMAND_SOUND_FX:
				case COMMAND_EFFECT:
					command += 2;
					break;
				}
			}
		}

		/* Update animation information */
		item->anim_number = anim->jump_anim_num;
		item->frame_number = anim->jump_frame_num;

		anim = &anims[item->anim_number];
		item->current_anim_state = anim->current_anim_state;
	}

	/* Do any sound FX or Effect commands */
	if (anim->number_commands > 0)
	{
		command = &commands[anim->command_index];
		for (i=anim->number_commands; i>0; i--)
		{
			switch ( *(command++) )
			{
				case COMMAND_MOVE_ORIGIN:
					command += 3;
				break;

				case COMMAND_JUMP_VELOCITY:
					command += 2;
				break;

				case COMMAND_ATTACK_READY:
				case COMMAND_DEACTIVATE:
				break;

				case COMMAND_SOUND_FX:
					if ( item->frame_number==*(command) )
					{
						type = *(command+1)&0xc000;
						if ( type==SFX_LANDANDWATER ||
							(type==SFX_LANDONLY && (lara.water_surface_dist>=0 || lara.water_surface_dist==NO_HEIGHT)) ||
							(type==SFX_WATERONLY && lara.water_surface_dist<0 && lara.water_surface_dist!=NO_HEIGHT ) )
						{
							num = *(command+1)&0x3fff;
							SoundEffect( (int)num,&item->pos,SFX_ALWAYS );
						}
					}
					command += 2;
				break;

				case COMMAND_EFFECT:
					if ( item->frame_number==*(command) )
					{
						type = *(command+1)&0xc000;
						if ( type==SFX_LANDANDWATER ||
							(type==SFX_LANDONLY && (lara.water_surface_dist>=0 || lara.water_surface_dist==NO_HEIGHT)) ||
							(type==SFX_WATERONLY && lara.water_surface_dist<0) )
						{
							num = *(command+1)&0x3fff;
							(*effect_routines[(int)num])( item );
						}
					}
					command += 2;
				break;
			}
		}
	}

	if ( !item->gravity_status ) 					// Calculate absolute new velocities
	{                                               // if on the Ground...
		speed = anim->velocity;
		if ( anim->acceleration )
			speed += anim->acceleration * (item->frame_number - anim->frame_base);
		item->speed = (sint16)(speed >> 16);
	}
	else                                            // If gravity ON
	{                                               // do Up/down movement
		speed = anim->velocity + anim->acceleration * (item->frame_number - anim->frame_base - 1);
		item->speed -= (sint16)(speed>>16);
		speed += anim->acceleration;
		item->speed += (sint16)(speed>>16);

		item->fallspeed += (item->fallspeed<FASTFALL_SPEED) ? GRAVITY : 1;

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


/*****************************************************************************
 *				Use Item from Inventory...
 ****************************************************************************/
void	UseItem( sint16 object_num )
{
	if ( object_num<0 || object_num>=NUMBER_OBJECTS )
		return;
	switch ( object_num )
	{
		case GUN_ITEM:
		case GUN_OPTION:
			lara.request_gun_type = LG_PISTOLS;
		break;

		case MAGNUM_ITEM:
		case MAGNUM_OPTION:
			lara.request_gun_type = LG_MAGNUMS;
		break;

		case UZI_ITEM:
		case UZI_OPTION:
			lara.request_gun_type = LG_UZIS;
		break;

		case SHOTGUN_ITEM:
		case SHOTGUN_OPTION:
			lara.request_gun_type = LG_SHOTGUN;
		break;

		case HARPOON_ITEM:
		case HARPOON_OPTION:
			lara.request_gun_type = LG_HARPOON;
		break;

		case M16_ITEM:
		case M16_OPTION:
			lara.request_gun_type = LG_M16;
		break;

		case ROCKET_GUN_ITEM:
		case ROCKET_OPTION:
			lara.request_gun_type = LG_ROCKET;
		break;

		case FLAREBOX_ITEM:
		case FLAREBOX_OPTION:
			lara.request_gun_type = LG_FLARE;
//			Inv_RemoveItem( FLAREBOX_ITEM );
		break;

		case MEDI_ITEM:
		case MEDI_OPTION:
			if ( lara_item->hit_points>0 && lara_item->hit_points<LARA_HITPOINTS )
			{
				lara_item->hit_points += LARA_HITPOINTS/2;
				if ( lara_item->hit_points>LARA_HITPOINTS )
					lara_item->hit_points = LARA_HITPOINTS;
				Inv_RemoveItem( MEDI_ITEM );
		    	SoundEffect(116, NULL, SFX_ALWAYS);
				savegame.health_used++;
			}
		break;

		case BIGMEDI_ITEM:
		case BIGMEDI_OPTION:
			if ( lara_item->hit_points>0 && lara_item->hit_points<LARA_HITPOINTS )
			{
				lara_item->hit_points += LARA_HITPOINTS;
				if ( lara_item->hit_points>LARA_HITPOINTS )
					lara_item->hit_points = LARA_HITPOINTS;
				Inv_RemoveItem( BIGMEDI_ITEM );
		    	SoundEffect(116, NULL, SFX_ALWAYS);
				savegame.health_used+=2;
			}
		break;

		default:
		break;
	}
}

/*******************************************************************************
 *******************************************************************************
 *					Control Mode For Cheating....
 *******************************************************************************
 ******************************************************************************/
void LaraCheatGetStuff(void)
{
	int i;

	Inv_AddItem( HARPOON_ITEM );
	Inv_AddItem( M16_ITEM );
	Inv_AddItem( ROCKET_GUN_ITEM );
	Inv_AddItem( SHOTGUN_ITEM );
	Inv_AddItem( UZI_ITEM );
	Inv_AddItem( MAGNUM_ITEM );
	Inv_AddItem( GUN_ITEM );
	for (i=0;i<10;i++)
	{
		Inv_AddItem( FLAREBOX_ITEM );
		Inv_AddItem( MEDI_ITEM );
		Inv_AddItem( BIGMEDI_ITEM );
	}
/*	Inv_AddItem( KEY_ITEM1 );
	Inv_AddItem( KEY_ITEM2 );
	Inv_AddItem( KEY_ITEM3 );
	Inv_AddItem( KEY_ITEM4 );
	Inv_AddItem( PUZZLE_ITEM1 );
	Inv_AddItem( PUZZLE_ITEM2 );
	Inv_AddItem( PUZZLE_ITEM3 );
	Inv_AddItem( PUZZLE_ITEM4 );
	Inv_AddItem( PICKUP_ITEM1 );
	Inv_AddItem( PICKUP_ITEM2 );
*/

	lara.magnums.ammo = MAGNUM_AMMO_CLIP*50;
	lara.uzis.ammo = UZI_AMMO_CLIP*50;
	lara.shotgun.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.harpoon.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.m16.ammo = SHOTGUN_AMMO_CLIP*50;
	lara.rocket.ammo = SHOTGUN_AMMO_CLIP*50;
}

#if !defined(NO_FLY_CHEAT) || defined(ALWAYS_ENABLE_DOZY_CHEAT)
sint16 cheat_hit_points;

void	LaraCheat( ITEM_INFO *item, COLL_INFO *coll )
{
	lara_item->hit_points = LARA_HITPOINTS;

	LaraUnderWater( item,coll );
	if ( input&IN_SLOW && !(input&IN_LOOK) )
	{
		lara.water_status = LARA_ABOVEWATER;			// Return to Normal Mode...
		item->frame_number = STOP_F;
		item->anim_number = STOP_A;
		item->pos.x_rot = item->pos.z_rot = 0;
		lara.torso_x_rot = lara.torso_y_rot = 0;
		lara.head_x_rot = lara.head_y_rot = 0;
		lara.gun_status = LG_ARMLESS;
		LaraInitialiseMeshes(1);
		lara.mesh_effects = 0;
		lara_item->hit_points = cheat_hit_points;
	}
}

void	LaraCheatyBits( void )
{
	if (!gameflow.cheat_enable && !gameflow.dozy_cheat_enabled)
		return;
	// D gets you health and weapons
	if (input & IN_D)
	{
		LaraCheatGetStuff();
		lara_item->hit_points = LARA_HITPOINTS;
	}

	// C just allows you to fly around
	if ( input&IN_C )
	{
		lara_item->pos.y_pos -= STEP_L/2;
		if ( lara.water_status!=LARA_CHEAT )
		{
			lara.water_status = LARA_CHEAT;
			lara_item->frame_number = SWIMGLIDE_F;
			lara_item->anim_number = SWIMGLIDE_A;
			lara_item->current_anim_state = AS_SWIM;
			lara_item->goal_anim_state = AS_SWIM;
			lara_item->gravity_status = 0;
			lara_item->pos.x_rot = 30*ONE_DEGREE;
			lara_item->fallspeed = 30;
			lara.air = LARA_AIR;
			lara.death_count = 0;
			lara.torso_x_rot = lara.torso_y_rot = 0;
			lara.head_x_rot = lara.head_y_rot = 0;
			lara.mesh_effects = 0x7fff;

			cheat_hit_points = lara_item->hit_points;
		}
	}
}
#endif


/******************************************************************************
 *			Control Lara Extra Used for Deaths etc etc
 *****************************************************************************/
void	ControlLaraExtra( sint16 item_num )
{
		AnimateItem(&items[item_num]);
}


/******************************************************************************
 *				initialise lara dummy routine
 *****************************************************************************/
#ifdef PSX_VERSION
	extern sint32	gym_save_x, gym_save_y, gym_save_z, gym_save_r, gym_save_yr;
#endif

void	InitialiseLaraLoad( sint16 item_num )
{
	lara.item_number = item_num;
	lara_item = &items[item_num];
#ifdef PSX_VERSION
	if (CurrentLevel==LV_GYM)
	{
		gym_save_x = lara_item->pos.x_pos;
		gym_save_y = lara_item->pos.y_pos;
		gym_save_z = lara_item->pos.z_pos;
		gym_save_yr = lara_item->pos.y_rot;
		gym_save_r = lara_item->room_number;
	}
#endif

#ifdef PC_VERSION
	Log(LT_Info,"Lara Loaded!!!");
#endif
}


/******************************************************************************
 *			Initialise Lara for this Particular Level
 *****************************************************************************/
void	InitialiseLara( int type )
{
	ITEM_INFO	*item;
	int	i;

	item = lara_item;
	item->data = (void *)&lara;
	item->collidable = 0;
	item->hit_points = LARA_HITPOINTS;

	lara.calc_fallspeed = 0;
	lara.climb_status = 0;
	lara.pose_count = 0;
	lara.hit_frame = 0;
	lara.hit_direction = -1;
	lara.air = LARA_AIR;						// Start with full Oxygen please
	lara.dive_count = 0;
	lara.death_count = 0;
	lara.current_active = 0;
	lara.spaz_effect_count = 0;
	lara.flare_age = 0;
	lara.skidoo = NO_ITEM;
	lara.weapon_item = NO_ITEM;
	lara.back_gun = 0;
	lara.flare_frame = 0;
	lara.flare_control_left = lara.flare_control_right = 0;
	lara.extra_anim = 0;
	lara.look = 1;
	lara.burn = 0;
	lara.water_surface_dist = 100;
	lara.last_pos.x = item->pos.x_pos;
	lara.last_pos.y = item->pos.y_pos;
	lara.last_pos.z = item->pos.z_pos;
	lara.spaz_effect = NULL;
	lara.mesh_effects = 0;
	lara.target = NULL;
	lara.turn_rate = 0;
	lara.move_angle = 0;
	lara.head_x_rot = lara.head_y_rot = lara.head_z_rot = 0;
	lara.torso_x_rot = lara.torso_y_rot = lara.torso_z_rot = 0;
	lara.left_arm.flash_gun = lara.right_arm.flash_gun = 0;
	lara.left_arm.lock = lara.right_arm.lock = 0;
	lara.creature = NULL;

	/* Setup initial Animation status according to where she is */
	if (type==IL_NORMAL && GF_LaraStartAnim)
	{
		lara.water_status = LARA_ABOVEWATER;
		lara.gun_status = LG_HANDSBUSY;
		item->anim_number = objects[LARA_EXTRA].anim_index;
		item->frame_number = anims[item->anim_number].frame_base;
		item->current_anim_state = EXTRA_BREATH;
		item->goal_anim_state = (sint16)GF_LaraStartAnim;
		AnimateLara(item);
		lara.extra_anim = 1;

		/* Do cinematic camera */
		camera.type = CINEMATIC_CAMERA;
		cine_frame = 0;
		S_MemCpy(&cinematic_pos, &item->pos, sizeof(PHD_3DPOS));
	}
	else if (room[item->room_number].flags & UNDERWATER)
	{
		lara.water_status = LARA_UNDERWATER;
		item->fallspeed = 0;
		item->goal_anim_state = AS_TREAD;
		item->current_anim_state = AS_TREAD;
		item->anim_number = TREAD_A;
		item->frame_number = TREAD_F;

	}
	else
	{
		lara.water_status = LARA_ABOVEWATER;
		item->goal_anim_state = AS_STOP;
		item->current_anim_state = AS_STOP;
		item->anim_number = STOP_A;
		item->frame_number = STOP_F;
	}

	if (type==IL_CUTSCENE)
	{
		for ( i=0;i<15;i++ )
			lara.mesh_ptrs[i] = meshes[objects[LARA].mesh_index + i];
		lara.mesh_ptrs[THIGH_L] = meshes[objects[PISTOLS].mesh_index + THIGH_L];
		lara.mesh_ptrs[THIGH_R] = meshes[objects[PISTOLS].mesh_index + THIGH_R];
		lara.gun_status = LG_ARMLESS;
	}
	else
	{
		InitialiseLaraInventory(CurrentLevel);
	}

#ifdef PC_VERSION
	Log(LT_Info,"Lara Initialised!!!");
#endif
}


void InitialiseLaraInventory(int level_number)
{
	int i, ammo;
	START_INFO *start;

#if defined(PSX_VERSION) && defined(GAMEDEBUG)
	printf(__FUNCTION__"\n");
#endif

	Inv_RemoveAllItems();						// Remove all old items from Inventry...

	start = &savegame.start[level_number];

	if ( GF_RemoveWeapons )
	{
		start->got_pistols = start->got_magnums = start->got_uzis = start->got_shotgun = start->got_m16 = start->got_rocket = start->got_harpoon = 0;
		start->gun_type = LG_UNARMED;
		start->gun_status = LG_ARMLESS;
		GF_RemoveWeapons = 0;
	}
	if ( GF_RemoveAmmo )
	{
		start->pistol_ammo = start->magnum_ammo = start->uzi_ammo = start->shotgun_ammo = start->harpoon_ammo = start->rocket_ammo = start->m16_ammo = start->harpoon_ammo = start->rocket_ammo = 0;
		start->num_medis = start->num_big_medis = start->num_flares = 0;
		GF_RemoveAmmo = 0;
	}


	Inv_AddItem( MAP_CLOSED );
	/* Initialise Pistols Now got Infinite Ammo */
	lara.pistols.ammo = 1000;
	if ( start->got_pistols )
		Inv_AddItem( GUN_ITEM );

	/* Initialise Magnums */
	if ( start->got_magnums )
	{
		Inv_AddItem( MAGNUM_ITEM );
		lara.magnums.ammo = start->magnum_ammo;
		GlobalItemReplace( MAGNUM_ITEM, MAG_AMMO_ITEM );
	}
	else
	{
		ammo = start->magnum_ammo/MAGNUM_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( MAG_AMMO_ITEM );
		lara.magnums.ammo = 0;
	}

	/* Initialise Uzis */
	if ( start->got_uzis )
	{
		Inv_AddItem( UZI_ITEM );
		lara.uzis.ammo = start->uzi_ammo;
		GlobalItemReplace( UZI_ITEM, UZI_AMMO_ITEM );
	}
	else
	{
		ammo = start->uzi_ammo/UZI_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( UZI_AMMO_ITEM );
		lara.uzis.ammo = 0;
	}

	/* Initialise Shotgun */
	if ( start->got_shotgun )
	{
		Inv_AddItem( SHOTGUN_ITEM );
		lara.shotgun.ammo = start->shotgun_ammo;
		GlobalItemReplace( SHOTGUN_ITEM, SG_AMMO_ITEM );
	}
	else
	{
		ammo = start->shotgun_ammo/SHOTGUN_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( SG_AMMO_ITEM );
		lara.shotgun.ammo = 0;
	}

	/* Initialise Rocket */
	if ( start->got_rocket )
	{
		Inv_AddItem( ROCKET_GUN_ITEM );
		lara.rocket.ammo = start->rocket_ammo;
		GlobalItemReplace( ROCKET_GUN_ITEM, ROCKET_AMMO_ITEM );
	}
	else
	{
		ammo = start->rocket_ammo/ROCKET_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( ROCKET_AMMO_ITEM );
		lara.rocket.ammo = 0;
	}

	/* Initialise M16 */
	if ( start->got_m16 )
	{
		Inv_AddItem( M16_ITEM );
		lara.m16.ammo = start->m16_ammo;
		GlobalItemReplace( M16_ITEM, M16_AMMO_ITEM );
	}
	else
	{
		ammo = start->m16_ammo/M16_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( M16_AMMO_ITEM );
		lara.m16.ammo = 0;
	}

	/* Initialise Harpoon */
	if ( start->got_harpoon )
	{
		Inv_AddItem( HARPOON_ITEM );
		lara.harpoon.ammo = start->harpoon_ammo;
		GlobalItemReplace( HARPOON_ITEM, HARPOON_AMMO_ITEM );
	}
	else
	{
		ammo = start->harpoon_ammo/HARPOON_AMMO_QTY;
		for ( i=0;i<ammo;i++ )
			Inv_AddItem( HARPOON_AMMO_ITEM );
		lara.harpoon.ammo = 0;
	}

	/* Initialise Flares */
	for (i=start->num_flares; i>0;i--)
		Inv_AddItem( FLARE_ITEM );

	for (i=start->num_medis; i>0; i--)
		Inv_AddItem( MEDI_ITEM );

	for (i=start->num_big_medis; i>0; i--)
		Inv_AddItem( BIGMEDI_ITEM );

	//lara.gun_status = start->gun_status;
	lara.gun_status = LG_ARMLESS;
	lara.request_gun_type = lara.gun_type = lara.last_gun_type = start->gun_type;	// Initialise Current Weapon...
	Log(LT_Info,"Lara Gun type = %d",lara.gun_type);
	LaraInitialiseMeshes(level_number);                     	// Initialise Lara Meshes..
	InitialiseNewWeapon();
#ifdef INVINCABLE_LARA
		Inv_AddItem( HARPOON_ITEM );
		Inv_AddItem( M16_ITEM );
		Inv_AddItem( ROCKET_GUN_ITEM );
		Inv_AddItem( SHOTGUN_ITEM );
		Inv_AddItem( UZI_ITEM );
		Inv_AddItem( MAGNUM_ITEM );
		Inv_AddItem( GUN_ITEM );
		for (i=0;i<50;i++)
			Inv_AddItem( FLAREBOX_ITEM );
		lara.pistols.ammo = GUN_AMMO_CLIP*50;
		lara.magnums.ammo = MAGNUM_AMMO_CLIP*50;
		lara.uzis.ammo = UZI_AMMO_CLIP*50;
		lara.shotgun.ammo = SHOTGUN_AMMO_CLIP*50;
		lara.harpoon.ammo = HARPOON_AMMO_CLIP*50;
		lara.m16.ammo = M16_AMMO_CLIP*50;
		lara.rocket.ammo = ROCKET_AMMO_CLIP*50;
#endif
}

/*****************************************************************************
 *			Initialise Laras Normal Meshes
 ****************************************************************************/
void	LaraInitialiseMeshes( int level_number )
{
	/* Gav: modified this to use START_INFO to make decisions */
	int i;
	START_INFO *start;

//	level_number = CurrentLevel;

	start = &savegame.start[level_number];

	/* Start by Making all Lara Meshes as Default */
	for ( i=0;i<15;i++ )
		lara.mesh_ptrs[i] = meshes[objects[LARA].mesh_index + i];

	/* Now Initialise THIGH Holsters With Guns or Not */
	switch (start->gun_type)
	{
	case LG_UNARMED:
		break;

	case LG_MAGNUMS:
		lara.mesh_ptrs[THIGH_L] = meshes[objects[MAGNUM].mesh_index + THIGH_L];
		lara.mesh_ptrs[THIGH_R] = meshes[objects[MAGNUM].mesh_index + THIGH_R];
		break;

	case LG_UZIS:
		lara.mesh_ptrs[THIGH_L] = meshes[objects[UZI].mesh_index + THIGH_L];
		lara.mesh_ptrs[THIGH_R] = meshes[objects[UZI].mesh_index + THIGH_R];
		break;

	default:
		lara.mesh_ptrs[THIGH_L] = meshes[objects[PISTOLS].mesh_index + THIGH_L];
		lara.mesh_ptrs[THIGH_R] = meshes[objects[PISTOLS].mesh_index + THIGH_R];
		break;
	}

	if (start->gun_type == LG_FLARE)
		lara.mesh_ptrs[HAND_L] = meshes[objects[FLARE].mesh_index + HAND_L];

	// Decide on back weapon (if any)
	switch (start->gun_type)
	{
	case LG_M16:
		lara.back_gun = M16;
		break;

	case LG_HARPOON:
		lara.back_gun = HARPOON_GUN;
		break;

	case LG_ROCKET:
		lara.back_gun = ROCKET_GUN;
		break;

	default:
		if (start->got_shotgun)
			lara.back_gun = SHOTGUN;
		else if (start->got_m16)
			lara.back_gun = M16;
		else if (start->got_rocket)
			lara.back_gun = ROCKET_GUN;
		else if (start->got_harpoon)
			lara.back_gun = HARPOON_GUN;
	}
}

/***************************************************************************
 *  Jump Tables for Lara Control depending on current anim state....
 ***************************************************************************/
void	(*lara_control_routines[])() = {
		lara_as_walk,
		lara_as_run,
		lara_as_stop,
		lara_as_forwardjump,
		lara_as_pose,
		lara_as_fastback,
		lara_as_turn_r,
		lara_as_turn_l,
		lara_as_death,
		lara_as_fastfall,
		lara_as_hang,
		lara_as_reach,
		lara_as_splat,
		lara_as_tread,
		lara_as_land,
		lara_as_compress,
		lara_as_back,
		lara_as_swim,
		lara_as_glide,
		lara_as_null,
		lara_as_fastturn,
		lara_as_stepright,
		lara_as_stepleft,
		lara_as_roll2,
		lara_as_slide,
		lara_as_backjump,
		lara_as_rightjump,
		lara_as_leftjump,
		lara_as_upjump,
		lara_as_fallback,
		lara_as_hangleft,
		lara_as_hangright,
		lara_as_slideback,
		lara_as_surftread,
		lara_as_surfswim,
		lara_as_dive,
		lara_as_pushblock,
		lara_as_pullblock,
		lara_as_ppready,
		lara_as_pickup,
		lara_as_switchon,
		lara_as_switchoff,
		lara_as_usekey,
		lara_as_usepuzzle,
		lara_as_uwdeath,
		lara_as_roll,
		lara_as_special,
		lara_as_surfback,
		lara_as_surfleft,
		lara_as_surfright,
		lara_as_usemidas,
		lara_as_diemidas,
		lara_as_swandive,
		lara_as_fastdive,
		lara_as_gymnast,
		lara_as_waterout,
		lara_as_climbstnc,
		lara_as_climbing,
		lara_as_climbleft,
		lara_as_climbend,
		lara_as_climbright,
		lara_as_climbdown,
		lara_as_laratest1,
		lara_as_laratest2,
		lara_as_laratest3,
		lara_as_wade,
		lara_as_waterroll,
		lara_as_pickupflare,
		lara_as_twist,
		lara_as_kick,
		lara_as_deathslide
};

void (*extra_control_routines[])() = {
		extra_as_breath,
		extra_as_plunger,
		extra_as_yetikill,
		extra_as_sharkkill,
		extra_as_airlock,
		extra_as_gongbong,
		extra_as_dinokill,
		extra_as_pulldagger,
		extra_as_startanim,
		extra_as_starthouse,
		extra_as_finalanim
};

void	(*lara_collision_routines[])() = {
		lara_col_walk,
		lara_col_run,
		lara_col_stop,
		lara_col_forwardjump,
		lara_col_pose,
		lara_col_fastback,
		lara_col_turn_r,
		lara_col_turn_l,
		lara_col_death,
		lara_col_fastfall,
		lara_col_hang,
		lara_col_reach,
		lara_col_splat,
		lara_col_tread,
		lara_col_land,
		lara_col_compress,
		lara_col_back,
		lara_col_swim,
		lara_col_glide,
		lara_col_null,
		lara_col_fastturn,
		lara_col_stepright,
		lara_col_stepleft,
		lara_col_roll2,
		lara_col_slide,
		lara_col_backjump,
		lara_col_rightjump,
		lara_col_leftjump,
		lara_col_upjump,
		lara_col_fallback,
		lara_col_hangleft,
		lara_col_hangright,
		lara_col_slideback,
		lara_col_surftread,
		lara_col_surfswim,
		lara_col_dive,
		lara_col_pushblock,
		lara_col_pullblock,
		lara_col_ppready,
		lara_col_pickup,
		lara_col_switchon,
		lara_col_switchoff,
		lara_col_usekey,
		lara_col_usepuzzle,
		lara_col_uwdeath,
		lara_col_roll,
		lara_col_special,
		lara_col_surfback,
		lara_col_surfleft,
		lara_col_surfright,
		lara_col_usemidas,
		lara_col_diemidas,
		lara_col_swandive,
		lara_col_fastdive,
		lara_col_gymnast,
		lara_col_waterout,
		lara_col_climbstnc,
		lara_col_climbing,
		lara_col_climbleft,
		lara_col_climbend,
		lara_col_climbright,
		lara_col_climbdown,
		lara_col_laratest1,
		lara_col_laratest2,
		lara_col_laratest3,
		lara_col_wade,
		lara_col_waterroll,
		lara_col_pickup,
		lara_col_twist,
		lara_col_kick,
		lara_col_deathslide
};

