#ifdef PSX_VERSION
#include <sys\types.h>
#include <libgte.h>
#include <libgpu.h>
#include <gtemac.h>
#include <inline_c.h>
#include "../spec_psx/typedefs.h"
#include "../spec_psx/maths.h"
#else
#include "../specific/standard.h"
#include "../specific/global.h"
#endif

#include "objects.h"
#include "lara.h"
#include "laraanim.h"
#include "effect2.h"
#include "sphere.h"
#include "control.h"
#include "camera.h"
#include "traps.h"

#define MAX_TRIGGER_RANGE 0x4000

extern long wibble;
extern short rcossin_tbl[];

void ControlFireHead(sint16 item_number);
void InitialiseFireHead(sint16 item_number);
void ControlRotateyThing(sint16 item_number);

static void TriggerFireHeadFlame(long x, long y, long z, long angle, long speed);

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

void *func[] = {
	&ControlFireHead,
	&InitialiseFireHead,
	&ControlRotateyThing
};

#endif

enum strut_anims {	FIREHEAD_STILL, FIREHEAD_REAR, FIREHEAD_BLOW	};
enum {	FH_BLOWLOOPS = 0,
		FH_SPEED,
		FH_STOP,
		FH_DEADLYRANGE
};

#define	DEADLYRANGE_ADD	32

void InitialiseFireHead(sint16 item_number)
{
	ITEM_INFO *item;

	item = &items[item_number];
	item->anim_number = objects[item->object_number].anim_index+1;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = FIREHEAD_REAR;
	item->goal_anim_state = FIREHEAD_REAR;

//	item->item_flags[FH_BLOWLOOPS] = 0;	// Number of frames it blows fire for.
//	item->item_flags[FH_SPEED] = 0;	// Speed of flames.
//	item->item_flags[FH_STOP] = 0;	// Rear up again ?
//	item->item_flags[FH_DEADLYRANGE] = 0;	// Deadly range of flame.
}

void ControlFireHead(sint16 item_number)
{
	ITEM_INFO *item;
	PHD_VECTOR	pos;
	long		angle,r,g;

	item = &items[item_number];

	if (!TriggerActive(item))
		return;

	if (item->current_anim_state != FIREHEAD_STILL)
	{
		angle = (((item->pos.y_rot>>4)+1024)&4095)<<1;
		r = 24+(GetRandomControl()&7);
		g = 12+(GetRandomControl()&3);

		if (item->current_anim_state == FIREHEAD_REAR)
		{
			pos.x = pos.z = 0;
			pos.y = 128;
			GetJointAbsPosition(item,&pos,7);

			item->item_flags[FH_SPEED] = 0;	// Speed of flames.
			item->item_flags[FH_STOP] = 0;	// Rear up again ?
			item->item_flags[FH_DEADLYRANGE] = 0;	// Deadly range of flames.
			item->item_flags[FH_BLOWLOOPS] = item->hit_points;	// Rear up again ?
			TriggerDynamic(pos.x, pos.y, pos.z, 8, r, g, 0);
		}
		else
		{
			pos.x = pos.z = pos.y = 0;
			GetJointAbsPosition(item,&pos,7);

			if (item->item_flags[FH_STOP] == 0)	// Increase speed of flames ?
			{
				SoundEffect(204, &item->pos, 0);
				if (item->item_flags[FH_SPEED] < 2048)
					item->item_flags[FH_SPEED] += 64;
				if (item->item_flags[FH_DEADLYRANGE] < 2048)
					item->item_flags[FH_DEADLYRANGE] += DEADLYRANGE_ADD;
			}
			else								// Decrease speed of flames ?
			{
				if (item->item_flags[FH_SPEED])
					item->item_flags[FH_SPEED] -= 64;
				if (item->item_flags[FH_DEADLYRANGE])
				{
					item->item_flags[FH_DEADLYRANGE] -= DEADLYRANGE_ADD;
					if (item->item_flags[FH_DEADLYRANGE] < 0)
						item->item_flags[FH_DEADLYRANGE] = 0;
				}
			}

			if (item->item_flags[FH_BLOWLOOPS])
				item->item_flags[FH_BLOWLOOPS]--;
			if (wibble&4)
				TriggerFireHeadFlame(pos.x, pos.y, pos.z, angle, item->item_flags[FH_SPEED]);

			if (item->item_flags[FH_BLOWLOOPS] == 0 && item->item_flags[FH_STOP] == 0 && item->frame_number == anims[item->anim_number].frame_base)
			{
				item->item_flags[FH_STOP] = 1;
				item->goal_anim_state = FIREHEAD_REAR;
			}

			TriggerDynamic(pos.x, pos.y, pos.z, 8 + (item->item_flags[FH_SPEED]>>7), r, g, 0);

			if (!lara.burn)
			{
				long xdmin,zdmin,ydmin,xdmax,zdmax,ydmax,lx,ly,lz;

				ydmin = item->pos.y_pos - 1024;
				ydmax = item->pos.y_pos + 256;

				switch (item->pos.y_rot)
				{
					case 0:
						xdmin = pos.x;
						xdmax = pos.x + item->item_flags[FH_DEADLYRANGE];
						zdmin = pos.z-512;
						zdmax = pos.z+512;
						break;
					case 16384:
						zdmax = pos.z;
						zdmin = pos.z - item->item_flags[FH_DEADLYRANGE];
						xdmin = pos.x-512;
						xdmax = pos.x+512;
						break;
					case -32768:
						xdmax = pos.x;
						xdmin = pos.x - item->item_flags[FH_DEADLYRANGE];
						zdmin = pos.z-512;
						zdmax = pos.z+512;
						break;
					default:
						zdmin = pos.z;
						zdmax = pos.z + item->item_flags[FH_DEADLYRANGE];
						xdmin = pos.x-512;
						xdmax = pos.x+512;
						break;
				}

				lx = lara_item->pos.x_pos;
				ly = lara_item->pos.y_pos;
				lz = lara_item->pos.z_pos;
				if (	lx > xdmin && lx < xdmax &&
					ly > ydmin && ly < ydmax &&
					lz > zdmin && lz < zdmax)
					LaraBurn();
			}
		}
	}
	else
		item->goal_anim_state = FIREHEAD_REAR;

	AnimateItem(item);
}

static void TriggerFireHeadFlame(long x, long y, long z, long angle, long speed)
{
	long		size,zv,xv;
	SPARKS	*sptr;
	long		dx,dz;

	dx = lara_item->pos.x_pos - x;
	dz = lara_item->pos.z_pos - z;

	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 = 48+(GetRandomControl()&31);
	sptr->sG = sptr->sR;
	sptr->sB = 192+(GetRandomControl()&63);

	sptr->dR = 192+(GetRandomControl()&63);
	sptr->dG = 128+(GetRandomControl()&63);
	sptr->dB = 32;

	sptr->ColFadeSpeed = 12 + (GetRandomControl()&3);
	sptr->FadeToBlack = 8;
	sptr->sLife = sptr->Life = (GetRandomControl()&7)+28;
	sptr->TransType = COLADD;
	sptr->extras = 0;
	sptr->Dynamic = -1;
	sptr->x = x+((GetRandomControl()&31)-16);
	sptr->y = y+((GetRandomControl()&31)-16);
	sptr->z = z+((GetRandomControl()&31)-16);

	speed -= (GetRandomControl()%((speed>>3)+1));

	zv = (rcossin_tbl[angle+1]*speed) >> 11;
	xv = (rcossin_tbl[angle]*speed) >> 11;
	sptr->Xvel = xv + ((GetRandomControl()&127)-64);
	sptr->Yvel = (GetRandomControl()&7)+6;
	sptr->Zvel = zv + ((GetRandomControl()&127)-64);

	sptr->Friction = 4;
	sptr->Flags = SP_SCALE|SP_DEF|SP_EXPDEF;
	if (GetRandomControl()&1)
	{
		sptr->Flags |= SP_ROTATE;
		sptr->RotAng = GetRandomControl()&4095;
		sptr->RotAdd = (GetRandomControl()&63)-32;
	}
	sptr->Gravity = -(GetRandomControl()&15)-8;
	sptr->MaxYvel = -(GetRandomControl()&7)-8;
	sptr->Def = objects[EXPLOSION1].mesh_index;
	sptr->Scalar = 3;
	size = (GetRandomControl()&15)+(speed>>4);
	sptr->Width = sptr->sWidth = size>>2;
 	sptr->Height = sptr->sHeight = size>>2;
	sptr->dWidth = size;
	sptr->dHeight = size;
}

void ControlRotateyThing(sint16 item_number)
{
	ITEM_INFO *item;

	item = &items[item_number];

	if (TriggerActive(item))
		AnimateItem(item);
	else
		KillItem(item_number);

}
