/*********************************************************************************************/
/*                                                                                           */
/* MP with a Pistol (MP2) Control - TS - 21-8-98                                                            */
/*                                                                                           */
/*********************************************************************************************/

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

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

#include "objects.h"
#include "lara.h"
#include "control.h"
#include "sound.h"
#include "sphere.h"
#include "people.h"
#include "effect2.h"

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

void MPGunControl(sint16 item_number);

void *func[] = {
	&MPGunControl,
};

#endif

extern void  AlertAllGuards(sint16 item_number);


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

#define MPGUN_SHOT_DAMAGE 32
//#define MPGUN_SHOT_DAMAGE 1

enum mpgun_anims {MPGUN_EMPTY, MPGUN_WAIT, MPGUN_WALK, MPGUN_RUN, MPGUN_AIM1, MPGUN_SHOOT1, MPGUN_AIM2,
	MPGUN_SHOOT2, MPGUN_SHOOT3A, MPGUN_SHOOT3B, MPGUN_SHOOT4A, MPGUN_AIM3, MPGUN_AIM4, MPGUN_DEATH, MPGUN_SHOOT4B,
	MPGUN_DUCK, MPGUN_DUCKED, MPGUN_DUCKAIM, MPGUN_DUCKSHOT, MPGUN_DUCKWALK, MPGUN_STAND};
// TS - Upped the turn speeds

#define MPGUN_WALK_TURN (ONE_DEGREE*6)
#define MPGUN_RUN_TURN (ONE_DEGREE*10)

#define MPGUN_WALK_RANGE SQUARE(WALL_L*3/2)
#define MPGUN_FEELER_DISTANCE WALL_L

#define MPGUN_DIE_ANIM 14
#define MPGUN_AIM1_ANIM 12
#define MPGUN_AIM2_ANIM 13
#define MPGUN_WT1_SHT1_ANIM 1
#define MPGUN_WT1_SHT2_ANIM 4
#define MPGUN_WLK_SHT4A_ANIM 18
#define MPGUN_WLK_SHT4B_ANIM 19
#define MPGUN_WALK_WAIT_ANIM 17
#define MPGUN_RUN_WAIT1_ANIM 27
#define MPGUN_RUN_WAIT2_ANIM 28



#define MPGUN_DEATH_SHOT_ANGLE 0x2000
#define MPGUN_AWARE_DISTANCE SQUARE(WALL_L)


//#define DEBUG_MPGUN

#ifdef DEBUG_MPGUN
extern char exit_message[];
#endif

#ifdef DEBUG_MPGUN
static char *MPGunStrings[] = {
"EMPTY", "WAIT", "WALK", "RUN", "AIM1", "SHOOT1", "AIM2",
"SHOOT2", "SHOOT3A", "SHOOT3B", "SHOOT4A", "AIM3", "AIM4", "DEATH", "SHOOT4B",
"DUCK", "DUCKED", "DUCKAIM", "DUCKSHOT", "DUCKWALK", "STAND"
};
#endif

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

static BITE_INFO mpgun_gun = {0,160,40, 13};

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

extern CREATURE_INFO *baddie_slots;

void MPGunControl(sint16 item_number)
{
	ITEM_INFO *item, *target, *real_enemy;
	CREATURE_INFO *mpgun, *cinfo;
	sint16 angle, torso_y, torso_x, head, tilt, meta_mood, slot, room_number, near_cover;
	sint32 lara_dx, lara_dz, x, z, distance, y, height;
	int random;
	AI_INFO info, lara_info;
	FLOOR_INFO *floor;

	if (!CreatureActive(item_number))
		return;

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

	#ifdef DEBUG_MPGUN
	sprintf(exit_message, "%s", MPGunStrings[item->current_anim_state]);
	PrintDbug(2, 4, exit_message);
//	sprintf(exit_message, "%s", MPGunStrings[item->goal_anim_state]);
//	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "%s", MPGunStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
	sprintf(exit_message, "AI Bits:%d", item->ai_bits);
	PrintDbug(2,6, exit_message);

	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d", mpgun->alerted, mpgun->reached_goal, mpgun->hurt_by_lara);
	PrintDbug(2,7, exit_message);
//	sprintf(exit_message, "Head Left:%d, Head Right: %d", mpgun->head_left, mpgun->head_right);
//	PrintDbug(2,7, exit_message);

	#endif

	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)
	{
		item->hit_points = 0;
		if (item->current_anim_state != MPGUN_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + MPGUN_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MPGUN_DEATH;
		}
		else if (!(GetRandomControl() & 3) && item->frame_number == anims[item->anim_number].frame_base + 1) //This is the frame where the gun is fired
		{
			CreatureAIInfo(item, &info);
			if (Targetable(item, &info))
			{
				if (info.angle > -MPGUN_DEATH_SHOT_ANGLE && info.angle < MPGUN_DEATH_SHOT_ANGLE)
				{
					torso_y = info.angle;
					head = info.angle;
					ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE);
					SoundEffect(72, &item->pos, 3<<13); //Pitch & Volume wibble?
				}
			}

		}
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(mpgun);
		else
		{
			mpgun->enemy = lara_item;
			lara_dz = lara_item->pos.z_pos - item->pos.z_pos;
			lara_dx = lara_item->pos.x_pos - item->pos.x_pos;

			lara_info.distance = lara_dz * lara_dz + lara_dx * lara_dx;
			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 != BOB )
					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 < lara_info.distance)
					mpgun->enemy = target;
			}

		}

		CreatureAIInfo(item, &info);

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

		room_number = item->room_number;
		x = item->pos.x_pos + (MPGUN_FEELER_DISTANCE * phd_sin(item->pos.y_rot + lara_info.angle) >> W2V_SHIFT);
		y = item->pos.y_pos;
		z = item->pos.z_pos + (MPGUN_FEELER_DISTANCE * phd_cos(item->pos.y_rot + lara_info.angle) >> W2V_SHIFT);
		floor = GetFloor(x, y, z, &room_number);
		height = GetHeight(floor, x, y, z);
//		TriggerFlareSparks(x,y - STEP_L,z, -1,-1,0,1,1);
		near_cover = (item->pos.y_pos > (height + (STEP_L * 3 / 2)) && item->pos.y_pos < (height + (STEP_L * 9 / 2)) && lara_info.distance > MPGUN_AWARE_DISTANCE);
//		near_cover = ( (height - (STEP_L * 3 / 2)));

	#ifdef DEBUG_MPGUN
//	sprintf(exit_message, "head: %d, Target Visible?: %d", mpgun->joint_rotation[1], TargetVisible(item, &info));
//	PrintDbug(2, 5, exit_message);
	#endif

	real_enemy = mpgun->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
	mpgun->enemy = lara_item;
	if (lara_info.distance < MPGUN_AWARE_DISTANCE || item->hit_status || TargetVisible(item, &lara_info)) //Maybe move this into MPGUN_WAIT case?
		{
			if (!mpgun->alerted)
				SoundEffect(300, &item->pos, 0);
			AlertAllGuards(item_number);
		}
	mpgun->enemy = real_enemy;


#ifdef DEBUG_MPGUN
		if (mpgun->mood == BORED_MOOD)
			PrintDbug(2, 2, "Bored");
		else if (mpgun->mood == ESCAPE_MOOD)
			PrintDbug(2, 2, "Escape");
		else if (mpgun->mood == ATTACK_MOOD)
			PrintDbug(2, 2, "Attack");
		else if (mpgun->mood == STALK_MOOD)
			PrintDbug(2, 2, "Stalk");
#endif

		switch (item->current_anim_state)
		{
		case MPGUN_WAIT:
		//	if (info.ahead)
		//		head = info.angle;
			head = lara_info.angle;
		//	mpgun->flags = 0;

			mpgun->maximum_turn = 0;

			if (item->anim_number == objects[item->object_number].anim_index + MPGUN_WALK_WAIT_ANIM ||
				item->anim_number == objects[item->object_number].anim_index + MPGUN_RUN_WAIT1_ANIM ||
				item->anim_number == objects[item->object_number].anim_index + MPGUN_RUN_WAIT2_ANIM)
			{
				if (abs(info.angle) <  MPGUN_RUN_TURN)
				item->pos.y_rot += info.angle;
				else if (info.angle < 0)
				item->pos.y_rot -= MPGUN_RUN_TURN;
				else
				item->pos.y_rot += MPGUN_RUN_TURN;
			}

			if (item->ai_bits & GUARD)
			{
				head = AIGuard(mpgun);
				item->goal_anim_state = MPGUN_WAIT;
				break;
			}

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

			else if (near_cover && (lara.target == item || item->hit_status))
				item->goal_anim_state = MPGUN_DUCK;
			else if (item->required_anim_state == MPGUN_DUCK)
				item->goal_anim_state = MPGUN_DUCK;
			else if (mpgun->mood == ESCAPE_MOOD)
				item->goal_anim_state = MPGUN_RUN;
			else if (Targetable(item, &info))
			{
			//	if (info.distance > MPGUN_WALK_RANGE)
			//		item->goal_anim_state = MPGUN_WALK;
			//	else
				{
					// 3 different shooting stances to choose from!
					random = GetRandomControl();
					if (random < 0x2000)
						item->goal_anim_state = MPGUN_SHOOT1;
					else if (random < 0x4000)
						item->goal_anim_state = MPGUN_SHOOT2;
					else
						item->goal_anim_state = MPGUN_AIM3;
				}
			}
			else if (mpgun->mood == BORED_MOOD || ((item->ai_bits & FOLLOW ) && (mpgun->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
			{
				if (info.ahead)
					item->goal_anim_state = MPGUN_WAIT;
				else
					item->goal_anim_state = MPGUN_WALK;
			}
			else
				item->goal_anim_state = MPGUN_RUN;
			break;

		case MPGUN_WALK:
	//		if (info.ahead)
	//			head = info.angle;
			head=lara_info.angle;
	//		mpgun->flags = 0;

			mpgun->maximum_turn = MPGUN_WALK_TURN;
			if (item->ai_bits & PATROL1)
			{
				item->goal_anim_state = MPGUN_WALK;
				head = 0;
			}
			else if (near_cover && (lara.target == item || item->hit_status))
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			else if (mpgun->mood == ESCAPE_MOOD)
				item->goal_anim_state = MPGUN_RUN;
			else if (Targetable(item, &info))
			{
				if (info.distance > MPGUN_WALK_RANGE && info.zone_number == info.enemy_zone)
					item->goal_anim_state = MPGUN_AIM4;
				else
					item->goal_anim_state = MPGUN_WAIT;
			}
			else if (mpgun->mood == BORED_MOOD)
			{
				if (info.ahead)
					item->goal_anim_state = MPGUN_WALK;
				else
					item->goal_anim_state = MPGUN_WAIT;
			}
			else
				item->goal_anim_state = MPGUN_RUN;
			break;

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

			mpgun->maximum_turn = MPGUN_RUN_TURN;
			tilt = angle/2;
			if (item->ai_bits & GUARD)
				item->goal_anim_state = MPGUN_WAIT;
			else if (near_cover && (lara.target == item || item->hit_status))
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			else if (mpgun->mood == ESCAPE_MOOD)
				break;
			else if (Targetable(item, &info) || ((item->ai_bits & FOLLOW ) && (mpgun->reached_goal || lara_info.distance > SQUARE(WALL_L*2))))
				item->goal_anim_state = MPGUN_WAIT;
			else if (mpgun->mood == BORED_MOOD)
				item->goal_anim_state = MPGUN_WALK;
			break;

		case MPGUN_AIM1:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}

			if ((item->anim_number == objects[MP2].anim_index + MPGUN_AIM1_ANIM) || (item->anim_number == objects[MP2].anim_index + MPGUN_WT1_SHT1_ANIM && item->frame_number == anims[item->anim_number].frame_base + 10)) // Cheers, Phil :)
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE))
					item->required_anim_state = MPGUN_WAIT;
			}
			else if (item->hit_status && !(GetRandomControl() & 0x3) && near_cover)
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			break;

		case MPGUN_SHOOT1:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}
			if (item->required_anim_state == MPGUN_WAIT)
				item->goal_anim_state = MPGUN_WAIT;
			break;

		case MPGUN_SHOOT2:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}
			if (item->frame_number == anims[item->anim_number].frame_base)
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE))
					item->goal_anim_state = MPGUN_WAIT;
			}
			else if (item->hit_status && !(GetRandomControl() & 0x3) && near_cover)
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			break;

		case MPGUN_SHOOT3A:
		case MPGUN_SHOOT3B:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}
			if (item->frame_number == anims[item->anim_number].frame_base || (item->frame_number == anims[item->anim_number].frame_base + 11))
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE))
					item->goal_anim_state = MPGUN_WAIT;
			}
			else if (item->hit_status && !(GetRandomControl() & 0x3) && near_cover)
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			break;

		case MPGUN_AIM4:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}
			if ((item->anim_number == objects[MP2].anim_index + MPGUN_WLK_SHT4A_ANIM && item->frame_number == anims[item->anim_number].frame_base + 17) || (item->anim_number == objects[MP2].anim_index + MPGUN_WLK_SHT4B_ANIM && item->frame_number == anims[item->anim_number].frame_base + 6)) // Cheers, Phil :)
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE))
					item->required_anim_state = MPGUN_WALK;
			}
			else if (item->hit_status && !(GetRandomControl() & 0x3) && near_cover)
			{
				item->required_anim_state = MPGUN_DUCK;
				item->goal_anim_state = MPGUN_WAIT;
			}
			// Go back to walk so guard can stop when he gets close enough
			if (info.distance < MPGUN_WALK_RANGE)
				item->required_anim_state = MPGUN_WALK;
			break;

		case MPGUN_SHOOT4A:
		case MPGUN_SHOOT4B:
			if (info.ahead)
			{
				torso_y = info.angle;
				torso_x = info.x_angle;
			}
			if (item->required_anim_state == MPGUN_WALK)
			{
				item->goal_anim_state = MPGUN_WALK;
			}
			if (item->frame_number == anims[item->anim_number].frame_base + 16)
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE))
					item->goal_anim_state = MPGUN_WALK;
			}
			// Go back to walk so guard can stop when he gets close enough
			if (info.distance < MPGUN_WALK_RANGE)
				item->goal_anim_state = MPGUN_WALK;
			break;

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

			mpgun->maximum_turn = 0;

			if (Targetable(item, &info))
				item->goal_anim_state = MPGUN_DUCKAIM;
			else if (item->hit_status || !near_cover || (info.ahead && !(GetRandomControl() & 0x1F)))
				item->goal_anim_state = MPGUN_STAND;
			else 
				item->goal_anim_state = MPGUN_DUCKWALK;
			break;

		case MPGUN_DUCKAIM:
			mpgun->maximum_turn = ONE_DEGREE;

			if (info.ahead)
				torso_y = info.angle;

			if (Targetable(item, &info))
				item->goal_anim_state = MPGUN_DUCKSHOT;
			else
				item->goal_anim_state = MPGUN_DUCKED;
			break;

		case MPGUN_DUCKSHOT:
			if (info.ahead)
				torso_y = info.angle;

			if (item->frame_number == anims[item->anim_number].frame_base)
			{
				if (!ShotLara(item, &info, &mpgun_gun, torso_y, MPGUN_SHOT_DAMAGE) || !(GetRandomControl() & 0x7))
					item->goal_anim_state = MPGUN_DUCKED;
			}

			break;

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

			mpgun->maximum_turn = MPGUN_WALK_TURN;

			if (Targetable(item, &info) || item->hit_status || !near_cover || (info.ahead && !(GetRandomControl() & 0x1F)))
				item->goal_anim_state = MPGUN_DUCKED;
			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);
}
