/*********************************************************************************************/
/*                                                                                           */
/* People Control                                                                            */
/*                                                                                           */
/*********************************************************************************************/

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

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

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "control.h"
#include "sound.h"
#include "sphere.h"
#include "effect2.h"
#include "title.h"

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


/* How close before a baddie will open fire */
#define PEOPLE_SHOOT_RANGE SQUARE(WALL_L*8)
#define PEOPLE_HIT_CHANCE 0x2000
#define PEOPLE_TARGETING_SPEED 300

#define TARGET_HEIGHT_OFFSET (STEP_L*2)
#define LOS_START_HEIGHT_OFFSET (STEP_L*3)
#define LOS_TARGET_HEIGHT_OFFSET (STEP_L*2)


/*********************************** FUNCTION CODE *******************************************/

int TargetVisible(ITEM_INFO *item, AI_INFO *info)
{
	// Shameless rip-off of Targetable, but using position of head rather than just rot_y
	GAME_VECTOR start, target;
	CREATURE_INFO *creature;
	ITEM_INFO *enemy;
	sint16 true_angle, *bounds;

	creature = (CREATURE_INFO *)item->data;
	if ((enemy = creature->enemy) == NULL)
		return 0;

	/* Don't shoot dead people or unintelligent things*/
	if (enemy->hit_points <= 0 || /*!objects[enemy->object_number].intelligent*/ enemy->data == NULL)
		return 0;
	true_angle = info->angle - creature->joint_rotation[2]; // This means for guards head y_rotation must be in the third slot
	if (true_angle > -FRONT_ARC && true_angle < FRONT_ARC && info->distance < PEOPLE_SHOOT_RANGE)
	{
		start.x = item->pos.x_pos;
		// TS - not sure about altering this...  just testing
		// start.y = item->pos.y_pos - STEP_L*3;
		start.y = item->pos.y_pos - LOS_START_HEIGHT_OFFSET;
		start.z = item->pos.z_pos;
		start.room_number = item->room_number;

		target.x = enemy->pos.x_pos;
		// TS - not sure about altering this...  just testing
		// target.y = enemy->pos.y_pos - STEP_L*3;
		bounds = GetBestFrame(enemy);
		target.y = enemy->pos.y_pos + (sint32)( ((*(bounds+2)<<1) + *(bounds+2) + *(bounds+3)) >>2 );

		/*
		if (enemy == lara_item && (enemy->current_anim_state == AS_DUCK || enemy->current_anim_state == AS_DUCKROLL ||
									enemy->current_anim_state ==AS_ALL4S || enemy->current_anim_state == AS_CRAWL ||
									enemy->current_anim_state == AS_ALL4TURNL || enemy->current_anim_state == AS_ALL4TURNR))
				target.y = enemy->pos.y_pos - STEP_L;
		else
			target.y = enemy->pos.y_pos - LOS_TARGET_HEIGHT_OFFSET;
			*/
		target.z = enemy->pos.z_pos;

		return (LOS(&start, &target));
	}

	return (0);
}

int Targetable(ITEM_INFO *item, AI_INFO *info)
{
	GAME_VECTOR start, target;
	CREATURE_INFO *creature;
	ITEM_INFO *enemy;
	sint16 *bounds;

	creature = (CREATURE_INFO *)item->data;

	if ((enemy = creature->enemy) == NULL)
		return 0;

	/* Don't shoot dead people or unintelligent things*/
	if (enemy->hit_points <= 0 || /*!objects[enemy->object_number].intelligent*/ enemy->data == NULL)
		return 0;

	if (info->ahead && info->distance < PEOPLE_SHOOT_RANGE)
	{
		start.x = item->pos.x_pos;
		// TS - not sure about altering this...  just testing
		// start.y = item->pos.y_pos - STEP_L*3; //Original

		//start.y = item->pos.y_pos - TARGET_HEIGHT_OFFSET;
		bounds = GetBestFrame(item);
		start.y = item->pos.y_pos + (sint32)( ((*(bounds+2)<<1) + *(bounds+2) + *(bounds+3)) >>2 );
		start.z = item->pos.z_pos;
		start.room_number = item->room_number;

		target.x = enemy->pos.x_pos;
		// TS - not sure about altering this...  just testing
		// target.y = enemy->pos.y_pos - STEP_L*3;
		bounds = GetBestFrame(enemy);
		target.y = enemy->pos.y_pos + (sint32)( ((*(bounds+2)<<1) + *(bounds+2) + *(bounds+3)) >>2 );

		/*
		if (enemy == lara_item && (enemy->current_anim_state == AS_DUCK || enemy->current_anim_state == AS_DUCKROLL ||
									enemy->current_anim_state ==AS_ALL4S || enemy->current_anim_state == AS_CRAWL ||
									enemy->current_anim_state == AS_ALL4TURNL || enemy->current_anim_state == AS_ALL4TURNR))
				target.y = enemy->pos.y_pos - STEP_L;
		else
			target.y = enemy->pos.y_pos - TARGET_HEIGHT_OFFSET;
		*/

		target.z = enemy->pos.z_pos;

		return (LOS(&start, &target));
	}

	return (0);
}

sint16 GunShot(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number)
{
	/* Gun flash from baddies guns */

//	TriggerDynamic(x, y, z, 12, 31, 24, 8);
	return (NO_ITEM);
#if	0
#ifdef PSX_VERSION
	Glow(x,y,z,room_number,4,0x800,0x400,0x200,0,SPRITE_TRANS_ADD|SPRITE_SCALE|SPRITE_SHADE|SPRITE_TINT|SPRITE_COLOUR(0x7f,0x70,0x1f));
#endif

	fx_number = CreateEffect(room_number);
	if (fx_number != NO_ITEM)
	{
		fx = &effects[fx_number];
		fx->pos.x_pos = x;
		fx->pos.y_pos = y;
		fx->pos.z_pos = z;
		fx->room_number = room_number;	// OI!  Gav!!!  This is filled in by CreateEffect - Dude
		fx->pos.x_rot = fx->pos.z_rot = 0;
		fx->pos.y_rot = yrot;
		fx->counter = 3;
		fx->frame_number = 0;
		fx->object_number = GUN_FLASH;
		fx->shade = 16*256;				// OI!  Gav!!!  This is filled in by CreateEffect - Dude
	}

	return (fx_number);
#endif
}


sint16 GunHit(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number)
{
	/* Lara gets a blood splat */
	PHD_VECTOR pos;

	/* Give Lara a blood splat on a random mesh to keep her happy */
	pos.x = pos.y = pos.z = 0;
	GetJointAbsPosition(lara_item, &pos, GetRandomControl()*25/0x7fff);
	DoBloodSplat(pos.x, pos.y, pos.z, lara_item->speed, lara_item->pos.y_rot, lara_item->room_number);
	SoundEffect(50, &lara_item->pos, 0);

	return (GunShot(x, y, z, speed, yrot, room_number));
}


sint16 GunMiss(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number)
{
	/* Lara sees a richochet */
	GAME_VECTOR pos;

	/* Do richochet near Lara's feet	*/
	pos.x = lara_item->pos.x_pos + (GetRandomControl()-0x4000) * (WALL_L/2)/0x7fff;
	pos.y = lara_item->floor;
	pos.z = lara_item->pos.z_pos + (GetRandomControl()-0x4000) * (WALL_L/2)/0x7fff;
	pos.room_number = lara_item->room_number;
	Richochet(&pos);

	return (GunShot(x, y, z, speed, yrot, room_number));
}


int ShotLara(ITEM_INFO *item, AI_INFO *info, BITE_INFO *gun, sint16 extra_rotation, int damage)
{
	/* See if gun shot hit Lara given the range.
		Return whether Lara was targetable or not (NOT whether she was hit) */
	int hit, targetable, random, distance;
	sint16 fx_number;
	sint16 smash_item;
	GAME_VECTOR start, target;
	CREATURE_INFO *creature;
	ITEM_INFO *enemy;
	PHD_VECTOR pos;


	creature = (CREATURE_INFO *)item->data;
	enemy = creature->enemy;

	if (info->distance > PEOPLE_SHOOT_RANGE || !Targetable(item, info))
		hit = targetable = 0;
	else
	{
		/* Add enemy's sideways speed to the distance to give less chance of hitting her if she is moving across line of fire */
		distance = (phd_sin(info->enemy_facing) * enemy->speed >> W2V_SHIFT) * PEOPLE_SHOOT_RANGE / PEOPLE_TARGETING_SPEED;
		distance = info->distance + SQUARE(distance);
		if (distance > PEOPLE_SHOOT_RANGE)
			hit = 0;
		else
		{
			/* Min hit chance is 0x1000, max is 0x6000 */
			random = (PEOPLE_SHOOT_RANGE - info->distance) / (PEOPLE_SHOOT_RANGE/0x5000) + PEOPLE_HIT_CHANCE;
			hit = (GetRandomControl() < random);
		}
		targetable = 1;
	}

	item->fired_weapon = 3;	//##

	fx_number = CreateEffect(item->room_number);
	if (fx_number != NO_ITEM)
	{
		FX_INFO 		*fx;
		PHD_VECTOR	pos;

		pos.x = gun->x>>2;
		pos.y = gun->y>>2;
		pos.z = gun->z>>2;
		GetJointAbsPosition(item, &pos, gun->mesh_num );

		fx = &effects[fx_number];
		fx->pos.x_pos = pos.x;
		fx->pos.y_pos = pos.y;
		fx->pos.z_pos = pos.z;
		fx->room_number = item->room_number;
		fx->pos.y_rot = 0;
		fx->pos.x_rot = 0;
		fx->pos.z_rot = GetRandomControl();
		fx->speed = 16 + (GetRandomControl() & 31);
		fx->fallspeed = -48 - (GetRandomControl() & 7);
		fx->object_number = GUNSHELL;
		fx->frame_number = objects[GUNSHELL].mesh_index;
		fx->shade = 0x4210;
		fx->counter = 1;	// Number of bounces.
		fx->flag1 = item->pos.y_rot - 0x4800 + (GetRandomControl()&0xfff);	// Flag1 = y rotation.

		pos.x = gun->x-(gun->x>>2);
		pos.y = gun->y-(gun->y>>2);
		pos.z = gun->z-(gun->z>>2);
		GetJointAbsPosition(item, &pos, gun->mesh_num );
		TriggerGunSmoke(pos.x, pos.y, pos.z, 0, 0, 0, 0, LG_PISTOLS, 32);
	}

	if (damage)
	{
		if (enemy == lara_item)
		{
			/* Shooting at Lara */
			if (hit)
			{
				CreatureEffect(item, gun, GunHit);
				lara_item->hit_points -= damage;
				lara_item->hit_status = 1;
			}
			else if (targetable)
				CreatureEffect(item, gun, GunMiss);
		}
		else
		{
			/* Shooting at another 'baddy' */
			CreatureEffect(item, gun, GunShot);
			if (hit)
			{
				enemy->hit_points -= damage/10;
				enemy->hit_status = 1;
				random = GetRandomControl() & 0xF;
				if (random > 14)
					random = 0;
				pos.x = pos.y = pos.z = 0;
				GetJointAbsPosition(enemy, &pos, random);
				DoBloodSplat(pos.x, pos.y, pos.z, enemy->speed, enemy->pos.y_rot, enemy->room_number);
			}
		}
	}

	/* Smash any objects that get in the way */
	start.x = item->pos.x_pos;
	start.y = item->pos.y_pos - STEP_L*3;
	start.z = item->pos.z_pos;
	start.room_number = item->room_number;

	target.x = enemy->pos.x_pos;
	target.y = enemy->pos.y_pos - STEP_L*3;
	target.z = enemy->pos.z_pos;

	smash_item = ObjectOnLOS(&start, &target);
	if (smash_item != NO_ITEM)
	{
		if (!(items[smash_item].object_number == SMASH_OBJECT1 && CurrentLevel == LV_CRASH))
	 		SmashItem(smash_item, 0);
	}

	return (targetable);
}

