/*********************************************************************************************/
/*                                                                                           */
/* Seal Mutant Control - TS  - 14/8/98                                                     */
/*                                                                                           */
/*********************************************************************************************/

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

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

#include "objects.h"
#include "items.h"
#include "box.h"
#include "lara.h"
#include "laraanim.h"
#include "control.h"
#include "people.h"
#include "sphere.h"
#include "effect2.h"

static sint16 TriggerSealmuteGasThrower(ITEM_INFO *item, BITE_INFO *bite, sint16 speed);
static void TriggerSealmuteGas(long x, long y, long z, long xv, long yv, long zv, long fxnum);

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

#define SEAL_BITE_DAMAGE 100
#define SEAL_SLASH_TOUCH (0x80)
#define SEAL_KICK_TOUCH (0x4000)

#define SEAL_DIE_ANIM 5

#define SEAL_WALK_TURN (3*ONE_DEGREE)
#define SEAL_RUN_TURN  (6*ONE_DEGREE)

#define SEAL_ATTACK1_RANGE SQUARE(WALL_L)
#define SEAL_ATTACK2_RANGE SQUARE(WALL_L*2)
#define SEAL_ATTACK3_RANGE SQUARE(WALL_L*4/3)
#define SEAL_FIRE_RANGE SQUARE(WALL_L*2)
#define SEAL_ROAR_CHANCE 0x60
#define SEAL_WALK_CHANCE (SEAL_ROAR_CHANCE + 0x400)
#define SEAL_AWARE_DISTANCE SQUARE(WALL_L)
#define SEALMUTE_FLAME_LIMIT 80
enum seal_anims {
	SEAL_STOP,
	SEAL_WALK,
	SEAL_BURP,
	SEAL_DEATH
};

/*---------------------------------------------------------------------------
 *	Externals
\*--------------------------------------------------------------------------*/
//#define DEBUG_SEAL

#ifdef DEBUG_SEAL
extern char exit_message[];
#endif

#ifdef DEBUG_SEAL
static char *SealStrings[] = {"STOP", "WALK", "BURP", "DEATH"};
#endif

//Gibby - the place where he shoots from is his head, which is mesh_num 10
//He actually 'fires' on frame 46 of the BURP anim
/*---------------------------------------------------------------------------
 *	Locals
\*--------------------------------------------------------------------------*/

static BITE_INFO seal_gas = {0,48,140, 10};
//static BITE_INFO seal_bite_right = {19,-13,3, 14};

/*---------------------------------------------------------------------------
 *	Public Functions
\*--------------------------------------------------------------------------*/
extern CREATURE_INFO *baddie_slots;

void SealmuteControl(sint16 item_number)
{
	ITEM_INFO *item, *target, *real_enemy;
	CREATURE_INFO *seal, *cinfo;
	sint16 angle, head, torso_y, torso_x, tilt, slot;
	sint32 lara_dx, lara_dz, x, z, distance;
	AI_INFO info, lara_info;

	if (!CreatureActive(item_number))
		return;

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

	if (item->item_flags[0] > SEALMUTE_FLAME_LIMIT)
		item->hit_points = 0;

	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != SEAL_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + SEAL_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = SEAL_DEATH;
			seal->flags = 0;
			//item->item_flags[0] = 1;	// Make him burn.
		}
		else if (item->item_flags[0] > SEALMUTE_FLAME_LIMIT)	// Set on fire by flamer blokes?
		{
			PHD_VECTOR pos;
			long	bright,r,g,b,rnd;

			for (r=9;r<17;r++)	// Loop through all of Sealmutes nodes.
			{
				if ((wibble&4) == 0)	// Trigger some flames ?
				{
					pos.x = 0;
					pos.y = 0;
					pos.z = 0;
					GetJointAbsPosition(item, &pos, r);
					TriggerFireFlame(pos.x, pos.y, pos.z,-1,255);
				}
			}

			bright = item->frame_number - anims[item->anim_number].frame_base;
			if (bright > 16)
			{
				bright = anims[item->anim_number].frame_end - item->frame_number;
				if (bright > 16)
					bright = 16;
			}

			rnd = GetRandomControl();
			r=31-((rnd>>4)&3);
			g=24-((rnd>>6)&7);
			b=rnd&7;
			r = (r*bright)>>4;
			g = (g*bright)>>4;
			b = (b*bright)>>4;

			TriggerDynamic(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,12,r,g,b);
		}
		else
		{
			if (	item->frame_number >= anims[item->anim_number].frame_base + 1 &&
				item->frame_number <= anims[item->anim_number].frame_end - 8)
			{
				unsigned long	length;

				length = item->frame_number - anims[item->anim_number].frame_base + 1;
				if (length > 24)
				{
					length = anims[item->anim_number].frame_end - item->frame_number - 8;
					if (length <= 0)
						length = 1;

					if (length > 24)
						length = (GetRandomControl()&15)+8;
				}
				TriggerSealmuteGasThrower(item, &seal_gas, length);
			}
		}
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(seal);
		else
		{
			seal->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 != FLAMETHROWER_BLOKE ) || target->hit_points <= 0)
					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)
					seal->enemy = target;
			}

		}

		CreatureAIInfo(item, &info);

	//	if (info.ahead)
	//		head = info.angle;
		if (seal->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 (info.zone_number == info.enemy_zone)
		{
			GetCreatureMood(item, &info, VIOLENT);
			if (seal->enemy == lara_item && lara.poisoned >= 0x100)
				seal->mood = ESCAPE_MOOD;
			CreatureMood(item, &info, VIOLENT);
		}
		else
		{
			GetCreatureMood(item, &info, TIMID);
			if (seal->enemy == lara_item && lara.poisoned >= 0x100)
				seal->mood = ESCAPE_MOOD;
			CreatureMood(item, &info, TIMID);
		}

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

		real_enemy = seal->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
		seal->enemy = lara_item;
		if (lara_info.distance < SEAL_AWARE_DISTANCE || item->hit_status || TargetVisible(item, &lara_info))
			AlertAllGuards(item_number);
		seal->enemy = real_enemy;


		switch (item->current_anim_state)
		{
		case SEAL_STOP:
			seal->maximum_turn = 0;
			seal->flags = 0;

			head = info.angle;
			if (item->ai_bits & GUARD)
			{
				head = AIGuard(seal);
			//	torso_y = head >> 3;
				item->goal_anim_state = SEAL_STOP;
				break;
			}
			else if (item->ai_bits & PATROL1)
			{
				item->goal_anim_state = SEAL_WALK;
				head= 0;
			}
			else if (seal->mood == ESCAPE_MOOD)
				item->goal_anim_state = SEAL_WALK;
			else if (Targetable(item, &info) && info.distance < SEAL_FIRE_RANGE)
				item->goal_anim_state = SEAL_BURP;
			else if (item->required_anim_state)
				item->goal_anim_state = item->required_anim_state;
			else
				item->goal_anim_state = SEAL_WALK;
			break;

		case SEAL_WALK:
			seal->maximum_turn = SEAL_WALK_TURN;
			if (info.ahead)
				head = info.angle;
			if (item->ai_bits & PATROL1)
			{
				item->goal_anim_state = SEAL_WALK;
				head = 0;
			}
			else if (Targetable(item, &info) && info.distance < SEAL_FIRE_RANGE)
			{
			//	claw->maximum_turn = SEAL_WALK_TURN;
				item->goal_anim_state = SEAL_STOP;
			}
			break;


		case SEAL_BURP:

			if (abs(info.angle) <  SEAL_WALK_TURN)
				item->pos.y_rot += info.angle;
			else if (info.angle < 0)
				item->pos.y_rot -= SEAL_WALK_TURN;
			else
				item->pos.y_rot += SEAL_WALK_TURN;

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

			if (	item->frame_number >= anims[item->anim_number].frame_base + 35 &&
				item->frame_number <= anims[item->anim_number].frame_base + 58)
			{
				if (seal->flags<24)
					seal->flags+=3;

				if (seal->flags<24)
					TriggerSealmuteGasThrower(item, &seal_gas, seal->flags);
				else
					TriggerSealmuteGasThrower(item, &seal_gas, (GetRandomControl()&15)+8);
				if (seal->enemy != lara_item)
					seal->enemy->hit_status = 1;
			}
		}
	}

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

#ifdef DEBUG_SEAL
	sprintf(exit_message, "Mood: %d", seal->mood);
	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", SealStrings[item->current_anim_state]);
	PrintDbug(2, 3, exit_message);
	sprintf(exit_message, "%s", SealStrings[item->goal_anim_state]);
	PrintDbug(2, 4, exit_message);
//	sprintf(exit_message, "%s", SealStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Anim Number; %d", item->anim_number - objects[MUTANT2].anim_index);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d", seal->alerted, seal->reached_goal, seal->hurt_by_lara);
//	PrintDbug(2,6, exit_message);
	sprintf(exit_message, "Mood: %d", seal->mood);
	PrintDbug(2,7, exit_message);
#endif

	CreatureAnimation(item_number, angle, tilt);

}


static sint16 TriggerSealmuteGasThrower(ITEM_INFO *item, BITE_INFO *bite, sint16 speed)
{
	PHD_VECTOR	pos1,pos2;
	FX_INFO		*fx;
	sint16 		fx_number;
	PHD_ANGLE		angles[2];
	long			xv,yv,zv,vel,spd,lp;


	fx_number = CreateEffect(item->room_number);


	if (fx_number != NO_ITEM)
	{
		fx = &effects[fx_number];

		pos1.x = bite->x;
		pos1.y = bite->y;
		pos1.z = bite->z;
		GetJointAbsPosition( item, &pos1, bite->mesh_num );
		pos2.x = bite->x;
		pos2.y = bite->y<<1;
		pos2.z = bite->z<<3;
		GetJointAbsPosition( item, &pos2, bite->mesh_num );

		phd_GetVectorAngles( pos2.x-pos1.x,pos2.y-pos1.y,pos2.z-pos1.z, angles );

		fx->pos.x_pos = pos1.x;
		fx->pos.y_pos = pos1.y;
		fx->pos.z_pos = pos1.z;
		fx->room_number = item->room_number;
		fx->pos.x_rot = angles[1];
		fx->pos.z_rot = 0;
		fx->pos.y_rot = angles[0];
		fx->speed = speed<<2;
		fx->object_number = DRAGON_FIRE;
		fx->counter = 20;
		fx->flag1 = 1;	// Set to not fire.

		TriggerSealmuteGas(0,0,0,0,0,0,fx_number);

		for (lp=0;lp<2;lp++)
		{
			spd = (GetRandomControl()%(speed<<2))+32;
			vel = (spd * phd_cos(fx->pos.x_rot)) >> W2V_SHIFT;
			zv = (vel * phd_cos(fx->pos.y_rot)) >> W2V_SHIFT;
			xv = (vel * phd_sin(fx->pos.y_rot)) >> W2V_SHIFT;
			yv = -((spd * phd_sin(fx->pos.x_rot)) >> W2V_SHIFT);
			TriggerSealmuteGas(fx->pos.x_pos,fx->pos.y_pos,fx->pos.z_pos,xv<<5,yv<<5,zv<<5,-1);
		}

		vel = ((speed<<1) * phd_cos(fx->pos.x_rot)) >> W2V_SHIFT;
		zv = (vel * phd_cos(fx->pos.y_rot)) >> W2V_SHIFT;
		xv = (vel * phd_sin(fx->pos.y_rot)) >> W2V_SHIFT;
		yv = -(((speed<<1) * phd_sin(fx->pos.x_rot)) >> W2V_SHIFT);
		TriggerSealmuteGas(fx->pos.x_pos,fx->pos.y_pos,fx->pos.z_pos,xv<<5,yv<<5,zv<<5,-2);
	}

	return (fx_number);
}

static void TriggerSealmuteGas(long x, long y, long z, long xv, long yv, long zv, long fxnum)
{
	long		size;
	SPARKS	*sptr;

	sptr = &spark[GetFreeSpark()];

	sptr->On = 1;
	sptr->sR = 128+(GetRandomControl()&63);
	sptr->sG = 128+(GetRandomControl()&63);
	sptr->sB = 32;

	sptr->dR = 32+(GetRandomControl()&15);
	sptr->dG = 32+(GetRandomControl()&15);
	sptr->dB = 0;

	if (xv||yv||zv)
	{
		sptr->ColFadeSpeed = 6;
		sptr->FadeToBlack = 2;
		sptr->sLife = sptr->Life = (GetRandomControl()&1)+16;
	}
	else
	{
		sptr->ColFadeSpeed = 8;
		sptr->FadeToBlack = 16;
		sptr->sLife = sptr->Life = (GetRandomControl()&3)+28;
	}

	sptr->TransType = COLADD;

	sptr->extras = 0;
	sptr->Dynamic = -1;

	sptr->x = x + ((GetRandomControl()&31)-16);
	sptr->y = y;
	sptr->z = z + ((GetRandomControl()&31)-16);

	sptr->Xvel = ((GetRandomControl()&15)-16)+xv;
	sptr->Yvel = yv;
	sptr->Zvel = ((GetRandomControl()&15)-16)+zv;
	sptr->Friction = 0;

	if (GetRandomControl()&1)
	{
		if (fxnum>=0)
			sptr->Flags = SP_SCALE|SP_DEF|SP_ROTATE|SP_EXPDEF|SP_FX;
		else
			sptr->Flags = SP_SCALE|SP_DEF|SP_ROTATE|SP_EXPDEF;
		sptr->RotAng = GetRandomControl()&4095;
		if (GetRandomControl()&1)
			sptr->RotAdd = -(GetRandomControl()&15)-16;
		else
			sptr->RotAdd = (GetRandomControl()&15)+16;
	}
	else
	{
		if (fxnum>=0)
	 		sptr->Flags = SP_SCALE|SP_DEF|SP_EXPDEF|SP_FX;
		else
			sptr->Flags = SP_SCALE|SP_DEF|SP_EXPDEF;
	}

	sptr->FxObj = fxnum;
	sptr->Gravity = sptr->MaxYvel = 0;
	sptr->Def = objects[EXPLOSION1].mesh_index;
	size = (GetRandomControl()&31)+48;
	if (xv||yv||zv)
	{
		sptr->sWidth = sptr->Width = size>>5;
 		sptr->sHeight = sptr->Height = size>>5;
		if (fxnum == -2)
			sptr->Scalar = 2;
		else
			sptr->Scalar = 3;
	}
	else
	{
		sptr->sWidth = sptr->Width = size>>4;
 		sptr->sHeight = sptr->Height = size>>4;
		sptr->Scalar = 4;
	}
	sptr->dWidth = size>>1;
	sptr->dHeight = size>>1;
}
