#/**************************************************************************************************************/
/*                                                           	                                             */
/* Diver control - Revised (i.e. made to work) by TS - 8/9/98						G.Rummery 1997    */
/*                                                                                                            */
/**************************************************************************************************************/

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

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

#include "objects.h"
#include "items.h"
#include "lara.h"
#include "laraanim.h"
#include "control.h"
#include "effect2.h"

static sint16 Harpoon(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number);
static sint32 GetWaterSurface(sint32 x, sint32 y, sint32 z, sint16 room_number);

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

void DiverControl(sint16 item_number);
void ControlGhostGasEmitter(sint16 item_number);

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

#endif

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

#define MAX_TRIGGER_RANGE 	0x4000

#define DIVER_HARPOON_SPEED 150
#define DIVER_SWIM1_TURN (ONE_DEGREE*3)
#define DIVER_SWIM2_TURN (ONE_DEGREE*3)
#define DIVER_DIE_ANIM 16

enum diver_anim {
	DIVER_EMPTY,
	DIVER_SWIM1,
	DIVER_SWIM2,
	DIVER_SHOOT1,
	DIVER_AIM1,
	DIVER_NULL1,
	DIVER_AIM2,
	DIVER_SHOOT2,
	DIVER_NULL2,
	DIVER_DEATH
};

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

static BITE_INFO diver_poon = {17,164,44, 18};

sint16 Harpoon(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number);
sint32 GetWaterSurface(sint32 x, sint32 y, sint32 z, sint16 room_number);

/*---------------------------------------------------------------------------
 *	Public Functions
\*--------------------------------------------------------------------------*/

void DiverControl(sint16 item_number)
{
	ITEM_INFO *item;
	CREATURE_INFO *diver;
	sint16 angle, head, neck;
	AI_INFO info;
	sint32 water_level, shoot;
	GAME_VECTOR start, target;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];
	diver = (CREATURE_INFO *)item->data;
	angle = head = neck = 0;

	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != DIVER_DEATH)
		{
			item->anim_number = objects[DIVER].anim_index + DIVER_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = DIVER_DEATH;
		}

		/* Make dead diver float to surface */
		CreatureFloat(item_number);

		return;
	}
	else
	{
		CreatureAIInfo(item, &info);

		GetCreatureMood(item, &info, TIMID);

		CreatureMood(item, &info, TIMID);

		/* Can diver target Lara? */
		if (lara.water_status == LARA_ABOVEWATER)
		{
			/* Lara is on dry land, so may be worth going to surface to target her */
			start.x = item->pos.x_pos;
			start.y = item->pos.y_pos - STEP_L;
			start.z = item->pos.z_pos;
			start.room_number = item->room_number;

			target.x = lara_item->pos.x_pos;
			target.y = lara_item->pos.y_pos - (LARA_HITE-150); // don't look at her origin, aim higher
			target.z = lara_item->pos.z_pos;

			shoot = LOS(&start, &target);

			/* If diver can see Lara and Lara is above the surface, he should surface to shoot at her */
			if (shoot)
			{
				diver->target.x = lara_item->pos.x_pos;
				diver->target.y = lara_item->pos.y_pos;
				diver->target.z = lara_item->pos.z_pos;
			}

			/* Cancel shoot if not facing towards Lara yet */
			if (info.angle < -0x2000 || info.angle > 0x2000)
				shoot = 0;
		}
		else if (info.angle > -0x2000 && info.angle < 0x2000)
		{
			/* Lara is in the water, so normal targeting is all that is required */
			start.x = item->pos.x_pos;
			start.y = item->pos.y_pos;
			start.z = item->pos.z_pos;
			start.room_number = item->room_number;

			target.x = lara_item->pos.x_pos;
			target.y = lara_item->pos.y_pos;
			target.z = lara_item->pos.z_pos;

			shoot = LOS(&start, &target);
		}
		else
			shoot = 0;

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

		water_level = GetWaterSurface(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos, item->room_number) + WALL_L/2;

		switch (item->current_anim_state)
		{
		case DIVER_SWIM1:
			// Diver underwater
			diver->maximum_turn = DIVER_SWIM1_TURN;
			if (shoot)
				neck = -info.angle;

			if (diver->target.y < water_level && item->pos.y_pos < water_level + diver->LOT.fly)
				item->goal_anim_state = DIVER_SWIM2;
			else if (diver->mood == ESCAPE_MOOD)
				break;
			else if (shoot)
				item->goal_anim_state = DIVER_AIM1;
			break;

		case DIVER_AIM1:
			diver->flags = 0;

			if (shoot)
				neck = -info.angle;

			if (!shoot || diver->mood == ESCAPE_MOOD || (diver->target.y < water_level && item->pos.y_pos < water_level + diver->LOT.fly))
				item->goal_anim_state = DIVER_SWIM1;
			else
				item->goal_anim_state = DIVER_SHOOT1;
			break;

		case DIVER_SHOOT1:
			if (shoot)
				neck = -info.angle;

			if (!diver->flags)
			{
				CreatureEffect(item, &diver_poon, Harpoon);
				//ShotLara(item, &info, &diver_poon, head, DIVER_POON_DAMAGE);
				diver->flags = 1;
			}
			break;


		case DIVER_SWIM2:
			// Diver on the surface
			diver->maximum_turn = DIVER_SWIM2_TURN;

			if (shoot)
				head = info.angle;

			if (diver->target.y > water_level)
				item->goal_anim_state = DIVER_SWIM1;
			else if (diver->mood == ESCAPE_MOOD)
				break;
			else if (shoot)
				item->goal_anim_state = DIVER_AIM2;
			break;

		case DIVER_AIM2:
			diver->flags = 0;

			if (shoot)
				head = info.angle;

			if (!shoot || diver->mood == ESCAPE_MOOD || diver->target.y > water_level)
				item->goal_anim_state = DIVER_SWIM2;
			else
				item->goal_anim_state = DIVER_SHOOT2;
			break;

		case DIVER_SHOOT2:
			if (shoot)
				head = info.angle;

			if (!diver->flags)
			{
				CreatureEffect(item, &diver_poon, Harpoon);
				//ShotLara(item, &info, &diver_poon, head, DIVER_POON_DAMAGE);
				diver->flags = 1;
			}
			break;

		}
	}

//	CreatureJoint(item, 0, head);
//	CreatureJoint(item, 1, neck);

	CreatureAnimation(item_number, angle, 0);

	switch (item->current_anim_state)
	{
	case DIVER_SWIM1:
	case DIVER_AIM1:
	case DIVER_SHOOT1:
		CreatureUnderwater(item, WALL_L/2);
		break;
	default:
		item->pos.y_pos = water_level - WALL_L/2;
	}
}

/*---------------------------------------------------------------------------
 *	Local Functions
\*--------------------------------------------------------------------------*/

static sint16 Harpoon(sint32 x, sint32 y, sint32 z, sint16 speed, PHD_ANGLE yrot, sint16 room_number)
{
	sint16 fx_number;
	FX_INFO *fx;

	fx_number = CreateEffect(room_number);

	if (fx_number != NO_ITEM)
	{
		fx = &effects[fx_number];
		fx->pos.x_pos = x;
		fx->pos.y_pos = y;
		fx->pos.z_pos = z;
		fx->room_number = room_number;
		fx->pos.x_rot = fx->pos.z_rot = 0;
		fx->pos.y_rot = yrot;
		fx->speed = DIVER_HARPOON_SPEED;
		fx->fallspeed = 0;
		fx->frame_number = 0;
		fx->object_number = DIVER_HARPOON;
		fx->shade = 14 * 256;
		ShootAtLara(fx);
	}

	return (fx_number);
}

static sint32 GetWaterSurface(sint32 x, sint32 y, sint32 z, sint16 room_number)
{
	/* Similar to GetWaterHeight() but is looking for whether a clear
		water surface is available or whether a ceiling is in the way */
	ROOM_INFO *r;
	FLOOR_INFO *floor;

	r = &room[room_number];
	floor = &r->floor[((z - r->z) >> WALL_SHIFT) + ((x - r->x) >> WALL_SHIFT) * r->x_size];

	if (r->flags & UNDERWATER)
	{
		// Upwards until leave water
		while (floor->sky_room != NO_ROOM)
		{
			r = &room[floor->sky_room];
			if (!(r->flags & UNDERWATER))
				return (floor->ceiling << 8);
			floor = &r->floor[((z - r->z) >> WALL_SHIFT) + ((x - r->x) >> WALL_SHIFT) * r->x_size];
		}

		return (NO_HEIGHT); // only line that differs from GetWaterHeight!
	}
	else
	{
		// Go down until hit water
		while (floor->pit_room != NO_ROOM)
		{
			r = &room[floor->pit_room];
			if (r->flags & UNDERWATER)
				return (floor->floor << 8);
			floor = &r->floor[((z - r->z) >> WALL_SHIFT) + ((x - r->x) >> WALL_SHIFT) * r->x_size];
		}
	}
	return (NO_HEIGHT);
}

void ControlGhostGasEmitter(sint16 item_number)
{
	ITEM_INFO *item;
	SPARKS	*sptr;
	long		size;
	long		dx,dz;

	item = &items[item_number];

	if (!TriggerActive(item) || (wibble & 15))
		return;

	dx = lara_item->pos.x_pos - item->pos.x_pos;
	dz = lara_item->pos.z_pos - item->pos.z_pos;

	if (dx < -MAX_TRIGGER_RANGE || dx > MAX_TRIGGER_RANGE || dz < -MAX_TRIGGER_RANGE || dz > MAX_TRIGGER_RANGE)
		return;

	sptr = &spark[GetFreeSpark()];

	sptr->On = 1;
	sptr->sR = 0;
	sptr->sG = 0;
	sptr->sB = 0;

	sptr->dR = 12;
	sptr->dG = 32;
	sptr->dB = 0;

	sptr->ColFadeSpeed = 24 + (GetRandomControl()&7);
	sptr->FadeToBlack = 32;
	sptr->sLife = sptr->Life = (GetRandomControl()&7)+64;

	sptr->TransType = COLADD;

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

	sptr->x = item->pos.x_pos + ((GetRandomControl()&511)-256);
	sptr->y = item->pos.y_pos - 256 - ((GetRandomControl()&15)+8);
	sptr->z = item->pos.z_pos + ((GetRandomControl()&1023)-512);
	sptr->Xvel = ((GetRandomControl()&255)-128);
	sptr->Yvel = -(GetRandomControl()&1)-1;
	sptr->Zvel = ((GetRandomControl()&255)-128);
	sptr->Friction = 4;

	if (GetRandomControl()&1)
	{
		sptr->Flags = SP_SCALE|SP_DEF|SP_ROTATE|SP_EXPDEF;
		sptr->RotAng = GetRandomControl()&4095;
		if (GetRandomControl()&1)
			sptr->RotAdd = -(GetRandomControl()&7)-4;
		else
			sptr->RotAdd = (GetRandomControl()&7)+4;
	}
	else
		sptr->Flags = SP_SCALE|SP_DEF|SP_EXPDEF;

	sptr->Def = objects[EXPLOSION1].mesh_index;
	sptr->Scalar = 3;
	sptr->Gravity = sptr->MaxYvel = 0;
	size = (GetRandomControl()&31)+96;
	sptr->Width = sptr->sWidth = size>>1;
	sptr->dWidth = size>>1;
	size += (GetRandomControl()&31)+32;
 	sptr->Height = sptr->sHeight = size>>1;
	sptr->dHeight = size>>1;
}

