/*********************************************************************************************/
/*                                                                                           */
/* Swat Control  - TS - August 98    - Also used for London Mercenaries                      */
/*                                                                                           */
/*********************************************************************************************/

/*---------------------------------------------------------------------------
 *	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 "people.h"
#include "effect2.h"
#include "sphere.h"

#if defined(PSX_VERSION) && defined(RELOC)

void InitialiseSwat(sint16 item_number);
void SwatControl(sint16 item_number);

void *func[] = {
	&InitialiseSwat,
	&SwatControl,
};

#endif

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

//#define SWAT_SHOT_DAMAGE 1
#define SWAT_SHOT_DAMAGE 28


enum swat_anims {SWAT_EMPTY, SWAT_STOP, SWAT_WALK, SWAT_RUN, SWAT_WAIT, SWAT_SHOOT1, SWAT_SHOOT2, SWAT_DEATH, SWAT_AIM1, SWAT_AIM2, SWAT_AIM3, SWAT_SHOOT3};

#define SWAT_WALK_TURN (ONE_DEGREE*6)
#define SWAT_RUN_TURN (ONE_DEGREE*9)

#define SWAT_RUN_RANGE SQUARE(WALL_L*2)
#define SWAT_SHOOT1_RANGE SQUARE(WALL_L*3)

#define SWAT_DIE_ANIM 19
#define SWAT_STOP_ANIM 12
#define SWAT_WALK_STOP_ANIM 17
#define SWAT_DEATH_SHOT_ANGLE 0x2000
#define SWAT_AWARE_DISTANCE SQUARE(WALL_L)

//#define DEBUG_SWAT

#ifdef DEBUG_SWAT
extern char exit_message[];
#endif

#ifdef DEBUG_SWAT
static char *SwatStrings[] = {
"EMPTY", "STOP", "WALK", "RUN", "WAIT", "SHOOT1",
"SHOOT2", "DEATH", "AIM1", "AIM2", "AIM3", "SHOOT3"};
#endif

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

static BITE_INFO swat_gun = {0,300,64, 7};

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

void InitialiseSwat(sint16 item_number)
{
	ITEM_INFO *item;

	item = &items[item_number];
	InitialiseCreature(item_number);

	/* Start Swat in stop pose*/
	item->anim_number = objects[item->object_number].anim_index + SWAT_STOP_ANIM;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = item->goal_anim_state = SWAT_STOP;
}


void SwatControl(sint16 item_number)
{
	//Swat SMG man with Laser sight

	ITEM_INFO *item, *real_enemy;
	CREATURE_INFO *swat;
	sint16 angle, torso_y, torso_x, head, tilt, meta_mood;
	sint32 lara_dx, lara_dz;
	AI_INFO info, lara_info;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];
	swat = (CREATURE_INFO *)item->data;
	torso_y = torso_x = head = angle = tilt = 0;

	if (item->fired_weapon)	// Dynamic light for firing weapon.
	{
		PHD_VECTOR pos;

		phd_PushMatrix();
		pos.x = swat_gun.x;
		pos.y = swat_gun.y;
		pos.z = swat_gun.z;
		GetJointAbsPosition(item, &pos, swat_gun.mesh_num);
		TriggerDynamic(pos.x, pos.y, pos.z, (item->fired_weapon<<1)+8, 24, 16, 4);
		phd_PopMatrix();
	}

	if (boxes[item->box_number].overlap_index & BLOCKED)
	{
		DoLotsOfBloodD(item->pos.x_pos, item->pos.y_pos-(GetRandomControl()&255)-32, item->pos.z_pos, (GetRandomControl()&127)+128, GetRandomControl()<<1, item->room_number , 3);
		item->hit_points -= 20;
	}

	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != SWAT_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + SWAT_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = SWAT_DEATH;
			if (!(GetRandomControl() & 1))
				swat->flags = 1;
			else
				swat->flags = 0;
		}
		else if (swat->flags && item->frame_number > anims[item->anim_number].frame_base + 44 && item->frame_number < anims[item->anim_number].frame_base + 52 && !(item->frame_number & 0x3)) //These are the frames where the gun is fired
		{
			CreatureAIInfo(item, &info);
			if (Targetable(item, &info))
			{
				if (info.angle > -SWAT_DEATH_SHOT_ANGLE && info.angle < SWAT_DEATH_SHOT_ANGLE)
				{
					torso_y = info.angle;
					head = info.angle;
					ShotLara(item, &info, &swat_gun, torso_y, SWAT_SHOT_DAMAGE*3);
					if (item->object_number == LON_MERCENARY1)
						SoundEffect(72, &item->pos, 3<<13); //Pitch & Volume wibble?
					else
						SoundEffect(137, &item->pos, 3<<13); //Pitch & Volume wibble?
				}
			}
		}
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(swat);
		else
			swat->enemy = lara_item;

		CreatureAIInfo(item, &info);

		if (swat->enemy == lara_item)
		{
			lara_info.angle = info.angle;
			lara_info.distance = info.distance;
		}
		else
		{
			lara_dz = lara_item->pos.z_pos - item->pos.z_pos;
			lara_dx = lara_item->pos.x_pos - item->pos.x_pos;
			lara_info.angle = phd_atan(lara_dz, lara_dx) - item->pos.y_rot; //only need to fill out the bits of lara_info that will be needed by TargetVisible
			lara_info.distance = lara_dz * lara_dz + lara_dx * lara_dx;
		}

		if (swat->enemy != lara_item) //Should eventually change this to be any person
			meta_mood = VIOLENT;	//Shooters run up to their target if it's not a person
		else
			meta_mood = TIMID;		//Else they stay their distance

		GetCreatureMood(item, &info, meta_mood);

		CreatureMood(item, &info, meta_mood);

		angle = CreatureTurn(item, swat->maximum_turn);

		real_enemy = swat->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
		swat->enemy = lara_item;
//##		if ((lara_info.distance < SWAT_AWARE_DISTANCE || item->hit_status || TargetVisible(item, &lara_info)) && !(item->ai_bits & FOLLOW)) //Maybe move this into SWAT_WAIT case?
		if (item->hit_status || ((lara_info.distance < SWAT_AWARE_DISTANCE ||  TargetVisible(item, &lara_info)) && (abs(lara_item->pos.y_pos - item->pos.y_pos) < (WALL_L*2)))) // TS- TODO: take this back out after demo!!
		{
			if (!swat->alerted)
			{
				if (item->object_number == SWAT_GUN)
					SoundEffect(300, &item->pos, 0);
				else
					SoundEffect(299, &item->pos, 0);
			}
			AlertAllGuards(item_number);
		}
		swat->enemy = real_enemy;
/*
		if (swat->mood == BORED_MOOD)
			PrintDbug(2, 2, "Bored");
		else if (swat->mood == ESCAPE_MOOD)
			PrintDbug(2, 2, "Escape");
		else if (swat->mood == ATTACK_MOOD)
			PrintDbug(2, 2, "Attack");
		else if (swat->mood == STALK_MOOD)
			PrintDbug(2, 2, "Stalk");
*/
		switch (item->current_anim_state)
		{
		case SWAT_STOP:
			head = lara_info.angle;
			swat->flags = 0;

			swat->maximum_turn = 0;

			if (item->anim_number == objects[item->object_number].anim_index + SWAT_WALK_STOP_ANIM)
			{
				if (abs(info.angle) <  SWAT_RUN_TURN)
				item->pos.y_rot += info.angle;
				else if (info.angle < 0)
				item->pos.y_rot -= SWAT_RUN_TURN;
				else
				item->pos.y_rot += SWAT_RUN_TURN;
			}

			if (item->ai_bits & GUARD)
			{
				head = AIGuard(swat);
				if (!(GetRandomControl() & 0xFF))
				{
					if (item->current_anim_state == SWAT_STOP)
						item->goal_anim_state = SWAT_WAIT;
					else
						item->goal_anim_state = SWAT_STOP;
				}
				break;
			}

			else if (item->ai_bits & PATROL1)
			{
				item->goal_anim_state = SWAT_WALK;
				head=0;
			}

			else if (swat->mood == ESCAPE_MOOD)
				item->goal_anim_state = SWAT_RUN;
			else if (Targetable(item, &info))
			{
				if (info.distance < SWAT_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
				{
					if (GetRandomControl() < 0x4000)
						item->goal_anim_state = SWAT_AIM1;
					else
						item->goal_anim_state = SWAT_AIM3;
				}
				else
					item->goal_anim_state = SWAT_WALK;
			}
			else if (swat->mood == BORED_MOOD || ((item->ai_bits & FOLLOW ) && (swat->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
				item->goal_anim_state = SWAT_STOP;
			else if (swat->mood != BORED_MOOD && info.distance > SWAT_RUN_RANGE)
				item->goal_anim_state = SWAT_RUN;
			else
				item->goal_anim_state = SWAT_WALK;
			break;

		case SWAT_WAIT:
					head = lara_info.angle;
			swat->flags = 0;

			swat->maximum_turn = 0;
			if (item->ai_bits & GUARD)
			{
				head = AIGuard(swat);
				if (!(GetRandomControl() & 0xFF))
				{
					if (item->current_anim_state == SWAT_STOP)
						item->goal_anim_state = SWAT_WAIT;
					else
						item->goal_anim_state = SWAT_STOP;
				}
				break;
			}
			else if (Targetable(item, &info))
				item->goal_anim_state = SWAT_SHOOT1;
			else if (swat->mood != BORED_MOOD || !info.ahead)
				item->goal_anim_state = SWAT_STOP;
			break;

		case SWAT_WALK:
			head=lara_info.angle;
			swat->flags = 0;

			swat->maximum_turn = SWAT_WALK_TURN;
			if (item->ai_bits & PATROL1)
			{
				head=0;
				item->goal_anim_state = SWAT_WALK;
			}
			else if (swat->mood == ESCAPE_MOOD)
				item->goal_anim_state = SWAT_RUN;
			else if ((item->ai_bits & GUARD)  || ((item->ai_bits & FOLLOW ) && (swat->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
					item->goal_anim_state = SWAT_STOP;
			else if (Targetable(item, &info))
			{
				if (info.distance < SWAT_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
					item->goal_anim_state = SWAT_STOP;
				else
					item->goal_anim_state = SWAT_AIM2;
			}
			else if (swat->mood == BORED_MOOD && info.ahead)
				item->goal_anim_state = SWAT_STOP;
			else if (swat->mood != BORED_MOOD && info.distance > SWAT_RUN_RANGE)
				item->goal_anim_state = SWAT_RUN;
			break;

		case SWAT_RUN:
			if (info.ahead)
				head = info.angle;

			swat->maximum_turn = SWAT_RUN_TURN;
			tilt = angle/2;

			if ((item->ai_bits & GUARD)  || ((item->ai_bits & FOLLOW ) && (swat->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
				item->goal_anim_state = SWAT_WALK;
			else if (swat->mood == ESCAPE_MOOD)
				break;
			else if (Targetable(item, &info))
				item->goal_anim_state = SWAT_WALK;
			else if (swat->mood == BORED_MOOD || (swat->mood == STALK_MOOD && !(item->ai_bits & FOLLOW) && info.distance < SWAT_RUN_RANGE) )
				item->goal_anim_state = SWAT_WALK;
			break;

		case SWAT_AIM1:
		case SWAT_AIM3:
			swat->flags = 0;

			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;

				if (Targetable(item, &info))
					item->goal_anim_state = (item->current_anim_state==SWAT_AIM1)? SWAT_SHOOT1 : SWAT_SHOOT3;
				else
					item->goal_anim_state = SWAT_STOP;
			}
			break;

		case SWAT_AIM2:
			swat->flags = 0;

			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;

				if (Targetable(item, &info))
					item->goal_anim_state = SWAT_SHOOT2;
				else
					item->goal_anim_state = SWAT_WALK;
			}
			break;


		case SWAT_SHOOT3:
			if (item->goal_anim_state != SWAT_STOP)
			{
				if (swat->mood == ESCAPE_MOOD || info.distance > SWAT_SHOOT1_RANGE || !Targetable(item, &info))
					item->goal_anim_state = SWAT_STOP;
			}
		case SWAT_SHOOT2:
		case SWAT_SHOOT1:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}

			if (!swat->flags)
			{
				ShotLara(item, &info, &swat_gun, torso_y, SWAT_SHOT_DAMAGE);
				swat->flags = 5;
			}
			else
				swat->flags--;
			break;
		}
	}


#ifdef DEBUG_SWAT
	sprintf(exit_message, "%s", SwatStrings[item->current_anim_state]);
	PrintDbug(2, 4, exit_message);
	sprintf(exit_message, "%s", SwatStrings[item->goal_anim_state]);
	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "%s", SwatStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
	sprintf(exit_message, "AI:%d, goal:%d, alert:%d", item->ai_bits, swat->reached_goal,swat->alerted);
	PrintDbug(2,7, exit_message);
#endif


	CreatureTilt(item, tilt);
	CreatureJoint(item, 0, torso_y);
	CreatureJoint(item, 1, torso_x);
	CreatureJoint(item, 2, head);

	/* Actually do animation allowing for collisions */
	CreatureAnimation(item_number, angle, 0);
}
