/*********************************************************************************************/
/*                                                                                           */
/* BLOWPIPE TRIBESMAN - TS - 28/7/98                                                          */
/*                                                                                           */
/*********************************************************************************************/

/*---------------------------------------------------------------------------
 *	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 "sound.h"
#include "control.h"
#include "sphere.h"
#include "effect2.h"

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

//#define DEBUG_BLOWPIPE

#define BLOW_BIFF_DAMAGE 100
#define BLOW_SHOOT_DAMAGE 20
#define BLOW_BIFF_ENEMY_DAMAGE 5

#define BLOWPIPE_SPEED	150

#define BLOW_WALK_TURN (ONE_DEGREE*9)
#define BLOW_RUN_TURN (ONE_DEGREE*6)
#define BLOW_WAIT_TURN (ONE_DEGREE*2)

#define BLOW_PIPE_RANGE SQUARE(WALL_L*8)
#define BLOW_CLOSE_RANGE SQUARE(WALL_L/2)
#define BLOW_WALK_RANGE SQUARE(WALL_L*2)
#define BLOW_AWARE_DISTANCE (WALL_L)
#define BLOW_HIT_RANGE (STEP_L*2)
#define BLOW_SHIFT_CHANCE 0x200
#define BLOW_TOUCH 0x2400

#define BLOW_KNEELING_DIE_ANIM 21
#define BLOW_STANDING_DIE_ANIM 20

enum blow_anims {
	BLOW_EMPTY,
	BLOW_WAIT1,
	BLOW_WALK,
	BLOW_RUN,
	BLOW_ATTACK1,
	BLOW_ATTACK2,
	BLOW_ATTACK3,
	BLOW_ATTACK4,
	BLOW_AIM3,
	BLOW_DEATH,
	BLOW_ATTACK5,
	BLOW_WAIT2
};

/*---------------------------------------------------------------------------
 *	Externals
\*--------------------------------------------------------------------------*/

#ifdef DEBUG_BLOWPIPE
extern char exit_message[];
static char *BlowpipeStrings[] = {"EMPTY", "WAIT1", "WALK", "RUN", "ATTACK1", "ATTACK2", "ATTACK3", "ATTACK4", "AIM3", "DEATH", "ATTACK5", "WAIT2"};
#endif

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

static BITE_INFO blow_biff_hit = {0,0,-200, 13};
static BITE_INFO blow_shoot_hit = {8,40,-248, 13};

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

/*********************************** FUNCTION CODE *******************************************/

void BlowpipeControl(sint16 item_number)
{
	ITEM_INFO *item, *enemy;
	CREATURE_INFO *blow;
	sint16 angle, head_x, head_y, torso_x, torso_y, tilt, meta_mood;
	AI_INFO info;
	ROOM_INFO *r;

	r = &room[lara_item->room_number];

	if (!CreatureActive(item_number))
		return;

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

/*
	lara_item->box_number = r->floor[((lara_item->pos.z_pos - r->z) >> WALL_SHIFT) +
		((lara_item->pos.x_pos - r->x) >> WALL_SHIFT) * r->x_size].box;
	lara_dz = abs(lara_item->pos.z_pos - item->pos.z_pos);
	lara_dx = abs(lara_item->pos.x_pos - item->pos.x_pos);
	lara_dy = item->pos.y_pos - lara_item->pos.y_pos;
	lara_anim = lara_item->current_anim_state;
	if (lara_anim == AS_DUCK || lara_anim == AS_DUCKROLL || lara_anim ==AS_ALL4S || lara_anim == AS_CRAWL ||
		lara_anim == AS_ALL4TURNL || lara_anim == AS_ALL4TURNR)
				lara_dy -= STEP_L;

	if (lara_dx > lara_dz)
		lara_distance = lara_dx + (lara_dz >> 1);
	else
		lara_distance = lara_dz + (lara_dx >> 1);

	lara_y_angle = phd_atan(lara_distance, lara_dy);
	if (lara_y_angle > 0x2000)
		lara_y_angle = 0x2000;
	else if (lara_y_angle < -0x2000)
		lara_y_angle = -0x2000;

	head_x = lara_y_angle;
*/
	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != BLOW_DEATH)
		{
			if (item->current_anim_state == BLOW_WAIT1 || item->current_anim_state == BLOW_ATTACK1)
				item->anim_number = objects[item->object_number].anim_index + BLOW_KNEELING_DIE_ANIM;
			else
				item->anim_number = objects[item->object_number].anim_index + BLOW_STANDING_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = BLOW_DEATH;
		}
	}
	else
	{
		if (item->ai_bits)
			GetAITarget(blow);

		CreatureAIInfo(item, &info);
		if (info.zone_number == info.enemy_zone)
			meta_mood = VIOLENT;
		else
			meta_mood = TIMID;

		GetCreatureMood(item, &info, meta_mood);

		if (item->hit_status && lara.poisoned >= 0x100 && blow->mood == BORED_MOOD )
			blow->mood = ESCAPE_MOOD;
		CreatureMood(item, &info, TIMID);

		angle = CreatureTurn(item, blow->mood == BORED_MOOD ? BLOW_WAIT_TURN : blow->maximum_turn);
		if (info.ahead)
		{
			head_y = info.angle >> 1;
//			head_x = info.x_angle;
			torso_y = info.angle >> 1;
		}

		if ( item->hit_status || (blow->enemy == lara_item && (info.distance < BLOW_AWARE_DISTANCE || TargetVisible(item, &info)) && (abs(lara_item->pos.y_pos - item->pos.y_pos) < (WALL_L*2)))) //Maybe move this into LONDSEC_WAIT case?
			AlertAllGuards(item_number);

		switch (item->current_anim_state)
		{
		case BLOW_WAIT1:
			if (info.ahead)
			{
				torso_y = info.angle;
			//Okay, let's make the head rotation rotate the torso around the x-axis
				torso_x = info.x_angle>>1;
			}
			blow->flags &= 0x0fff;
			blow->maximum_turn = BLOW_WAIT_TURN;
			if (item->ai_bits & GUARD)
			{
				head_y = AIGuard(blow);
				torso_y = 0;
				torso_x = 0;
				blow->maximum_turn = 0;
				if (!(GetRandomControl() & 0xFF))			
						item->goal_anim_state = BLOW_WAIT2;
				break;
			}
			else if (blow->mood == ESCAPE_MOOD)
			{
				if (lara.target != item && info.ahead && !item->hit_status)
					item->goal_anim_state = BLOW_WAIT1;
				else
					item->goal_anim_state = BLOW_RUN;
			}
			else if (info.bite && info.distance < BLOW_CLOSE_RANGE)
				item->goal_anim_state = BLOW_WAIT2;
			else if (info.bite && info.distance < BLOW_WALK_RANGE)
				item->goal_anim_state = BLOW_WALK;
			else if (Targetable(item, &info) && info.distance < BLOW_PIPE_RANGE)
				item->goal_anim_state = BLOW_ATTACK1;
			else if (blow->mood == BORED_MOOD)
			{
				if (GetRandomControl() < BLOW_SHIFT_CHANCE)
					item->goal_anim_state = BLOW_WALK;
				else
					break;
			}
			else
				item->goal_anim_state = BLOW_RUN;
			break;

		case BLOW_WAIT2:
			blow->flags &= 0x0fff;
			blow->maximum_turn = BLOW_WAIT_TURN;
			if (item->ai_bits & GUARD)
			{
				head_y = AIGuard(blow);
				torso_y = 0;
				torso_x = 0;
				blow->maximum_turn = 0;
				if (!(GetRandomControl() & 0xFF))			
						item->goal_anim_state = BLOW_WAIT1;
				break;
			}
			else if (blow->mood == ESCAPE_MOOD)
			{
				if (lara.target != item && info.ahead && !item->hit_status)
					item->goal_anim_state = BLOW_WAIT1;
				else
					item->goal_anim_state = BLOW_RUN;
			}
			else if (info.bite && info.distance < BLOW_CLOSE_RANGE)
					item->goal_anim_state = BLOW_ATTACK3;
			else if (info.bite && info.distance < BLOW_WALK_RANGE)
				item->goal_anim_state = BLOW_WALK;
			else if (Targetable(item, &info) &&  info.distance < BLOW_PIPE_RANGE)
				item->goal_anim_state = BLOW_WAIT1;
			else if (blow->mood == BORED_MOOD && GetRandomControl() < BLOW_SHIFT_CHANCE)
				item->goal_anim_state = BLOW_WALK;
			else
				item->goal_anim_state = BLOW_RUN;
			break;

		case BLOW_WALK:
			blow->maximum_turn = BLOW_WALK_TURN;

			if (info.bite && info.distance < BLOW_CLOSE_RANGE)
				item->goal_anim_state = BLOW_WAIT2;
			else if (info.bite && info.distance < BLOW_WALK_RANGE)
				item->goal_anim_state = BLOW_WALK;
			else if (Targetable(item, &info) && info.distance < BLOW_PIPE_RANGE)
				item->goal_anim_state = BLOW_WAIT1;
			else if (blow->mood == ESCAPE_MOOD)
				item->goal_anim_state = BLOW_RUN;
			else if (blow->mood == BORED_MOOD)
			{
				if (GetRandomControl() > BLOW_SHIFT_CHANCE)
					item->goal_anim_state = BLOW_WALK;
				else if (GetRandomControl() > BLOW_SHIFT_CHANCE)
					item->goal_anim_state = BLOW_WAIT2;
				else
					item->goal_anim_state = BLOW_WAIT1;
			}
//			else if (!info.ahead || info.distance > BLOW_WALK_RANGE)
			else if (info.distance > BLOW_WALK_RANGE)
				item->goal_anim_state = BLOW_RUN;
			break;

		case BLOW_RUN:
			blow->flags &= 0x0fff;
			blow->maximum_turn = BLOW_RUN_TURN;
			tilt = angle>>2;

			if (info.bite && info.distance < BLOW_CLOSE_RANGE)
				item->goal_anim_state = BLOW_WAIT2;
			else if (Targetable(item, &info) && info.distance < BLOW_PIPE_RANGE)
				item->goal_anim_state = BLOW_WAIT1;
			if (item->ai_bits & GUARD)
				item->goal_anim_state = BLOW_WAIT2;
			else if (blow->mood == ESCAPE_MOOD && lara.target != item && info.ahead)
					item->goal_anim_state = BLOW_WAIT2;
			else if (blow->mood == BORED_MOOD)
				item->goal_anim_state = BLOW_WAIT1;
			break;

		case BLOW_AIM3:
			if (!info.bite || info.distance > BLOW_CLOSE_RANGE)
				item->goal_anim_state = BLOW_WAIT2;
			else
				item->goal_anim_state = BLOW_ATTACK3;
			break;

		case BLOW_ATTACK1:
			if (info.ahead)
			{
				torso_y = info.angle;
			//Okay, let's make the head rotation rotate the torso around the x-axis
			//	torso_x = info.x_angle>>1;
				torso_x = info.x_angle;
			}
				blow->maximum_turn = 0;
				if (abs(info.angle) <  BLOW_WAIT_TURN)
					item->pos.y_rot += info.angle;
				else if (info.angle < 0)
					item->pos.y_rot -= BLOW_WAIT_TURN;
				else
					item->pos.y_rot += BLOW_WAIT_TURN;


			if (item->frame_number == anims[item->anim_number].frame_base + 15)
			{
				ITEM_INFO		*dart;
				PHD_ANGLE		angles[2];
				PHD_VECTOR	pos1,pos2;
				BITE_INFO		*bite;
				sint16 		dart_num,lp;

				dart_num = CreateItem();
				if ( dart_num != NO_ITEM )
				{
					dart = &items[dart_num];
					dart->object_number = DARTS;
					dart->room_number = item->room_number;

					bite = &blow_shoot_hit;
					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;
					pos2.z = bite->z<<1;
					GetJointAbsPosition( item, &pos2, bite->mesh_num );

					phd_GetVectorAngles( pos2.x-pos1.x,pos2.y-pos1.y,pos2.z-pos1.z, angles );
//					phd_GetVectorAngles( lara_item->pos.x_pos-pos1.x,lara_item->pos.y_pos-256-pos1.y,lara_item->pos.z_pos-pos1.z, angles );

					dart->pos.x_pos = pos1.x;
					dart->pos.y_pos = pos1.y;
					dart->pos.z_pos = pos1.z;
					InitialiseItem(dart_num);
					dart->pos.x_rot = angles[1];
					dart->pos.y_rot = angles[0];
					dart->speed = 256;
					AddActiveItem( dart_num );	// Make It Active for Control
					dart->status = ACTIVE;

					pos1.x = bite->x;
					pos1.y = bite->y;
					pos1.z = bite->z+96;
					GetJointAbsPosition( item, &pos1, bite->mesh_num );
					for (lp=0;lp<2;lp++)
						TriggerDartSmoke(pos1.x, pos1.y, pos1.z, 0, 0, 1);

				}

				item->goal_anim_state = BLOW_WAIT1;
			}
			break;

		case BLOW_ATTACK3:
			enemy = blow->enemy;
			if (enemy == lara_item)
			{
				if (!(blow->flags&0xf000) && (item->touch_bits & BLOW_TOUCH))
				{
					lara_item->hit_points -= BLOW_BIFF_DAMAGE;
					lara_item->hit_status = 1;

					blow->flags |= 0x1000;
					SoundEffect(70, &item->pos, 0);
					CreatureEffect(item, &blow_biff_hit, DoBloodSplat);
				}
			}
			else
			{
				if (!(blow->flags&0xf000) && enemy)
				{
					if (ABS(enemy->pos.x_pos - item->pos.x_pos) < BLOW_HIT_RANGE &&
						 ABS(enemy->pos.y_pos - item->pos.y_pos) < BLOW_HIT_RANGE &&
						 ABS(enemy->pos.z_pos - item->pos.z_pos) < BLOW_HIT_RANGE)
					{
						enemy->hit_points -= BLOW_BIFF_ENEMY_DAMAGE;
						enemy->hit_status = 1;

						blow->flags |= 0x1000;
						SoundEffect(70, &item->pos, 0);
					}
				}
			}
			break;
		}
	}

	CreatureTilt(item, tilt);
	head_y -= torso_y;
	CreatureJoint(item, 0, torso_y);
	CreatureJoint(item, 1, torso_x);
	CreatureJoint(item, 2, head_y);
	CreatureJoint(item, 3, head_x);

	#ifdef DEBUG_BLOWPIPE
//	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", blow->mood, boxes[item->box_number].height, boxes[lara_item->box_number].height);
//	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", BlowpipeStrings[item->current_anim_state]);
	PrintDbug(2, 3, exit_message);
	sprintf(exit_message, "%s", BlowpipeStrings[item->goal_anim_state]);
	PrintDbug(2, 4, 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[MUTANT2].anim_index);
//	PrintDbug(2, 6, exit_message);
	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d, AI:%d", blow->alerted, blow->reached_goal, blow->hurt_by_lara, item->ai_bits);
	PrintDbug(2,6, exit_message);
//	sprintf(exit_message, "Flags: %d", hybrid->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 collisions */
	CreatureAnimation(item_number, angle, 0);
}


