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

#include "objects.h"
#include "lara.h"
#include "gameflow.h"
#include "title.h"

void InitialiseCobra(sint16 item_number);
void CobraControl(sint16 item_number);

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

void *func[] = {
	&InitialiseCobra,
	&CobraControl,
};

#endif

/*********************************** TYPE DEFINITIONS ****************************************/
//Cobra - coded by TS 13-7-98


#define COBRA_DAMAGE 80

enum cobra_anims {COBRA_RISE, COBRA_WAIT, COBRA_STRIKE, COBRA_DOWN, COBRA_DEATH};

#define COBRA_TURN (ONE_DEGREE*10)

#define COBRA_FORGET_RADIUS SQUARE(WALL_L*3)
#define COBRA_OUTER_RADIUS SQUARE(WALL_L*3/2)
#define COBRA_INNER_RADIUS SQUARE(WALL_L)

#define RATTLER_FORGET_RADIUS SQUARE(WALL_L*5/2)
#define RATTLER_OUTER_RADIUS SQUARE(WALL_L*5/4)
#define RATTLER_INNER_RADIUS SQUARE(WALL_L*2/3)

#define COBRA_UPSET_SPEED 15
#define COBRA_HIT_RANGE (STEP_L*2)

#define COBRA_TOUCH 0x2000

#define COBRA_DIE_ANIM 4
#define COBRA_DOWN_ANIM 2

//#define DEBUG_COBRA

#ifdef DEBUG_COBRA
extern char exit_message[];
#endif

#ifdef DEBUG_COBRA
static char *CobraStrings[] = {
	"RISE",
	"WAIT",
	"STRIKE",
	"DOWN",
	"DEATH"
};
#endif

static int snake_forget_radius;
static int snake_outer_radius;
static int snake_inner_radius;

BITE_INFO cobra_hit = {0,0,0,13};

void InitialiseCobra(sint16 item_number)
{
	/* Cobra wants to start in wait anim */
	ITEM_INFO *item;

	InitialiseCreature(item_number);

//	CurrentLevel = LV_AREA51;
	item = &items[item_number];
	item->anim_number = objects[item->object_number].anim_index + COBRA_DOWN_ANIM;
	item->frame_number = anims[item->anim_number].frame_base + 45; //Actually coiled up
	item->current_anim_state = item->goal_anim_state = COBRA_DOWN;
	item->item_flags[2] = item->hit_points;
	item->hit_points = DONT_TARGET;
}

void CobraControl(sint16 item_number)
{
	ITEM_INFO *item;
	CREATURE_INFO *cobra;
	sint16 angle, head, tilt;
	AI_INFO info;

	if (!CreatureActive(item_number))
		return;

	if (CurrentLevel < LV_ROOFTOPS)
	{
		snake_forget_radius = COBRA_FORGET_RADIUS;
		snake_outer_radius = COBRA_OUTER_RADIUS;
		snake_inner_radius = COBRA_INNER_RADIUS;
	}
	else
	{
		snake_forget_radius = RATTLER_FORGET_RADIUS;
		snake_outer_radius = RATTLER_OUTER_RADIUS;
		snake_inner_radius = RATTLER_INNER_RADIUS;
	}

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

	if (item->hit_points <= 0 && item->hit_points != DONT_TARGET)
	{
		if (item->current_anim_state != COBRA_DEATH)
		{
			item->anim_number = objects[item->object_number].anim_index + COBRA_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = COBRA_DEATH;
		}
	}
	else
	{
		CreatureAIInfo(item, &info);

		info.angle += 0xC00; // cos origin is offset from head
//		GetCreatureMood(item, &info, VIOLENT);
//		CreatureMood(item, &info, VIOLENT);
		cobra->target.x = lara_item->pos.x_pos;
		cobra->target.z = lara_item->pos.z_pos;
		angle = CreatureTurn(item, cobra->maximum_turn);

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

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

		switch (item->current_anim_state)
		{
			case COBRA_WAIT:	// Ready for action - make it targetable
				cobra->flags = 0;
				if (info.distance > snake_forget_radius)
					item->goal_anim_state = COBRA_DOWN;
				else if ((lara_item->hit_points > 0) && ((info.ahead && info.distance < snake_inner_radius) || item->hit_status || (lara_item->speed > COBRA_UPSET_SPEED)))
					item->goal_anim_state = COBRA_STRIKE;
				break;

			case COBRA_DOWN:	// Coiled - make it untargetable
				cobra->flags = 0;
				if (item->hit_points != DONT_TARGET)
				{
					item->item_flags[2] = item->hit_points;
					item->hit_points = DONT_TARGET;
				}


				if (info.distance < snake_outer_radius && lara_item->hit_points > 0)
				{
					item->goal_anim_state = COBRA_RISE;
					item->hit_points = item->item_flags[2];
				}
				break;

			case COBRA_STRIKE:

					if (cobra->flags != 1 && (item->touch_bits & COBRA_TOUCH))// &&
//						cobra->flags >= cobra_hitframes[item->current_anim_state][0] &&
//						cobra->flags <= cobra_hitframes[item->current_anim_state][1])
					{
						cobra->flags = 1;
						lara_item->hit_points -= COBRA_DAMAGE;
						lara_item->hit_status = 1;
						lara.poisoned = 0x100;	// Set to max poisoning.

						CreatureEffect(item, &cobra_hit, DoBloodSplat);
					}

				break;
			case COBRA_RISE:
				item->hit_points = item->item_flags[2];
				break;
		}
	}

//	CreatureTilt(item, tilt);
//	CreatureJoint(item, 0, head>>1);
//	CreatureJoint(item, 1, head>>1);

	#ifdef DEBUG_COBRA
	sprintf(exit_message, "Hit Points: %d, item_flags: %d", item->hit_points, item->item_flags[2]);
	PrintDbug(2, 2, exit_message);
//	sprintf(exit_message, "Mood: %d", cobra->mood);
//	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", CobraStrings[item->current_anim_state]);
	PrintDbug(2, 3, exit_message);
	sprintf(exit_message, "%s", CobraStrings[item->goal_anim_state]);
	PrintDbug(2, 4, exit_message);
//	sprintf(exit_message, "%s", CobraStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Anim Number; %d", item->anim_number - objects[COBRA].anim_index);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d", cobra->alerted, cobra->reached_goal, cobra->hurt_by_lara);
//	PrintDbug(2,6, exit_message);
//	sprintf(exit_message, "AI Bits: %d", item->ai_bits);
//	PrintDbug(2,7, exit_message);
	#endif


	/* Actually do animation allowing for collisions */
	CreatureAnimation(item_number, angle, 0);
}
