/***********************************************************************************************************/
/*                                                                                                         */
/* Lara Firing Control                                                                                     */
/*                                                                                                         */
/***********************************************************************************************************/

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

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

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "camera.h"
#include "control.h"
#include "input.h"
#include "sound.h"
#include "invfunc.h"
#include "inventry.h"
#include "savegame.h"
#include "sphere.h"
#include "traps.h"
#include "lot.h"
#include "laraflar.h"
#include "lara1gun.h"
#include "lara2gun.h"

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

#define PISTOL_DAMAGE	1		// Everyhing relates to pistol damage

#define PISTOL_LOCK_YMIN	-60*ONE_DEGREE
#define PISTOL_LOCK_YMAX	+60*ONE_DEGREE
#define PISTOL_LOCK_XMIN	-60*ONE_DEGREE
#define PISTOL_LOCK_XMAX	+60*ONE_DEGREE

#define PISTOL_LARM_YMIN	-170*ONE_DEGREE
#define PISTOL_LARM_YMAX	+60*ONE_DEGREE
#define PISTOL_LARM_XMIN	-80*ONE_DEGREE
#define PISTOL_LARM_XMAX	+80*ONE_DEGREE

#define PISTOL_RARM_YMIN	-60*ONE_DEGREE
#define PISTOL_RARM_YMAX	+170*ONE_DEGREE
#define PISTOL_RARM_XMIN	-80*ONE_DEGREE
#define PISTOL_RARM_XMAX	+80*ONE_DEGREE

#define SHOTGUN_LOCK_YMIN	-60*ONE_DEGREE
#define SHOTGUN_LOCK_YMAX	+60*ONE_DEGREE
#define SHOTGUN_LOCK_XMIN	-55*ONE_DEGREE
#define SHOTGUN_LOCK_XMAX	+55*ONE_DEGREE

#define SHOTGUN_LARM_YMIN	-80*ONE_DEGREE
#define SHOTGUN_LARM_YMAX	+80*ONE_DEGREE
#define SHOTGUN_LARM_XMIN	-65*ONE_DEGREE
#define SHOTGUN_LARM_XMAX	+65*ONE_DEGREE

#define SHOTGUN_RARM_YMIN	-80*ONE_DEGREE
#define SHOTGUN_RARM_YMAX	+80*ONE_DEGREE
#define SHOTGUN_RARM_XMIN	-65*ONE_DEGREE
#define SHOTGUN_RARM_XMAX	+65*ONE_DEGREE

#define M16_LOCK_YMIN -60*ONE_DEGREE
#define M16_LOCK_YMAX +60*ONE_DEGREE
#define M16_LOCK_XMIN -55*ONE_DEGREE
#define M16_LOCK_XMAX +55*ONE_DEGREE

#define M16_LARM_YMIN -80*ONE_DEGREE
#define M16_LARM_YMAX +80*ONE_DEGREE
#define M16_LARM_XMIN -65*ONE_DEGREE
#define M16_LARM_XMAX +65*ONE_DEGREE

#define M16_RARM_YMIN -80*ONE_DEGREE
#define M16_RARM_YMAX +80*ONE_DEGREE
#define M16_RARM_XMIN -65*ONE_DEGREE
#define M16_RARM_XMAX +65*ONE_DEGREE

#define ROCKET_LOCK_YMIN	-60*ONE_DEGREE
#define ROCKET_LOCK_YMAX	+60*ONE_DEGREE
#define ROCKET_LOCK_XMIN	-55*ONE_DEGREE
#define ROCKET_LOCK_XMAX	+55*ONE_DEGREE

#define ROCKET_LARM_YMIN	-80*ONE_DEGREE
#define ROCKET_LARM_YMAX	+80*ONE_DEGREE
#define ROCKET_LARM_XMIN	-65*ONE_DEGREE
#define ROCKET_LARM_XMAX	+65*ONE_DEGREE

#define ROCKET_RARM_YMIN	-80*ONE_DEGREE
#define ROCKET_RARM_YMAX	+80*ONE_DEGREE
#define ROCKET_RARM_XMIN	-65*ONE_DEGREE
#define ROCKET_RARM_XMAX	+65*ONE_DEGREE

#define GRENADE_LOCK_YMIN	-60*ONE_DEGREE
#define GRENADE_LOCK_YMAX	+60*ONE_DEGREE
#define GRENADE_LOCK_XMIN	-55*ONE_DEGREE
#define GRENADE_LOCK_XMAX	+55*ONE_DEGREE

#define GRENADE_LARM_YMIN	-80*ONE_DEGREE
#define GRENADE_LARM_YMAX	+80*ONE_DEGREE
#define GRENADE_LARM_XMIN	-65*ONE_DEGREE
#define GRENADE_LARM_XMAX	+65*ONE_DEGREE

#define GRENADE_RARM_YMIN	-80*ONE_DEGREE
#define GRENADE_RARM_YMAX	+80*ONE_DEGREE
#define GRENADE_RARM_XMIN	-65*ONE_DEGREE
#define GRENADE_RARM_XMAX	+65*ONE_DEGREE

#define HARPOON_LOCK_YMIN -60*ONE_DEGREE
#define HARPOON_LOCK_YMAX +60*ONE_DEGREE
#define HARPOON_LOCK_XMIN -65*ONE_DEGREE
#define HARPOON_LOCK_XMAX +65*ONE_DEGREE

#define HARPOON_LARM_YMIN -80*ONE_DEGREE
#define HARPOON_LARM_YMAX +80*ONE_DEGREE
#define HARPOON_LARM_XMIN -75*ONE_DEGREE
#define HARPOON_LARM_XMAX +75*ONE_DEGREE

#define HARPOON_RARM_YMIN -80*ONE_DEGREE
#define HARPOON_RARM_YMAX +80*ONE_DEGREE
#define HARPOON_RARM_XMIN -75*ONE_DEGREE
#define HARPOON_RARM_XMAX +75*ONE_DEGREE

#define SKID_LOCK_YMIN -30*ONE_DEGREE
#define SKID_LOCK_YMAX +30*ONE_DEGREE
#define SKID_LOCK_XMIN -55*ONE_DEGREE
#define SKID_LOCK_XMAX +55*ONE_DEGREE

#define SKID_LARM_YMIN -30*ONE_DEGREE
#define SKID_LARM_YMAX +30*ONE_DEGREE
#define SKID_LARM_XMIN -55*ONE_DEGREE
#define SKID_LARM_XMAX +55*ONE_DEGREE

#define SKID_RARM_YMIN -30*ONE_DEGREE
#define SKID_RARM_YMAX +30*ONE_DEGREE
#define SKID_RARM_XMIN -55*ONE_DEGREE
#define SKID_RARM_XMAX +55*ONE_DEGREE

/*---------------------------------------------------------------------------
 *	Globals
\*--------------------------------------------------------------------------*/

WEAPON_INFO weapons[NUM_WEAPONS] = {
	{	// NULL
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
	},{	// PISTOLS
		{PISTOL_LOCK_YMIN,PISTOL_LOCK_YMAX,PISTOL_LOCK_XMIN,PISTOL_LOCK_XMAX},
		{PISTOL_LARM_YMIN,PISTOL_LARM_YMAX,PISTOL_LARM_XMIN,PISTOL_LARM_XMAX},
		{PISTOL_RARM_YMIN,PISTOL_RARM_YMAX,PISTOL_RARM_XMIN,PISTOL_RARM_XMAX},
		10*ONE_DEGREE,		// aiming speed
		8*ONE_DEGREE,		// randomness shot_accuracy
		650,				// gun height
		PISTOL_DAMAGE,		// damage
		8*WALL_L,			// targettable distance
		9,				// Recoil frame for pistol-type guns
		3,				// How long GunFlash lasts for
		8,				// Sample Number for firing
	},{	// MAGNUMS
		{PISTOL_LOCK_YMIN,PISTOL_LOCK_YMAX,PISTOL_LOCK_XMIN,PISTOL_LOCK_XMAX},
		{PISTOL_LARM_YMIN,PISTOL_LARM_YMAX,PISTOL_LARM_XMIN,PISTOL_LARM_XMAX},
		{PISTOL_RARM_YMIN,PISTOL_RARM_YMAX,PISTOL_RARM_XMIN,PISTOL_RARM_XMAX},
		10*ONE_DEGREE,
		8*ONE_DEGREE,
		650,
		2*PISTOL_DAMAGE,
		8*WALL_L,
		9,
		3,
		21,
	},{	// UZIS
		{PISTOL_LOCK_YMIN,PISTOL_LOCK_YMAX,PISTOL_LOCK_XMIN,PISTOL_LOCK_XMAX},
		{PISTOL_LARM_YMIN,PISTOL_LARM_YMAX,PISTOL_LARM_XMIN,PISTOL_LARM_XMAX},
		{PISTOL_RARM_YMIN,PISTOL_RARM_YMAX,PISTOL_RARM_XMIN,PISTOL_RARM_XMAX},
		10*ONE_DEGREE,                        // aiming speed
		8*ONE_DEGREE,                         // randomness
		650,                                  // gun height
		1*PISTOL_DAMAGE,                      // damage
		8*WALL_L,							    // targettable distance
		3,									// Recoil frame for pistol-type guns
		3,									// How long GunFlash lasts for
		43,                                   // Sample Number for firing
	},{	// SHOTGUN
		{SHOTGUN_LOCK_YMIN,SHOTGUN_LOCK_YMAX,SHOTGUN_LOCK_XMIN,SHOTGUN_LOCK_XMAX},
		{SHOTGUN_LARM_YMIN,SHOTGUN_LARM_YMAX,SHOTGUN_LARM_XMIN,SHOTGUN_LARM_XMAX},
		{SHOTGUN_RARM_YMIN,SHOTGUN_RARM_YMAX,SHOTGUN_RARM_XMIN,SHOTGUN_RARM_XMAX},
		10*ONE_DEGREE,                     	// aiming speed
		0,			                     	// randomness ( Zero for Shotgun As Pellets are Randomised )
		500,                              	// gun height
		3*PISTOL_DAMAGE,                     	// damage; was 4x for Tomb1
		8*WALL_L,								// targettable distance
		9,									// Recoil frame for pistol-type guns
		3,									// How long GunFlash lasts for
		45,                                   // Sample Number for firing
	},{	// M16
		{M16_LOCK_YMIN,M16_LOCK_YMAX,M16_LOCK_XMIN,M16_LOCK_XMAX},							// M16
		{M16_LARM_YMIN,M16_LARM_YMAX,M16_LARM_XMIN,M16_LARM_XMAX},
		{M16_RARM_YMIN,M16_RARM_YMAX,M16_RARM_XMIN,M16_RARM_XMAX},
		10*ONE_DEGREE, // aiming speed
		4*ONE_DEGREE,  // randomness (not much for M16)
		500,
		3*PISTOL_DAMAGE, // rapid fire though
		12*WALL_L,     // long range weapon
		0,
		3,
		0,
	},{	// ROCKET LAUNCHER
		{ROCKET_LOCK_YMIN,ROCKET_LOCK_YMAX,ROCKET_LOCK_XMIN,ROCKET_LOCK_XMAX},							// ROCKET
		{ROCKET_LARM_YMIN,ROCKET_LARM_YMAX,ROCKET_LARM_XMIN,ROCKET_LARM_XMAX},
		{ROCKET_RARM_YMIN,ROCKET_RARM_YMAX,ROCKET_RARM_XMIN,ROCKET_RARM_XMAX},
		10*ONE_DEGREE, // aiming speed
		8*ONE_DEGREE,  // randomness
		500,
		30*PISTOL_DAMAGE, // big mother!
		8*WALL_L,
		0,
		2,
		0,
	},{	// GRENADE LAUNCHER
		{GRENADE_LOCK_YMIN,GRENADE_LOCK_YMAX,GRENADE_LOCK_XMIN,GRENADE_LOCK_XMAX},							// GRENADE
		{GRENADE_LARM_YMIN,GRENADE_LARM_YMAX,GRENADE_LARM_XMIN,GRENADE_LARM_XMAX},
		{GRENADE_RARM_YMIN,GRENADE_RARM_YMAX,GRENADE_RARM_XMIN,GRENADE_RARM_XMAX},
		10*ONE_DEGREE, // aiming speed
		8*ONE_DEGREE,  // randomness
		500,
		20*PISTOL_DAMAGE, // big mother!
		8*WALL_L,
		0,
		2,
		0,
	},{	// HARPOON
		{HARPOON_LOCK_YMIN,HARPOON_LOCK_YMAX,HARPOON_LOCK_XMIN,HARPOON_LOCK_XMAX},							// HARPOON
		{HARPOON_LARM_YMIN,HARPOON_LARM_YMAX,HARPOON_LARM_XMIN,HARPOON_LARM_XMAX},
		{HARPOON_RARM_YMIN,HARPOON_RARM_YMAX,HARPOON_RARM_XMIN,HARPOON_RARM_XMAX},
		10*ONE_DEGREE, // aiming speed
		8*ONE_DEGREE,  // randomness
		500,
		4*PISTOL_DAMAGE, // slow firing (damage halved out of water)
		8*WALL_L,
		0,
		2,
		0,
	},{	// FLARE
		{0,0,0,0},
		{0,0,0,0},
		{0,0,0,0},
		0,
		0,
		0,
		0,
		0,
		0,
		0,
		0,
	},{	// SKIDOO GUN ?
		{SKID_LOCK_YMIN,SKID_LOCK_YMAX,SKID_LOCK_XMIN,SKID_LOCK_XMAX},							// SKIDOO GUNS
		{SKID_LARM_YMIN,SKID_LARM_YMAX,SKID_LARM_XMIN,SKID_LARM_XMAX},
		{SKID_RARM_YMIN,SKID_RARM_YMAX,SKID_RARM_XMIN,SKID_RARM_XMAX},
		10*ONE_DEGREE, // aiming speed
		8*ONE_DEGREE,  // randomness
		400,
		3*PISTOL_DAMAGE, // like uzis
		8*WALL_L,
		0,
		2,
		43,
	}
};

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

static sint16 HoldStates[] = {
	AS_WALK,
	AS_STOP,
	AS_POSE,
	AS_TURN_R,
	AS_TURN_L,
	AS_BACK,
	AS_FASTTURN,
	AS_STEPLEFT,
	AS_STEPRIGHT,
	AS_WADE,
	AS_PICKUP,
	AS_SWITCHON,
	AS_SWITCHOFF,
	-1
};

/*---------------------------------------------------------------------------
 *	Local Functions
\*--------------------------------------------------------------------------*/

static int CheckForHoldingState(int state)
{
	sint16 *holds=HoldStates;

	if (lara.extra_anim)
		return (0);

	while(*holds>=0)
	{
		if ( state==*holds )
			return(1);
		holds++;
	}
	return(0);
}

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

/*******************************************************************************/
/*                                                                             */
/*    Control All General Aspects of Laras Combat                              */
/*                                                                             */
/*******************************************************************************/
void	LaraGun( void )
{
	if ( lara.left_arm.flash_gun>0 )
		lara.left_arm.flash_gun--;
	if ( lara.right_arm.flash_gun>0 )
		lara.right_arm.flash_gun--;

	if (lara_item->hit_points<=0)
		lara.gun_status = LG_ARMLESS;
	else if (lara.gun_status==LG_ARMLESS)	// if no gun out, or Lara holding a flare
	{
		if (input&IN_DRAW)
			lara.request_gun_type = lara.last_gun_type;
		else if (input&IN_F)
		{
			if (lara.gun_type == LG_FLARE) // got flare out already, so throw it
				lara.gun_status = LG_UNDRAW;
			else if (Inv_RequestItem(FLAREBOX_ITEM))
				lara.request_gun_type = LG_FLARE;
		}

		if (lara.request_gun_type != lara.gun_type || input & IN_DRAW)
		{
			// draw it, if OK, else cancel request
			if (lara.request_gun_type==LG_FLARE || (lara.skidoo==NO_ITEM && (lara.request_gun_type==LG_HARPOON || lara.water_status==LARA_ABOVEWATER ||
				  (lara.water_status==LARA_WADE && lara.water_surface_dist > -weapons[lara.gun_type].gun_height))))
			{
				// drop flare if holding one
				if (lara.gun_type == LG_FLARE)
				{
					CreateFlare(0);
					undraw_flare_meshes();
					lara.flare_control_left = 0;
				}

				// and initiate draw of new weapon
				lara.gun_type = lara.request_gun_type;
				InitialiseNewWeapon();
				lara.gun_status = LG_DRAW;
				lara.left_arm.frame_number = lara.right_arm.frame_number = 0;
			}
			else
			{
				// override this request, but remember choice
				lara.last_gun_type = lara.request_gun_type;
				if (lara.gun_type == LG_FLARE)
					lara.request_gun_type = LG_FLARE;
				else
					lara.gun_type = lara.request_gun_type;
			}
		}
	}
	else if (lara.gun_status == LG_READY)	// got gun out already
	{
		if ((input & IN_F) && Inv_RequestItem(FLAREBOX_ITEM))
			lara.request_gun_type = LG_FLARE;

		if ((input & IN_DRAW) || lara.request_gun_type!=lara.gun_type) // holster or new weapon required
			lara.gun_status = LG_UNDRAW;
		else if (lara.gun_type!=LG_HARPOON && lara.water_status!=LARA_ABOVEWATER &&
			(lara.water_status!=LARA_WADE || lara.water_surface_dist < -weapons[lara.gun_type].gun_height)) // fallen in water
			lara.gun_status = LG_UNDRAW;
	}

	switch ( lara.gun_status )
	{
		case LG_DRAW:							// Guns are being Drawn
			if ( lara.gun_type != LG_FLARE && lara.gun_type != LG_UNARMED )
				lara.last_gun_type = lara.gun_type;
			switch ( lara.gun_type )
			{
				case LG_PISTOLS:
				case LG_MAGNUMS:
				case LG_UZIS:
					if ( camera.type!=CINEMATIC_CAMERA && camera.type!=LOOK_CAMERA )
						camera.type = COMBAT_CAMERA;
					draw_pistols(lara.gun_type);
			   	break;

				case LG_SHOTGUN:
				case LG_HARPOON:
				case LG_ROCKET:
				case LG_GRENADE:
				case LG_M16:
					if ( camera.type!=CINEMATIC_CAMERA && camera.type!=LOOK_CAMERA )
						camera.type = COMBAT_CAMERA;
					draw_shotgun(lara.gun_type);
				break;

				case LG_FLARE:
					draw_flare();
				break;

				default:
					lara.gun_status = LG_ARMLESS; // attempt to draw weapon when none available
				break;
			}
		break;

		case LG_UNDRAW:                     	// Guns are being Put away
			lara.mesh_ptrs[HEAD]=meshes[objects[LARA].mesh_index+HEAD];			// Use Original Head
			switch ( lara.gun_type )
			{
				case LG_PISTOLS:
				case LG_MAGNUMS:
				case LG_UZIS:
					undraw_pistols(lara.gun_type);
				break;

				case LG_SHOTGUN:
				case LG_HARPOON:
				case LG_ROCKET:
				case LG_GRENADE:
				case LG_M16:
					undraw_shotgun(lara.gun_type);
				break;

				case LG_FLARE:
					undraw_flare();
				break;

				default:
				break;
			}
		break;

		case LG_SPECIAL:
			draw_flare();
		break;

		case LG_READY:
			if ( lara.pistols.ammo && input&IN_ACTION )
				lara.mesh_ptrs[HEAD]=meshes[objects[UZI].mesh_index+HEAD];		// Use Mean Head
			else
				lara.mesh_ptrs[HEAD]=meshes[objects[LARA].mesh_index+HEAD];					// Use Original Head

			if ( camera.type!=CINEMATIC_CAMERA && camera.type!=LOOK_CAMERA )
				camera.type = COMBAT_CAMERA;

			// check ammo if player wants to fire weapons
			if (input & IN_ACTION)
			{
				AMMO_INFO *ammo;

				switch(lara.gun_type)
				{
				case LG_SHOTGUN:
					ammo = &lara.shotgun;
					break;
				case LG_MAGNUMS:
					ammo = &lara.magnums;
					break;
				case LG_UZIS:
					ammo = &lara.uzis;
					break;
				case LG_ROCKET:
					ammo = &lara.rocket;
					break;
				case LG_GRENADE:
					ammo = &lara.grenade;
					break;
				case LG_HARPOON:
					ammo = &lara.harpoon;
					break;
				case LG_M16:
					ammo = &lara.m16;
					break;
				default:
					ammo = &lara.pistols;
				}

				// no ammo, so put away this gun and draw pistols instead
				if (ammo->ammo<=0)
				{
					ammo->ammo = 0;
					SoundEffect( 48, &lara_item->pos, 0 );		// play Guns Empty Sample
					if (Inv_RequestItem(GUN_ITEM))
						lara.request_gun_type = LG_PISTOLS;
					else
						lara.request_gun_type = LG_UNARMED;
					break;
				}
			}

			switch ( lara.gun_type )					// Guns are ready to be fired
			{
				case LG_PISTOLS:
				case LG_MAGNUMS:
				case LG_UZIS:
					PistolHandler(lara.gun_type);
				break;

				case LG_SHOTGUN:
				case LG_HARPOON:
				case LG_M16:
				case LG_ROCKET:
				case LG_GRENADE:
					RifleHandler(lara.gun_type);
				break;
			}
		break;

		case LG_ARMLESS:
			/* May be carrying a flare */
			if (lara.gun_type == LG_FLARE)
			{
				// Change to normal anims if not standing, walking or wading
				if (lara.skidoo!=NO_ITEM || CheckForHoldingState(lara_item->current_anim_state))
				{
					if (!lara.flare_control_left)
					{
						lara.left_arm.frame_number = FL_2HOLD_F;
						lara.flare_control_left = 1;
					}
					else if (lara.left_arm.frame_number != FL_HOLD_F)
					{
						lara.left_arm.frame_number++;
						if (lara.left_arm.frame_number == FL_END_F)
							lara.left_arm.frame_number = FL_HOLD_F;
					}
				}
				else
					lara.flare_control_left = 0;
				DoFlareInHand(lara.flare_age);
				set_flare_arm(lara.left_arm.frame_number);
			}
		break;

		case LG_HANDSBUSY:
			if ( lara.gun_type==LG_FLARE )
			{
				lara.flare_control_left = (lara.skidoo!=NO_ITEM || CheckForHoldingState(lara_item->current_anim_state));
				DoFlareInHand(lara.flare_age);
				set_flare_arm(lara.left_arm.frame_number);
			}
		break;
	}
}
/*******************************************************************************
 *			Initialise Current Weapon...
 ******************************************************************************/
void	InitialiseNewWeapon()
{
	lara.left_arm.frame_number = lara.right_arm.frame_number = 0;
	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.target = NULL;
	lara.left_arm.lock = lara.right_arm.lock = 0;
	lara.left_arm.flash_gun = lara.right_arm.flash_gun = 0;

	switch ( lara.gun_type )
	{
		case LG_PISTOLS:
		case LG_MAGNUMS:
		case LG_UZIS:
			lara.left_arm.frame_base = lara.right_arm.frame_base = objects[PISTOLS].frame_base;
			if ( lara.gun_status!=LG_ARMLESS )
				draw_pistol_meshes( lara.gun_type );	// Put Guns In Hands..
		break;

		case LG_SHOTGUN:
		case LG_HARPOON:
		case LG_M16:
		case LG_ROCKET:
		case LG_GRENADE:
			lara.left_arm.frame_base = lara.right_arm.frame_base = objects[WeaponObject(lara.gun_type)].frame_base;
			if ( lara.gun_status!=LG_ARMLESS )
				draw_shotgun_meshes( lara.gun_type );          		// Put ShotGun in Hand
		break;

		case LG_FLARE:
			lara.left_arm.frame_base = lara.right_arm.frame_base = objects[FLARE].frame_base;
			if ( lara.gun_status!=LG_ARMLESS )
				draw_flare_meshes();
		break;

		default:
			lara.left_arm.frame_base = lara.right_arm.frame_base = anims[lara_item->anim_number].frame_ptr;
//			lara.left_arm.frame_base = lara.right_arm.frame_base = objects[LARA].frame_base;
		break;
	}
}

/******************************************************************************
 *				Find  Angles from Lara to Predefined target...
 *			and if she can lock onto it or not..
 *		Returns MAX_DIST if LOS is Broken Or Distance squared if targetable
 *****************************************************************************/
void	LaraTargetInfo( WEAPON_INFO *winfo )
{
	GAME_VECTOR	src,target;
	PHD_ANGLE	ang[2];
	ITEM_INFO	*item;

	/* If Target Doesnt Exist use Defaults */
	if ( (item=lara.target)==NULL)
	{
		lara.left_arm.lock = lara.right_arm.lock = 0;
		lara.target_angles[0] = lara.target_angles[1] = 0;
		return;
	}

/* Calculate Angles towards Target */
	src.x = lara_item->pos.x_pos;
	src.y = lara_item->pos.y_pos - 650;
	src.z = lara_item->pos.z_pos;
	src.room_number = lara_item->room_number;
	find_target_point( item,&target );
	phd_GetVectorAngles( target.x-src.x, target.y-src.y, target.z-src.z, ang );

/* Determine if either arm can lock onto Target */
	ang[0] -= lara_item->pos.y_rot;
	ang[1] -= lara_item->pos.x_rot;

	if (LOS(&src, &target))
	{
		if ((ang[0] >= winfo->lock_angles[0])
		&&  (ang[0] <= winfo->lock_angles[1])
		&&  (ang[1] >= winfo->lock_angles[2])
		&&  (ang[1] <= winfo->lock_angles[3]))
			lara.left_arm.lock = lara.right_arm.lock = 1;
		else
		{
			if (lara.left_arm.lock)
			{
				if ((ang[0] < winfo->left_angles[0])
				||  (ang[0] > winfo->left_angles[1])
				||  (ang[1] < winfo->left_angles[2])
				||  (ang[1] > winfo->left_angles[3]))
					lara.left_arm.lock = 0;
			}
			if (lara.right_arm.lock)
			{
				if ((ang[0] < winfo->right_angles[0])
				||  (ang[0] > winfo->right_angles[1])
				||  (ang[1] < winfo->right_angles[2])
				||  (ang[1] > winfo->right_angles[3]))
					lara.right_arm.lock = 0;
			}
		}
	}
	else
		lara.left_arm.lock = lara.right_arm.lock = 0;

	lara.target_angles[0] = ang[0];
	lara.target_angles[1] = ang[1];
}

/******************************************************************************
 *					Get A New Target To Fire At
 *****************************************************************************/
#define NEAR_ANGLE (ONE_DEGREE*15)

void	LaraGetNewTarget( WEAPON_INFO *winfo )
{
	int			x,y,z,slot;
	int			dist,maxdist,maxdist2,bestdist;
	ITEM_INFO	*item,*bestitem;
	PHD_ANGLE	ang[2],bestyrot,yrot;
	GAME_VECTOR	src,target;
	CREATURE_INFO *creature;
//	sint16		item_num;

	src.x = lara_item->pos.x_pos;
	src.y = lara_item->pos.y_pos - 650;
	src.z = lara_item->pos.z_pos;
	src.room_number = lara_item->room_number;
	bestitem = NULL;
	bestyrot = 32767;
	bestdist = 0x7fffffff;
	maxdist = winfo->target_dist;
	maxdist2 = maxdist*maxdist;
//	for ( item_num = next_item_active; item_num!=NO_ITEM; item_num=item->next_active )	// Woh!! Goes thro all Active Items!!!!
	creature = baddie_slots;
	for (slot=0; slot<NUM_SLOTS; slot++, creature++)
	{
		if (creature->item_num == NO_ITEM || creature->item_num == lara.item_number)
			continue;

		item = &items[ creature->item_num ];                              						// For All Active Items..
		if ( item->hit_points <= 0 )         									// Dont target Silly Dead Things
			continue;
		x = item->pos.x_pos - src.x;
		y = item->pos.y_pos - src.y;
		z = item->pos.z_pos - src.z;
		if ( (ABS(x)) > maxdist || (ABS(y)) > maxdist || (ABS(z)) > maxdist )  			// Continue if Out of Range
			continue;
		dist = x*x + y*y + z*z;
		if ( dist<maxdist2 )
		{
			find_target_point( item,&target );                 			// And within arm bounds..
			if ( LOS( &src,&target ) )									// If got LOS
			{
				phd_GetVectorAngles( target.x-src.x, target.y-src.y, target.z-src.z, ang );
				ang[0] -= lara_item->pos.y_rot + lara.torso_y_rot;
				ang[1] -= lara_item->pos.x_rot + lara.torso_x_rot;
				if ( ang[0]>=winfo->lock_angles[0] && ang[0]<=winfo->lock_angles[1] &&
					 ang[1]>=winfo->lock_angles[2] && ang[1]<=winfo->lock_angles[3] )
				{
					yrot = ABS(ang[0]);
					if ( yrot<bestyrot+NEAR_ANGLE && dist<bestdist )
//					if ( yrot<bestyrot ) 								// Go on Best Angle...
					{
						bestdist = dist;
						bestyrot = yrot;
						bestitem = item;
					}
				}
			}
		}
	}
	lara.target = bestitem;
	/* Finally get more info about target */
	LaraTargetInfo( winfo );
}

/******************************************************************************
 *			Find Midpoint of Particular Item ...uses Bounding Box
 *			  Also fills in Room_Number in GAME_VECTOR structure
 *****************************************************************************/
void	find_target_point( ITEM_INFO *item, GAME_VECTOR *target )
{
	sint16		*bounds;
	sint32		x,y,z,c,s;

	bounds = GetBestFrame( item );
	x = (sint32)( ( *(bounds+0) + *(bounds+1) )/2 );
	y = (sint32)( *(bounds+2) + (*(bounds+3)-*(bounds+2))/3 );
	z = (sint32)( ( *(bounds+4) + *(bounds+5) )/2 );
	c = phd_cos( item->pos.y_rot );
	s = phd_sin( item->pos.y_rot );
	target->x = item->pos.x_pos + (( c*x + s*z ) >> W2V_SHIFT);
	target->y = item->pos.y_pos + y;
	target->z = item->pos.z_pos + (( c*z - s*x ) >> W2V_SHIFT);
	target->room_number = item->room_number;
}

/****************************************************************************
 *			Do Tracking Movement Of Weapon for X_Rot,Y_Rot
 ***************************************************************************/
void	AimWeapon( WEAPON_INFO *winfo, LARA_ARM *arm )
{
	PHD_ANGLE	curr,speed;
	PHD_ANGLE	destx,desty;


	speed = winfo->aim_speed;

	if ( arm->lock )
	{
		desty = lara.target_angles[0];
		destx = lara.target_angles[1];
	}
	else
		desty = destx = 0;

	curr = arm->y_rot;
	if ( curr>=desty-speed && curr<=desty+speed )
		curr = desty;
	else if ( curr<desty )
		curr += speed;
	else
		curr -= speed;
	arm->y_rot = curr;

	curr = arm->x_rot;
	if ( curr>=destx-speed && curr<=destx+speed )
		curr = destx;
	else if ( curr<destx )
		curr += speed;
	else
		curr -= speed;
	arm->x_rot = curr;

	arm->z_rot = 0;
}

/*****************************************************************************
 *		Fire Weapon along Y_Rot X_Rot.. Then see if Shot has hit
 *             The Required Baddie.
 *			Returns 1  if Baddie Hit
 *                  -1 if Baddie Missed
 *                  0  if Out of Ammo
 ****************************************************************************/
int		FireWeapon( int weapon_type, ITEM_INFO *target, ITEM_INFO *src, PHD_ANGLE *angles )
{
	int			r,i,nums,bestdist,best;
	AMMO_INFO		*ammo;
	WEAPON_INFO	*winfo;
	PHD_3DPOS		view;
	SPHERE		*sptr,slist[33];
	GAME_VECTOR	vsrc,vdest;
	FLOOR_INFO 	*floor;
	short 		room_number;
	sint16 		smash_item;

	switch ( weapon_type )
	{
		default:
			ammo = &lara.pistols;
			ammo->ammo = 1000;
		break;

		case LG_MAGNUMS:
			ammo = &lara.magnums;
			if ( savegame.bonus_flag )
				ammo->ammo = 1000;
		break;

		case LG_UZIS:
			ammo = &lara.uzis;
			if ( savegame.bonus_flag )
				ammo->ammo = 1000;
		break;

		case LG_M16:
			ammo = &lara.m16;
			if ( savegame.bonus_flag )
				ammo->ammo = 1000;
		break;

		case LG_SHOTGUN:
			ammo = &lara.shotgun;
			if ( savegame.bonus_flag )
				ammo->ammo = 1000;
		break;
	}

	ammo->ammo = 1000;		// GIBBY

	if ( ammo->ammo>0 ) 							// If Weve still Got Ammo
	{
		ammo->ammo--;
		winfo = &weapons[weapon_type];
		view.x_pos = src->pos.x_pos;
		view.y_pos = src->pos.y_pos - winfo->gun_height;
		view.z_pos = src->pos.z_pos;
		r = (int)((GetRandomControl()-16384)*winfo->shot_accuracy)/65536;
		view.x_rot = *(angles+1) + (sint16)r;
		r = (int)((GetRandomControl()-16384)*winfo->shot_accuracy)/65536;
		view.y_rot = *(angles+0) + (sint16)r;
		view.z_rot = 0;
		phd_GenerateW2V( &view );
		nums = GetSpheres( target, slist,0 );					// Get Target Spheres in ViewSpace...

		sptr = &slist[0];
		best = -1;
		bestdist = 0x7fffffff;
		for ( i=0;i<nums;i++,sptr++ )
		{
			r = sptr->r;									// Snaff up radius
			if ( (ABS(sptr->x))<r &&
			 	(ABS(sptr->y))<r && 						// Only If Sphere lies on Positive Z axis
			 	sptr->z > r &&                     		// then it has Been Hit...
		     	(sptr->x*sptr->x)+(sptr->y*sptr->y) <= (r*r) )
			{
			 	if ( sptr->z-r<bestdist )
			 	{
			 		bestdist = sptr->z - r;
			 		best = i;                 				// Get Nearest Point on Sphere Along LOS
			 	}
			}
		}

		savegame.ammo_used++;
		vsrc.x = view.x_pos;
		vsrc.y = view.y_pos;
		vsrc.z = view.z_pos;
		room_number = src->room_number;
		floor = GetFloor(view.x_pos, view.y_pos, view.z_pos, &room_number);
		vsrc.room_number = room_number;
		if ( best>=0 )
		{
			// Target has Possibly been hit
			savegame.ammo_hit++;
			vdest.x = vsrc.x + ((*(phd_mxptr+M20)*bestdist)>>W2V_SHIFT);
			vdest.y = vsrc.y + ((*(phd_mxptr+M21)*bestdist)>>W2V_SHIFT);
			vdest.z = vsrc.z + ((*(phd_mxptr+M22)*bestdist)>>W2V_SHIFT);

			/* Check for smashable object on LOS */
			smash_item = ObjectOnLOS(&vsrc, &vdest);
			if (smash_item != NO_ITEM)
				SmashItem(smash_item, weapon_type);

			HitTarget( target,&vdest, winfo->damage );
			return(1);
		}
		else
		{
			// Else target missed so do a richochet
			vdest.x = vsrc.x + ((*(phd_mxptr+M20)*winfo->target_dist)>>W2V_SHIFT);
			vdest.y = vsrc.y + ((*(phd_mxptr+M21)*winfo->target_dist)>>W2V_SHIFT);
			vdest.z = vsrc.z + ((*(phd_mxptr+M22)*winfo->target_dist)>>W2V_SHIFT);
			best = LOS( &vsrc,&vdest );

			/* Check for smashable object on LOS */
			smash_item = ObjectOnLOS(&vsrc, &vdest);
			if (smash_item != NO_ITEM)
				SmashItem(smash_item, weapon_type);
			else if (!best) // gav 14/7/97: if LOS to target, then havn't hit a wall
				Richochet( &vdest );
			return(-1);
		}
	}
	else
	{
		ammo->ammo = 0;
/*
		SoundEffect( 48, &src->pos, 0 );		// play Guns Empty Sample
		if (Inv_RequestItem(GUN_ITEM))
			lara.request_gun_type = LG_PISTOLS;
		else
			lara.request_gun_type = LG_UNARMED;
*/
		return(0);
	}
}

/******************************************************************************
 *			Target Has Been Hit by Lara firing
 *						her guns...
 *****************************************************************************/
#define MONKS_GET_ANGRY 10

void	HitTarget( ITEM_INFO *item, GAME_VECTOR *hitpos, int damage )
{
	CREATURE_INFO *monk;

	if ( item->hit_points>0 && item->hit_points<=damage )
		savegame.kills++;

	item->hit_points -= damage;        			// Subtract Hit Points from Baddie...
	item->hit_status = 1;

	if (hitpos)
		DoBloodSplat( hitpos->x,hitpos->y,hitpos->z,item->speed,item->pos.y_rot,item->room_number );

	/* Is this a friendly monk? */
	if (!monks_attack_lara && (item->object_number==MONK1 || item->object_number==MONK2))
	{
		monk = (CREATURE_INFO *)item->data;
		monk->flags += damage;

		// monk will allow a few accidental shots in melee, or one if they are being non-aggressive
		if ((monk->flags & 0x0fff) > MONKS_GET_ANGRY || monk->mood == BORED_MOOD)
			monks_attack_lara = 1;
	}
}


void SmashItem(sint16 item_number, int weapon_type)
{
	/* Weapon type not currently used, but there in case object is only smashed by certain levels of weaponary */
	ITEM_INFO *item;

	item = &items[item_number];
	switch (item->object_number)
	{
		case SMASH_WINDOW:
			SmashWindow(item_number);
			break;
	}
}

/*
 * Convert an LG_WEAPON to object number
 *
 */
int WeaponObject(int weapon_type)
{
	switch (weapon_type)
	{
		case LG_MAGNUMS:
			return MAGNUM;
		case LG_UZIS:
			return UZI;
		case LG_SHOTGUN:
			return SHOTGUN;
		case LG_ROCKET:
			return ROCKET_GUN;
		case LG_GRENADE:
		case LG_HARPOON:
			return HARPOON_GUN;
		case LG_M16:
			return M16;
		case LG_PISTOLS:
		default:
			return PISTOLS;
	}
}

void	DoProperDetection(short item_number, long x, long y, long z, long xv, long yv, long zv)
{
	ITEM_INFO *item;
	sint16 room_number;
	sint32 ceiling, height,oldtype,oldonobj,oldheight;
	sint32 bs, yang;
	FLOOR_INFO *floor;

	item = &items[item_number];

	room_number = item->room_number;
	floor = GetFloor(x,y,z, &room_number);
	oldheight = GetHeight(floor, x,y,z);
	oldonobj = OnObject;
	oldtype = height_type;

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

	/* Bounce off floor */
	height = GetHeight(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
	if (item->pos.y_pos >= height)
	{
		bs = 0;

		if ((height_type == BIG_SLOPE || height_type == DIAGONAL) && oldheight < height)
		{
			yang = (long)((unsigned short) item->pos.y_rot);
			if (tiltyoff < 0)
			{
				if (yang >= 0x8000)
					bs = 1;
			}
			else if (tiltyoff > 0)
			{
				if (yang <= 0x8000)
					bs = 1;
			}

			if (tiltxoff < 0)
			{
				if (yang >= 0x4000 && yang <= 0xc000)
					bs = 1;
			}
			else if (tiltxoff > 0)
			{
				if (yang <= 0x4000 || yang >= 0xc000)
					bs = 1;
			}
		}

		/* If last position of item was also below this floor height, we've hit a wall, else we've hit a floor */

		if (y > (height+32) && bs == 0 &&
			(((x >> WALL_SHIFT) != (item->pos.x_pos >> WALL_SHIFT)) ||
			 ((z >> WALL_SHIFT) != (item->pos.z_pos >> WALL_SHIFT))))
		{
			// Need to know which direction the wall is.

			long	xs;

			if ((x & (~(WALL_L-1))) != (item->pos.x_pos & (~(WALL_L-1))) &&	// X crossed boundary?
				(z & (~(WALL_L-1))) != (item->pos.z_pos & (~(WALL_L-1))))	// Z crossed boundary as well?
			{
				if (abs(x-item->pos.x_pos) < abs(z-item->pos.z_pos))
					xs = 1;	// X has travelled the shortest, so (maybe) hit first. (Seems to work ok).
				else
					xs = 0;
			}
			else
				xs = 1;

			if ((x & (~(WALL_L-1))) != (item->pos.x_pos & (~(WALL_L-1))) && xs)	// X crossed boundary?
			{
				if (xv <= 0)	// Hit angle = 0xc000.
					item->pos.y_rot = 0x4000 + (0xc000 - item->pos.y_rot);
				else			// Hit angle = 0x4000.
					item->pos.y_rot = 0xc000 + (0x4000 - item->pos.y_rot);
			}
			else		// Z crossed boundary.
				item->pos.y_rot = 0x8000 - item->pos.y_rot;

//			if (item->object_number == GRENADE)
//				item->speed -= item->speed>>1;
//			else
				item->speed >>= 1;

			/* Put item back in its last position */
			item->pos.x_pos = x;
			item->pos.y_pos = y;
			item->pos.z_pos = z;
		}
		else if (height_type == BIG_SLOPE || height_type == DIAGONAL) 	// Hit a steep slope?
		{
			// Need to know which direction the slope is.

			if (item->object_number == GRENADE)
				item->speed -= item->speed>>2;
			else
				item->speed -= item->speed>>2;

			if (tiltyoff < 0 && ((abs(tiltyoff)) - (abs(tiltxoff)) >= 2))	// Hit angle = 0x4000
			{
				if (((unsigned short)item->pos.y_rot) > 0x8000)
				{
			 		item->pos.y_rot = 0x4000 + (0xc000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed -= tiltyoff<<1;
						if ((unsigned short) item->pos.y_rot > 0x4000 && (unsigned short) item->pos.y_rot < 0xc000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0x4000)
								item->pos.y_rot = 0x4000;
						}
						else if ((unsigned short) item->pos.y_rot < 0x4000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0x4000)
								item->pos.y_rot = 0x4000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltyoff > 0 && ((abs(tiltyoff)) - (abs(tiltxoff)) >= 2))	// Hit angle = 0xc000
			{
				if (((unsigned short) item->pos.y_rot) < 0x8000)
				{
					item->pos.y_rot = 0xc000 + (0x4000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += tiltyoff<<1;
						if ((unsigned short) item->pos.y_rot > 0xc000 || (unsigned short) item->pos.y_rot < 0x4000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0xc000)
								item->pos.y_rot = 0xc000;
						}
						else if ((unsigned short) item->pos.y_rot < 0xc000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0xc000)
								item->pos.y_rot = 0xc000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltxoff < 0 && ((abs(tiltxoff)) - (abs(tiltyoff)) >= 2))	// Hit angle = 0
			{
				if (((unsigned short) item->pos.y_rot) > 0x4000 && ((unsigned short) item->pos.y_rot) < 0xc000)
				{
					item->pos.y_rot = (0x8000 - item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed -= tiltxoff<<1;

						if ((unsigned short) item->pos.y_rot < 0x8000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot > 0xf000)
								item->pos.y_rot = 0;
						}
						else if ((unsigned short) item->pos.y_rot >= 0x8000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot < 0x1000)
								item->pos.y_rot = 0;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltxoff > 0 && ((abs(tiltxoff)) - (abs(tiltyoff)) >= 2))	// Hit angle = 0x8000
			{
				if (((unsigned short)item->pos.y_rot) > 0xc000 || ((unsigned short)item->pos.y_rot) < 0x4000)
				{
					item->pos.y_rot = (0x8000 - item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += tiltxoff<<1;

						if ((unsigned short) item->pos.y_rot > 0x8000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0x8000)
								item->pos.y_rot = 0x8000;
						}
						else if ((unsigned short) item->pos.y_rot < 0x8000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0x8000)
								item->pos.y_rot = 0x8000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltyoff < 0 && tiltxoff < 0)	// Hit angle = 0x2000
			{
				if (((unsigned short)item->pos.y_rot) > 0x6000 && ((unsigned short)item->pos.y_rot) < 0xe000)
				{
			 		item->pos.y_rot = 0x2000 + (0xa000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += (-tiltyoff) + (-tiltxoff);
						if ((unsigned short) item->pos.y_rot > 0x2000 && (unsigned short) item->pos.y_rot < 0xa000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0x2000)
								item->pos.y_rot = 0x2000;
						}
						else if ((unsigned short) item->pos.y_rot != 0x2000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0x2000)
								item->pos.y_rot = 0x2000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltyoff < 0 && tiltxoff > 0)	// Hit angle = 0x6000
			{
				if (((unsigned short)item->pos.y_rot) > 0xa000 || ((unsigned short)item->pos.y_rot) < 0x2000)
				{
			 		item->pos.y_rot = 0x6000 + (0xe000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += (-tiltyoff) + tiltxoff;
						if ((unsigned short) item->pos.y_rot < 0xe000 && (unsigned short) item->pos.y_rot > 0x6000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0x6000)
								item->pos.y_rot = 0x6000;
						}
						else if ((unsigned short) item->pos.y_rot != 0x6000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0x6000)
								item->pos.y_rot = 0x6000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltyoff > 0 && tiltxoff > 0)	// Hit angle = 0xa000
			{
				if (((unsigned short)item->pos.y_rot) > 0xe000 || ((unsigned short)item->pos.y_rot) < 0x6000)
				{
			 		item->pos.y_rot = 0xa000 + (0x2000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += tiltyoff + tiltxoff;
						if ((unsigned short) item->pos.y_rot < 0x2000 || (unsigned short) item->pos.y_rot > 0xa000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0xa000)
								item->pos.y_rot = 0xa000;
						}
						else if ((unsigned short) item->pos.y_rot != 0xa000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0xa000)
								item->pos.y_rot = 0xa000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}
			else if (tiltyoff > 0 && tiltxoff < 0)	// Hit angle = 0xe000
			{
				if (((unsigned short)item->pos.y_rot) > 0x2000 && ((unsigned short)item->pos.y_rot) < 0xa000)
				{
			 		item->pos.y_rot = 0xe000 + (0x6000 - (unsigned short) item->pos.y_rot - 1);
					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					}
					else
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
					}
				}
				else
				{
					if (item->speed < 32)
					{
						item->speed += tiltyoff + (-tiltxoff);
						if ((unsigned short) item->pos.y_rot < 0x6000 || (unsigned short) item->pos.y_rot > 0xe000)
						{
							item->pos.y_rot -= 4096;
							if ((unsigned short) item->pos.y_rot < 0xe000)
								item->pos.y_rot = 0xe000;
						}
						else if ((unsigned short) item->pos.y_rot != 0xe000)
						{
							item->pos.y_rot += 4096;
							if ((unsigned short) item->pos.y_rot > 0xe000)
								item->pos.y_rot = 0xe000;
						}
					}

					if (item->object_number == GRENADE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
							item->fallspeed = 0;
					}
					else	if (item->object_number == FLARE)
					{
						if (item->fallspeed > 0)
							item->fallspeed = -(item->fallspeed>>2);
						else
							item->fallspeed = 0;
					}
				}
			}

			/* Put item back in its last position */
			item->pos.x_pos = x;
			item->pos.y_pos = y;
			item->pos.z_pos = z;
		}
		else
		{
			/* Hit the floor; bounce and slow down */
			if (item->fallspeed > 0)
			{
				if (item->fallspeed > 16)
				{
					if (item->object_number == GRENADE)
						item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
					else
					{
						item->fallspeed = -(item->fallspeed>>2);
						if (item->fallspeed < -100)
							item->fallspeed = -100;
					}
				}
				else
				{
					/* Roll on floor */
					item->fallspeed = 0;
					if (item->object_number == GRENADE)
 						item->speed--;
					else
						item->speed -= 3;

					if (item->speed < 0)
						item->speed = 0;
				}
			}
			item->pos.y_pos = height;
		}
	}
	else	// Check for on top of object.
	{
		if (yv >= 0)
		{
			room_number = item->room_number;
			floor = GetFloor(item->pos.x_pos, y, item->pos.z_pos, &room_number);
			oldheight = GetHeight(floor, item->pos.x_pos, y, item->pos.z_pos);
			oldonobj = OnObject;
			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);

			/* Bounce off floor */
			if (item->pos.y_pos >= oldheight && oldonobj)	// If old and new pos above object then detect.
			{
				/* Hit the floor; bounce and slow down */
				if (item->fallspeed > 0)
				{
					if (item->fallspeed > 16)
					{
						if (item->object_number == GRENADE)
							item->fallspeed = -(item->fallspeed - (item->fallspeed>>1));
						else
						{
							item->fallspeed = -(item->fallspeed>>2);
							if (item->fallspeed < -100)
								item->fallspeed = -100;
						}
					}
					else
					{
						/* Roll on floor */
						item->fallspeed = 0;
						if (item->object_number == GRENADE)
 							item->speed--;
						else
							item->speed -= 3;

						if (item->speed < 0)
							item->speed = 0;
					}
				}
				item->pos.y_pos = oldheight;
			}
		}
		else
		{
			/* Bounce off ceiling */
			room_number = item->room_number;
			floor = GetFloor(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, &room_number);
			ceiling = GetCeiling(floor, item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
			if (item->pos.y_pos < ceiling)
			{
				if (y < ceiling &&
				(((x >> WALL_SHIFT) != (item->pos.x_pos >> WALL_SHIFT)) ||
			 	((z >> WALL_SHIFT) != (item->pos.z_pos >> WALL_SHIFT))))
				{
					// Need to know which direction the wall is.

					if ((x & (~(WALL_L-1))) != (item->pos.x_pos & (~(WALL_L-1))))	// X crossed boundary?
					{
						if (xv <= 0)	// Hit angle = 0xc000.
							item->pos.y_rot = 0x4000 + (0xc000 - item->pos.y_rot);
						else			// Hit angle = 0x4000.
							item->pos.y_rot = 0xc000 + (0x4000 - item->pos.y_rot);
					}
					else		// Z crossed boundary.
					{
						item->pos.y_rot = 0x8000 - item->pos.y_rot;
					}

					if (item->object_number == GRENADE)
						item->speed -= item->speed>>3;
					else
						item->speed >>= 1;

					/* Put item back in its last position */
					item->pos.x_pos = x;
					item->pos.y_pos = y;
					item->pos.z_pos = z;
				}
				else
				{
	//				item->pos.x_pos = x;
					item->pos.y_pos = ceiling;
	//				item->pos.z_pos = z;
	//				item->pos.y_rot = item->pos.y_rot+0x8000;
				}

				if (item->fallspeed < 0)
					item->fallspeed = -item->fallspeed;
			}
		}
	}

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