/*********************************************************************************************/
/*                                                                                           */
/* Dino Control                                                                              */
/*                                                                                           */
/*********************************************************************************************/

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

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

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

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

#define DINO_TOUCH_DAMAGE 1
#define DINO_TRAMPLE_DAMAGE 10
#define DINO_BITE_DAMAGE 10000

#define DINO_TOUCH (0x3000)

enum dino_anims {
	DINO_EMPTY1,
	DINO_STOP,
	DINO_WALK,
	DINO_RUN,
	DINO_EMPTY2,
	DINO_DEATH,
	DINO_ROAR,
	DINO_ATTACK2,
	DINO_KILL,
	DINO_LONGROARSTART,
	DINO_LONGROARMID,
	DINO_LONGROAREND,
	DINO_SNIFFSTART,
	DINO_SNIFFMID,
	DINO_SNIFFEND
};

#define DINO_KILL_ANIM 11

#define DINO_ROAR_CHANCE 0x100

#define DINO_RUN_TURN  (ONE_DEGREE*4)
#define DINO_WALK_TURN (ONE_DEGREE*2)

#define DINO_RUN_RANGE SQUARE(WALL_L*5)
#define DINO_ATTACK_RANGE SQUARE(WALL_L*4)
#define DINO_BITE_RANGE SQUARE(1500)
#define DINO_HIT_RADIUS SQUARE(WALL_L*2/3)
static BITE_INFO trex_hit = {0,32,64, 13};

//#define DEBUG_TREX

#ifdef DEBUG_TREX
extern char exit_message[];
#endif


#ifdef DEBUG_TREX
static char *DinoStrings[] = {
	"DINO EMPTY1",
	"DINO STOP",
	"DINO WALK",
	"DINO RUN",
	"DINO EMPTY2",
	"DINO DEATH",
	"DINO ROAR",
	"DINO ATTACK2",
	"DINO KILL",
	"DINO LONGROARSTART",
	"DINO LONGROARMID",
	"DINO LONGROAREND",
	"DINO SNIFFSTART",
	"DINO SNIFFMID",
	"DINO SNIFFEND"
};
#endif
/*********************************** FUNCTION CODE *******************************************/



void DinoControl(sint16 item_number)
{
	ITEM_INFO *item, *best, *target;
	CREATURE_INFO *dino;
	sint16 head, neck, angle;
	sint32 x, y, z, best_distance, distance;
	long lp,target_number;
	AI_INFO info;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];

	dino = (CREATURE_INFO *)item->data;
	head = neck = angle = 0;

	/* Has dino been killed? */
	if (item->hit_points <= 0)
	{
		if (item->current_anim_state == DINO_STOP)
			item->goal_anim_state = DINO_DEATH;
		else
			item->goal_anim_state = DINO_STOP;
	}
	else
	{
		best = NULL;
		best_distance = 0x7fffffff;

		GetNearByRooms(item->pos.x_pos,item->pos.y_pos,item->pos.z_pos,4096,0,item->room_number);

		for (lp=0;lp<number_draw_rooms;lp++)
		{
			for (target_number = room[draw_rooms[lp]].item_number; target_number!=NO_ITEM; target_number=target->next_item)
			{
				target = &items[target_number];
				if ((target->object_number != FLARE_ITEM && target->object_number != RAPTOR)  || !target->hit_points || target->status != ACTIVE)
					continue;

				/* Is this target closest? */
				x = (target->pos.x_pos - item->pos.x_pos) >> 6;
				y = (target->pos.y_pos - item->pos.y_pos) >> 6;
				z = (target->pos.z_pos - item->pos.z_pos) >> 6;
				distance = x*x + y*y + z*z;
				if (distance < best_distance)
				{
					best = target;
					best_distance = distance;
				}
			}
		}

		dino->enemy = best;
		if (dino->hurt_by_lara)
			dino->enemy = lara_item;

		CreatureAIInfo(item, &info);

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

		GetCreatureMood(item, &info, VIOLENT);
		if (!item->item_flags[0] && !item->item_flags[1] && dino->enemy == lara_item)
			dino->mood = BORED_MOOD;
		CreatureMood(item, &info, VIOLENT);

		if (dino->mood == BORED_MOOD)
			dino->maximum_turn >>= 1;
		angle = CreatureTurn(item, dino->maximum_turn);
		neck = -(angle*10);

		/* An enemy touching the dino takes damage just from that */
		if (item->touch_bits)
			lara_item->hit_points -= (item->current_anim_state == DINO_RUN)? DINO_TRAMPLE_DAMAGE : DINO_TOUCH_DAMAGE;

		/* Flag if enemy behind and facing us - stop and turn else they can chase in rings */
		dino->flags = (dino->mood != ESCAPE_MOOD && !info.ahead &&
						 info.enemy_facing > -FRONT_ARC && info.enemy_facing < FRONT_ARC);

		/* Flag if enemy is close ahead - walk to bite range */
		if (!dino->flags && info.distance > DINO_BITE_RANGE && info.distance < DINO_ATTACK_RANGE && info.bite)
			dino->flags = 1;

		if (	lara.gun_type != LG_FLARE &&
		   		(lara_item->current_anim_state == AS_STOP ||
		     	lara_item->current_anim_state == AS_DUCK) &&
		  		lara_item->goal_anim_state == lara_item->current_anim_state &&
				!item->hit_status)	// Shall T-Rex attack lara?
		{
			if (item->item_flags[0] > 0)
				item->item_flags[0]--;	// No
		}
		else
		{
			item->item_flags[0] = 120;	// Yes
			item->item_flags[1] = 3;
		}

		/* Decide on dino's next move */
	 	switch (item->current_anim_state)
		{
			case DINO_STOP:
				if (item->required_anim_state)
					item->goal_anim_state = item->required_anim_state;
				else if (dino->mood == BORED_MOOD || dino->flags)
					item->goal_anim_state = DINO_WALK;
				else if (dino->mood == ESCAPE_MOOD)
				{
					if (lara.target != item && info.ahead && !item->hit_status)
					{
						if (GetRandomControl() < DINO_ROAR_CHANCE)
							item->goal_anim_state = DINO_ROAR;
						else
							item->goal_anim_state = DINO_STOP;
					}
					else
						item->goal_anim_state = DINO_RUN;
				}

				else if (info.distance < DINO_BITE_RANGE && info.bite)
					if (item->item_flags[0])
						item->goal_anim_state = DINO_ATTACK2;
					else
					{
						if ((GetRandomControl() & 1) && item->item_flags[1])
							item->goal_anim_state = DINO_LONGROARSTART;
						else if (item->item_flags[1])
							item->goal_anim_state = DINO_SNIFFSTART;
				}
				else
					item->goal_anim_state = DINO_RUN;
				break;

			case DINO_WALK:
				dino->maximum_turn = DINO_WALK_TURN;

				if (dino->mood != BORED_MOOD || !dino->flags)
					item->goal_anim_state = DINO_STOP;
				else if (info.ahead && GetRandomControl() < DINO_ROAR_CHANCE)
				{
					item->required_anim_state = DINO_ROAR;
					item->goal_anim_state = DINO_STOP;
				}
				break;

			case DINO_RUN:
				dino->maximum_turn = DINO_RUN_TURN;

				if (info.distance < DINO_RUN_RANGE && info.bite)
					item->goal_anim_state = DINO_STOP;
				else if (dino->flags)
					item->goal_anim_state = DINO_STOP;
				else if (dino->mood != ESCAPE_MOOD && info.ahead && GetRandomControl() < DINO_ROAR_CHANCE)
				{
					item->required_anim_state = DINO_ROAR;
					item->goal_anim_state = DINO_STOP;
				}
				else if (dino->mood == BORED_MOOD)
					item->goal_anim_state = DINO_STOP;
				else if (dino->mood == ESCAPE_MOOD && lara.target != item && info.ahead)
					item->goal_anim_state = DINO_STOP;
				break;

			case DINO_ATTACK2:
				dino->maximum_turn = DINO_WALK_TURN;

				if (dino->enemy == lara_item)
				{
					if (item->touch_bits & DINO_TOUCH)
					{
						CreatureEffect(item, &trex_hit, DoBloodSplat);
						lara_item->hit_points -= DINO_BITE_DAMAGE;
						lara_item->hit_status = 1;
						item->goal_anim_state = DINO_KILL;
						dino->maximum_turn = 0;
						CreatureKill(item, DINO_KILL_ANIM, DINO_KILL, EXTRA_DINOKILL);
					}

				}
				else
				{
					if (dino->enemy && item->frame_number == anims[item->anim_number].frame_base + 20)
					{
						if (ABS(dino->enemy->pos.z_pos - (item->pos.z_pos + (objects[TREX].pivot_length * phd_cos(item->pos.y_rot) >> W2V_SHIFT))) < DINO_HIT_RADIUS &&
							 ABS(dino->enemy->pos.y_pos - item->pos.y_pos) <= DINO_HIT_RADIUS &&
							 ABS(dino->enemy->pos.x_pos - (item->pos.x_pos + (objects[TREX].pivot_length * phd_sin(item->pos.y_rot) >> W2V_SHIFT))) < DINO_HIT_RADIUS)
						{
							if (dino->enemy->object_number == FLARE_ITEM)
								dino->enemy->hit_points = 0;
							else
							{
								dino->enemy->hit_points -= DINO_TRAMPLE_DAMAGE*5;
								dino->enemy->hit_status = 1;
								CreatureEffect(item, &trex_hit, DoBloodSplat);
							}
						}
					}
				}


				/* Make dino walk if fail to kill Lara (avoids repeat miss attack) */
				if (!(GetRandomControl() & 0x3))
					item->required_anim_state = DINO_WALK;
				break;
			case DINO_SNIFFSTART:
				dino->maximum_turn = 0;
				if (item->item_flags[1] > 0 && item->frame_number == anims[item->anim_number].frame_base)
				{
					item->item_flags[1]--;
					if (dino->enemy && dino->enemy->object_number == FLARE_ITEM)
					{
						dino->enemy->hit_points = 0;
						item->item_flags[1] = 0;
					}
				}
				break;

			case DINO_SNIFFMID:
				dino->maximum_turn = 0;
				if (item->frame_number == anims[item->anim_number].frame_base)
				{
					if ((GetRandomControl() & 1) && item->item_flags[1] && !item->item_flags[0])
					{
						item->goal_anim_state = DINO_SNIFFMID;
						if (item->item_flags[1] > 0)
							item->item_flags[1]--;
					}
					else
						item->goal_anim_state = DINO_SNIFFEND;
				}
				break;

			case DINO_LONGROARSTART:
				dino->maximum_turn = 0;
				if (item->item_flags[1] > 0 && item->frame_number == anims[item->anim_number].frame_base)
				{
					item->item_flags[1]--;
					if (dino->enemy && dino->enemy->object_number == FLARE_ITEM)
					{
						dino->enemy->hit_points = 0;
						item->item_flags[1]--;
					}
				}
				item->goal_anim_state = DINO_LONGROAREND;
				break;

			case DINO_ROAR:
				dino->maximum_turn = 0;
				break;

			case DINO_KILL:
				dino->maximum_turn = 0;
				CreatureEffect(item, &trex_hit, DoBloodSplat);
				break;

		}
	}

	/* Split dino's head movement between head and neck */
//	CreatureJoint(item, 0, head >> 1);
//	CreatureJoint(item, 1, head >> 1);

//	CreatureJoint(item, 2, neck);
//	CreatureJoint(item, 3, neck);


//	CreatureJoint(item, 0, (sint16)(head*2));
//	dino->joint_rotation[1] = dino->joint_rotation[0];

#ifdef DEBUG_TREX
		sprintf(exit_message,"if[0]:%d bite:%d mt:%d ang:%d enemy:%d", item->item_flags[0],info.bite,dino->maximum_turn, angle, (dino->enemy==lara_item) ? 1:0);
		PrintDbug(2,4,exit_message);
//		sprintf(buf,"mood:%d bite:%d dist:%d enemy:%d", dino->mood, info.bite,phd_sqrt(info.distance),(enemy==lara_item) ? 1:0);
//		PrintDbug(2,4,buf);

//		sprintf(buf,"%s",&dinoanimstrs[item->current_anim_state][0]);
//		PrintDbug(2,5,buf);
//		sprintf(buf,"%s",&dinoanimstrs[item->goal_anim_state][0]);
//		PrintDbug(2,6,buf);
//	sprintf(exit_message, "Bx:%d, LBx:%d, Z:%d, LZ:%d", item->box_number, lara_item->box_number, info.zone_number, info.enemy_zone);
//	PrintDbug(2, 1, exit_message);
//	sprintf(exit_message, "Mood: %d, BxH:%d, LBxH:%d", dino->mood, boxes[item->box_number].height, boxes[lara_item->box_number].height);
//	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", DinoStrings[item->current_anim_state]);
	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", DinoStrings[item->goal_anim_state]);
	PrintDbug(2, 3, exit_message);
//	sprintf(exit_message, "LRoom:%d, LRmFlags:%d", lara_item->room_number, room[lara_item->room_number].flags);
//	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "H:%d, LH:%d", item->pos.y_pos, lara_item->pos.y_pos);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Anim Number; %d", item->anim_number - objects[TREX].anim_index);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d", dino->alerted, dino->reached_goal, dino->hurt_by_lara);
//	PrintDbug(2,6, exit_message);
//	sprintf(exit_message, "Flags: %d", dino->flags);
//	PrintDbug(2,7, exit_message);
//	sprintf(exit_message, "Room %d  X:%d  Z:%d", lara_item->room_number, (int)(lara_item->pos.x_pos/1024), (int)(lara_item->pos.z_pos/1024));
//	PrintDbug(2, 15, exit_message);

#endif

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

	/* Need to make dino collidable even when he dies */
	if (item->hit_points <= 0)
		item->collidable = 0;
	else
		item->collidable = 1;
}

