/*********************************************************************************************/
/*                                                                                           */
/* OilSMG 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"


void InitialiseOilSMG(sint16 item_number);
void OilSMGControl(sint16 item_number);

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

void *func[] = {
	&InitialiseOilSMG,
	&OilSMGControl,
};

#endif

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

//#define OILSMG_SHOT_DAMAGE 30
#define OILSMG_SHOT_DAMAGE 1


// WORKER2: machine gun man
// WORKER4: flame thrower man

enum oilsmg_anims {OILSMG_EMPTY, OILSMG_STOP, OILSMG_WALK, OILSMG_RUN, OILSMG_WAIT, OILSMG_SHOOT1, OILSMG_SHOOT2, OILSMG_DEATH, OILSMG_AIM1, OILSMG_AIM2, OILSMG_AIM3, OILSMG_SHOOT3};

#define OILSMG_WALK_TURN (ONE_DEGREE*5)
#define OILSMG_RUN_TURN (ONE_DEGREE*10)

#define OILSMG_RUN_RANGE SQUARE(WALL_L*2)
#define OILSMG_SHOOT1_RANGE SQUARE(WALL_L*3)

#define OILSMG_DIE_ANIM 19
#define OILSMG_STOP_ANIM 12
#define OILSMG_DEATH_SHOT_ANGLE 0x2000
#define OILSMG_AWARE_DISTANCE SQUARE(WALL_L)

#define DEBUG_OILSMG

#ifdef DEBUG_OILSMG
extern char exit_message[];
#endif

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

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

static BITE_INFO oilsmg_gun = {0,400,64, 7};

/*********************************** FUNCTION CODE *******************************************/
extern int Targetable(ITEM_INFO *item, AI_INFO *info);
extern void ControlGlow(sint16 nFX);
extern void Glow(sint32 x,sint32 y,sint32 z,sint16 nRoom,sint16 nFrames,sint16 nShade,sint16 nShadeDelta,sint16 nScale,sint16 nScaleDelta,sint32 dwFlags);
extern void ControlGunShot(sint16 fx_number);
extern sint16 GunShot(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number);
extern sint16 GunHit(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number);
extern sint16 GunMiss(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number);
extern int ShotLara(ITEM_INFO *item, AI_INFO *info, BITE_INFO *gun, sint16 extra_rotation, int damage);


void InitialiseOilSMG(sint16 item_number)
{
	ITEM_INFO *item;

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

	/* Start OilSMG in stop pose*/
	item->anim_number = objects[WHITE_SOLDIER].anim_index + OILSMG_STOP_ANIM;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = item->goal_anim_state = OILSMG_STOP;
}


void OilSMGControl(sint16 item_number)
{
	//Oil SMG man

	ITEM_INFO *item, *target_item, *real_enemy;
	CREATURE_INFO *oilsmg;
	sint16 angle, torso_y, torso_x, head, tilt, i;
	sint32 lara_dx, lara_dz;
	int random;
	AI_INFO info, lara_info;

	if (!CreatureActive(item_number))
		return;

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

	#ifdef DEBUG_OILSMG
	sprintf(exit_message, "%s", OilSMGStrings[item->current_anim_state]);
	PrintDbug(2, 4, exit_message);
//	sprintf(exit_message, "%s", OilSMGStrings[item->goal_anim_state]);
//	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "%s", OilSMGStrings[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 != OILSMG_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + OILSMG_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = OILSMG_DEATH;
			if (!(GetRandomControl() & 3))
				oilsmg->flags = 1;
			else
				oilsmg->flags = 0;
		}
		else if (oilsmg->flags && (item->frame_number > anims[item->anim_number].frame_base + 3 && item->frame_number < anims[item->anim_number].frame_base + 12))
		{
			CreatureAIInfo(item, &info);
	/*		if (Targetable(item, &info))
			{
				if (info.angle > -OILSMG_DEATH_SHOT_ANGLE && info.angle < OILSMG_DEATH_SHOT_ANGLE)
				{*/
					torso_y = info.angle;
					head = info.angle;
					ShotLara(item, &info, &oilsmg_gun, 0, 0);
		//			CreatureEffect(item, &oilsmg_gun, GunShot);
	/*			}
			}
	*/
		}
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(oilsmg);
		else
			oilsmg->enemy = lara_item;

		CreatureAIInfo(item, &info);

		if (oilsmg->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;
		}

		GetCreatureMood(item, &info, VIOLENT);	//TODO: TS - change to VIOLENT or TIMID depending on AI job
												// or maybe do it in GetCreatureMood
		CreatureMood(item, &info, VIOLENT);

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

		real_enemy = oilsmg->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
		oilsmg->enemy = lara_item;
		if ((lara_info.distance < OILSMG_AWARE_DISTANCE || item->hit_status || TargetVisible(item, &lara_info)) && !(item->ai_bits & FOLLOW)) //Maybe move this into OILSMG_WAIT case?
			AlertAllGuards(item_number);
		oilsmg->enemy = real_enemy;

		if (oilsmg->mood == BORED_MOOD)
			PrintDbug(2, 2, "Bored");
		else if (oilsmg->mood == ESCAPE_MOOD)
			PrintDbug(2, 2, "Escape");
		else if (oilsmg->mood == ATTACK_MOOD)
			PrintDbug(2, 2, "Attack");
		else if (oilsmg->mood == STALK_MOOD)
			PrintDbug(2, 2, "Stalk");

		switch (item->current_anim_state)
		{
		case OILSMG_STOP:
			head = lara_info.angle;
			oilsmg->flags = 0;

			oilsmg->maximum_turn = 0;
			if (item->ai_bits & GUARD)
			{
				head = AIGuard(oilsmg);
				if (!(GetRandomControl() & 0xFF))
				{
					if (item->current_anim_state == OILSMG_STOP)
						item->goal_anim_state = OILSMG_WAIT;
					else
						item->goal_anim_state = OILSMG_STOP;
				}
				break;
			}

			else if (item->ai_bits & PATROL1)
				item->goal_anim_state = OILSMG_WALK;

			else if (oilsmg->mood == ESCAPE_MOOD)
				item->goal_anim_state = OILSMG_RUN;
			else if (Targetable(item, &info))
			{
				if (info.distance < OILSMG_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
				{
					if (GetRandomControl() < 0x4000)
						item->goal_anim_state = OILSMG_AIM1;
					else
						item->goal_anim_state = OILSMG_AIM3;
				}
				else
					item->goal_anim_state = OILSMG_WALK;
			}
			else if (oilsmg->mood == BORED_MOOD || ((item->ai_bits & FOLLOW ) && (oilsmg->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
				item->goal_anim_state = OILSMG_STOP;
			else if (info.distance > OILSMG_RUN_RANGE)
				item->goal_anim_state = OILSMG_RUN;
			else
				item->goal_anim_state = OILSMG_WALK;
			break;

		case OILSMG_WAIT:
					head = lara_info.angle;
			oilsmg->flags = 0;

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

		case OILSMG_WALK:
			head=lara_info.angle;
			oilsmg->flags = 0;

			oilsmg->maximum_turn = OILSMG_WALK_TURN;
			if (item->ai_bits & PATROL1)
			{
				item->goal_anim_state = OILSMG_WALK;
				head=0;
			}
			else if (oilsmg->mood == ESCAPE_MOOD)
				item->goal_anim_state = OILSMG_RUN;
			else if ((item->ai_bits & GUARD)  || ((item->ai_bits & FOLLOW ) && (oilsmg->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
					item->goal_anim_state = OILSMG_STOP;
			else if (Targetable(item, &info))
			{
				if (info.distance < OILSMG_SHOOT1_RANGE || info.zone_number != info.enemy_zone)
					item->goal_anim_state = OILSMG_STOP;
				else
					item->goal_anim_state = OILSMG_AIM2;
			}
			else if (oilsmg->mood == BORED_MOOD && info.ahead)
				item->goal_anim_state = OILSMG_STOP;
			else if (info.distance > OILSMG_RUN_RANGE)
				item->goal_anim_state = OILSMG_RUN;
			break;

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

			oilsmg->maximum_turn = OILSMG_RUN_TURN;
			tilt = angle/2;

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

		case OILSMG_AIM1:
		case OILSMG_AIM3:
			oilsmg->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==OILSMG_AIM1)? OILSMG_SHOOT1 : OILSMG_SHOOT3;
				else
					item->goal_anim_state = OILSMG_STOP;
			}
			break;

		case OILSMG_AIM2:
			oilsmg->flags = 0;

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

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


		case OILSMG_SHOOT3:
			if (item->goal_anim_state != OILSMG_STOP)
			{
				if (oilsmg->mood == ESCAPE_MOOD || info.distance > OILSMG_SHOOT1_RANGE || !Targetable(item, &info))
					item->goal_anim_state = OILSMG_STOP;
			}
		case OILSMG_SHOOT2:
		case OILSMG_SHOOT1:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}

			if (!oilsmg->flags)
			{
				ShotLara(item, &info, &oilsmg_gun, torso_y, OILSMG_SHOT_DAMAGE);
				oilsmg->flags = 5;
			}
			else
				oilsmg->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);
}
