/*********************************************************************************************/
/*                                                                                           */
/* Army Control  - TS - August 98                                                                        */
/*                                                                                           */
/*********************************************************************************************/

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

void InitialiseArmySMG(sint16 item_number);
void ArmySMGControl(sint16 item_number);

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

void *func[] __attribute__((section(".header"))) = {
	&InitialiseArmySMG,
	&ArmySMGControl,
};

#endif

extern CREATURE_INFO *baddie_slots;

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

//#define ARMY_SHOT_DAMAGE 1
#define ARMY_SHOT_DAMAGE 28


enum army_anims {ARMY_EMPTY, ARMY_STOP, ARMY_WALK, ARMY_RUN, ARMY_WAIT, ARMY_SHOOT1, ARMY_SHOOT2, ARMY_DEATH, ARMY_AIM1, ARMY_AIM2, ARMY_AIM3, ARMY_SHOOT3};

#define ARMY_WALK_TURN (ONE_DEGREE*5)
#define ARMY_RUN_TURN (ONE_DEGREE*10)

#define ARMY_RUN_RANGE SQUARE(WALL_L*2)
#define ARMY_SHOOT1_RANGE SQUARE(WALL_L*3)

#define ARMY_DIE_ANIM 19
#define ARMY_STOP_ANIM 12
#define ARMY_WALK_STOP_ANIM 17
#define ARMY_DEATH_SHOT_ANGLE 0x2000
#define ARMY_AWARE_DISTANCE SQUARE(WALL_L)

//#define DEBUG_ARMY

#ifdef DEBUG_ARMY
extern char exit_message[];
#endif

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

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

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

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

void InitialiseArmySMG(sint16 item_number)
{
	ITEM_INFO *item;

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

	/* Start Army in stop pose*/
	item->anim_number = objects[STHPAC_MERCENARY].anim_index + ARMY_STOP_ANIM;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = item->goal_anim_state = ARMY_STOP;
}

void ArmySMGControl(sint16 item_number)
{
	//Army SMG man / South Pacific Mercenary

	ITEM_INFO *item, *target, *real_enemy;
	CREATURE_INFO *army, *cinfo;
	sint16 angle, torso_y, torso_x, head, tilt, meta_mood, slot;
	sint32 lara_dx, lara_dz, x, z, distance, best_distance;
	AI_INFO info, lara_info;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];
	army = (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 = army_gun.x;
		pos.y = army_gun.y;
		pos.z = army_gun.z;
		GetJointAbsPosition(item, &pos, army_gun.mesh_num);
		TriggerDynamic(pos.x, pos.y, pos.z, (item->fired_weapon<<1)+8, 24, 16, 4);
		phd_PopMatrix();
	}

	#ifdef DEBUG_ARMY
	sprintf(exit_message, "%s", ArmyStrings[item->current_anim_state]);
	PrintDbug(2, 4, exit_message);
	sprintf(exit_message, "Mood:%d, AI:%d, patrol:%d, target:%d", army->mood, item->ai_bits, army->patrol2, army->enemy == NULL ? -1 : army->enemy->object_number);
	PrintDbug(2, 2, exit_message);

//	sprintf(exit_message, "%s", ArmyStrings[item->goal_anim_state]);
//	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "%s", ArmyStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "AI Bits:%d", item->ai_bits);
//	PrintDbug(2,7, exit_message);
	#endif


	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != ARMY_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + ARMY_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = ARMY_DEATH;

			if (!(GetRandomControl() & 3))
				army->flags = 1;
			else
				army->flags = 0;

		} // TS - TODO: random gun shot (unaimed) during death
		/*
		else if (army->flags && item->frame_number > anims[item->anim_number].frame_base + 44 && item->frame_number < anims[item->anim_number].frame_base + 52) //These are the frames where the gun is fired
		{
			CreatureAIInfo(item, &info);
			if (Targetable(item, &info))
			{
				if (info.angle > -ARMY_DEATH_SHOT_ANGLE && info.angle < ARMY_DEATH_SHOT_ANGLE)
				{
					torso_y = info.angle;
					head = info.angle;
					ShotLara(item, &info, &army_gun, torso_y, ARMY_SHOT_DAMAGE*3);
					SoundEffect(91, &item->pos, 3<<13); //Pitch & Volume wibble?

				}
			}
		}
		*/
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(army);
		else if (army->hurt_by_lara)
			army->enemy = lara_item;
		else
		{
			army->enemy = NULL;
			best_distance = 0x7fffffff;
			cinfo = baddie_slots;
			for (slot=0; slot<NUM_SLOTS; slot++, cinfo++)
			{
				if (cinfo->item_num==NO_ITEM || cinfo->item_num==item_number)
					continue;
				target = &items[cinfo->item_num];
				if (target->object_number == LARA  || target->object_number == STHPAC_MERCENARY || (target==lara_item && !army->hurt_by_lara))
					continue;
				/* Is this target closest? */
				x = target->pos.x_pos - item->pos.x_pos;
				z = target->pos.z_pos - item->pos.z_pos;
				distance = x*x + z*z;
				if (distance < best_distance)
				{
					army->enemy = target;
					best_distance = distance;
				}
			}

		}


		CreatureAIInfo(item, &info);


		if (army->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 (!army->hurt_by_lara && army->enemy == lara_item)
			army->enemy = NULL;

		if (army->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, army->maximum_turn);

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

			army->maximum_turn = 0;

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

			if (item->ai_bits & GUARD)
			{
				head = AIGuard(army);
				if (!(GetRandomControl() & 0xFF))
				{
					if (item->current_anim_state == ARMY_STOP)
						item->goal_anim_state = ARMY_WAIT;
					else
						item->goal_anim_state = ARMY_STOP;
				}
				break;
			}

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

			else if (army->mood == ESCAPE_MOOD)
				item->goal_anim_state = ARMY_RUN;
			else if (Targetable(item, &info))
			{
				if (info.distance < ARMY_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
				{
					if (GetRandomControl() < 0x4000)
						item->goal_anim_state = ARMY_AIM1;
					else
						item->goal_anim_state = ARMY_AIM3;
				}
				else
					item->goal_anim_state = ARMY_WALK;
			}
			else if ((!army->alerted && army->mood == BORED_MOOD) || ((item->ai_bits & FOLLOW ) && (army->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
				item->goal_anim_state = ARMY_STOP;
			else if (army->mood != BORED_MOOD && info.distance > ARMY_RUN_RANGE)
				item->goal_anim_state = ARMY_RUN;
			else
				item->goal_anim_state = ARMY_WALK;
			break;

		case ARMY_WAIT:
					head = lara_info.angle;
			army->flags = 0;

			army->maximum_turn = 0;
			if (item->ai_bits & GUARD)
			{
				head = AIGuard(army);
				if (!(GetRandomControl() & 0xFF))
						item->goal_anim_state = ARMY_STOP;
				break;
			}
			else if (Targetable(item, &info))
				item->goal_anim_state = ARMY_SHOOT1;
			else if (army->mood != BORED_MOOD || !info.ahead)
				item->goal_anim_state = ARMY_STOP;
			break;

		case ARMY_WALK:
			head=lara_info.angle;
			army->flags = 0;

			army->maximum_turn = ARMY_WALK_TURN;
			if (item->ai_bits & PATROL1)
				item->goal_anim_state = ARMY_WALK;
			else if (army->mood == ESCAPE_MOOD)
				item->goal_anim_state = ARMY_RUN;
			else if ((item->ai_bits & GUARD)  || ((item->ai_bits & FOLLOW ) && (army->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
					item->goal_anim_state = ARMY_STOP;
			else if (Targetable(item, &info))
			{
				if (info.distance < ARMY_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
					item->goal_anim_state = ARMY_STOP;
				else
					item->goal_anim_state = ARMY_AIM2;
			}
			else if (army->mood == BORED_MOOD && info.ahead)
				item->goal_anim_state = ARMY_STOP;
			else if (army->mood != BORED_MOOD && info.distance > ARMY_RUN_RANGE)
				item->goal_anim_state = ARMY_RUN;
			break;

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

			army->maximum_turn = ARMY_RUN_TURN;
			tilt = angle/2;

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

		case ARMY_AIM1:
		case ARMY_AIM3:
			army->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==ARMY_AIM1)? ARMY_SHOOT1 : ARMY_SHOOT3;
				else
					item->goal_anim_state = ARMY_STOP;
			}
			break;

		case ARMY_AIM2:
			army->flags = 0;

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

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


		case ARMY_SHOOT3:
			if (item->goal_anim_state != ARMY_STOP)
			{
				if (army->mood == ESCAPE_MOOD || info.distance > ARMY_SHOOT1_RANGE || !Targetable(item, &info))
					item->goal_anim_state = ARMY_STOP;
			}
		case ARMY_SHOOT2:
		case ARMY_SHOOT1:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}

			if (!army->flags)
			{
				ShotLara(item, &info, &army_gun, torso_y, ARMY_SHOT_DAMAGE);
				army->flags = 5;
			}
			else
				army->flags--;
			break;
		}
	}

	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);
}
