/*********************************************************************************************/
/*                                                                                           */
/* Winston - TS - 26/9/98                                                                     */
/*                                                                                           */
/*********************************************************************************************/

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

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


//void InitialiseWinston(sint16 item_number);
void WinstonControl(sint16 item_number);
void OldWinstonControl(sint16 item_number);
//void DrawWinston(ITEM_INFO *item);

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

void *func[] __attribute__((section(".header"))) = {
//	&InitialiseWinston,
	&WinstonControl,
	&OldWinstonControl,
//	&DrawWinston,
};

#endif

extern CREATURE_INFO *baddie_slots;

enum winston_anim {WINSTON_EMPTY, WINSTON_STOP, WINSTON_WALK, WINSTON_DEF1, WINSTON_DEF2, WINSTON_DEF3, WINSTON_HIT1, WINSTON_HIT2, WINSTON_HIT3, WINSTON_HITDOWN, WINSTON_FALLDOWN, WINSTON_GETUP, WINSTON_BRUSHOFF, WINSTON_ONFLOOR};

#define WINSTON_FALLDOWN_ANIM 16
#define WINSTON_STOP_RANGE SQUARE(WALL_L*3/2)
#define WINSTON_HP_AFTER_KO 16
#define WINSTON_KO_TIME 150
#define WINSTON_TURN (ONE_DEGREE * 2)
#define JUST_GOT_UP 999
/*********************************** TYPE DEFINITIONS ****************************************/

//#define DEBUG_WINSTON

#ifdef DEBUG_WINSTON
extern char exit_message[];
#endif

#ifdef DEBUG_WINSTON
static char *WinstonStrings[] = {"EMPTY", "STOP", "WALK", "DEF1", "DEF2", "DEF3", "HIT1", "HIT2", "HIT3", "HITDOWN", "FALLDOWN", "GETUP", "BRUSHOFF", "ONFLOOR"};
#endif

/*********************************** FUNCTION CODE *******************************************/
/*
void InitialiseWinston(sint16 item_number)
{
	ITEM_INFO *item;

	item = &items[item_number];
	InitialiseCreature(item_number);

	// Start Winston in stop pose
	item->anim_number = objects[WINSTON].anim_index + WINSTON_SIT_ANIM;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = item->goal_anim_state = WINSTON_SIT;
}

void DrawWinston(ITEM_INFO *item)
{
	// Big huge copy of DrawAnimatingItem() which swaps meshes
	int 		clip,i,poppush;
	OBJECT_INFO *object;
	sint32 		*bone;
	sint16		*rotation1, *rotation2;
	sint16		*extra_rotation;
	sint16		**meshpp, **swappp;
	uint32 		bit;
	sint16		*frmptr[2];
	int			rate,frac;

	frac=GetFrames( item,frmptr,&rate );
//	#ifdef DEBUG_WINSTON
//	sprintf(exit_message, "Status: %d, Mesh_Bits:%d", item->status, item->mesh_bits);
//	PrintDbug(2,5, exit_message);
//	#endif

	object = &objects[item->object_number];					// Draw Shadows...
	if (object->shadow_size)
		S_PrintShadow( object->shadow_size,frmptr[0],item,0 );

	phd_PushMatrix();
	phd_TranslateAbs(item->pos.x_pos, item->pos.y_pos, item->pos.z_pos);
	phd_RotYXZ(item->pos.y_rot, item->pos.x_rot, item->pos.z_rot);

	if ( (clip=S_GetObjectBounds(frmptr[0])) )
	{
		CalculateObjectLighting( item,frmptr[0] );

		extra_rotation = (sint16 *)item->data;

		meshpp = &meshes[objects[WINSTON].mesh_index];
		if (item->ai_bits != MODIFY)
			swappp = &meshes[objects[MESHSWAP2].mesh_index];
		else
			swappp = &meshes[objects[MESHSWAP3].mesh_index];

		bone = bones + object->bone_index;              	// Bone pointer
		bit = 1;

		if ( !frac )
		{
			phd_TranslateRel((sint32)*(frmptr[0]+6), (sint32)*(frmptr[0]+7), (sint32)*(frmptr[0]+8));
			rotation1 = frmptr[0]+9;
			gar_RotYXZsuperpack(&rotation1, 0);

			if (bit & item->mesh_bits)
				phd_PutPolygons( *meshpp, clip );
			else
				phd_PutPolygons( *swappp, clip );
			meshpp++;
			swappp++;

			for ( i=object->nmeshes-1; i>0; i--,bone+=4,meshpp++,swappp++ )
			{
				poppush = *(bone);							// Do Automated Hierarchy
				if (poppush & 1)                			// Push Pop
					phd_PopMatrix();
				if (poppush & 2)
					phd_PushMatrix();

				phd_TranslateRel( *(bone+1), *(bone+2), *(bone+3) );
				gar_RotYXZsuperpack(&rotation1, 0);

				if (extra_rotation && (poppush & (ROT_X|ROT_Y|ROT_Z)))			// If any Extra rotations required...
				{
					if (poppush & ROT_Y)
						phd_RotY(*(extra_rotation++));
					if (poppush & ROT_X)
						phd_RotX(*(extra_rotation++));
					if (poppush & ROT_Z)
						phd_RotZ(*(extra_rotation++));
				}

				bit <<= 1;
				if (bit & item->mesh_bits)
					phd_PutPolygons( *meshpp, clip );
				else
					phd_PutPolygons( *swappp, clip );
			}
		}
		else
		{
			InitInterpolate( frac,rate );
			phd_TranslateRel_ID( (sint32)*(frmptr[0]+6), (sint32)*(frmptr[0]+7), (sint32)*(frmptr[0]+8),
								 (sint32)*(frmptr[1]+6), (sint32)*(frmptr[1]+7), (sint32)*(frmptr[1]+8) );
			rotation1 = frmptr[0]+9;
			rotation2 = frmptr[1]+9;
			gar_RotYXZsuperpack_I(&rotation1, &rotation2, 0);

			if (bit & item->mesh_bits)
				phd_PutPolygons_I( *meshpp, clip );
			else
				phd_PutPolygons_I( *swappp, clip );
			meshpp++;
			swappp++;

			for ( i=object->nmeshes-1; i>0; i--,bone+=4,meshpp++,swappp++ )
			{
				poppush = *(bone);						// Do Automated Hierarchy
				if (poppush & 1)                			// Push Pop
					phd_PopMatrix_I();
				if (poppush & 2)
					phd_PushMatrix_I();

				phd_TranslateRel_I(*(bone+1), *(bone+2), *(bone+3));
				gar_RotYXZsuperpack_I(&rotation1, &rotation2, 0);

				if (extra_rotation && (poppush & (ROT_X|ROT_Y|ROT_Z)))			// If any Extra rotations required...
				{
					if (poppush & ROT_Y)
						phd_RotY_I(*(extra_rotation++));
					if (poppush & ROT_X)
						phd_RotX_I(*(extra_rotation++));
					if (poppush & ROT_Z)
						phd_RotZ_I(*(extra_rotation++));
				}

				bit <<= 1;
				if (bit & item->mesh_bits)
					phd_PutPolygons_I( *meshpp, clip );
				else if (item->hit_points > 0 || item->status == ACTIVE || bit != 0x400 || item->carried_item == -1)
					phd_PutPolygons_I( *swappp, clip );
			}

		}
	}
	phd_PopMatrix();
}

*/

void WinstonControl(sint16 item_number)
{
	ITEM_INFO *item;
	CREATURE_INFO *winston, *cinfo;
	sint16 angle, slot;
	AI_INFO info;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];
	winston = (CREATURE_INFO *)item->data;

	CreatureAIInfo(item, &info);
	GetCreatureMood(item, &info, VIOLENT); // ha ha
	CreatureMood(item, &info, VIOLENT); // ha ha

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

	if (!item->item_flags[1]) //Kill Old Winston, bring on the one in uniform
	{
		cinfo = baddie_slots;
		for (slot=0; slot<NUM_SLOTS; slot++, cinfo++)
		{
			if (items[cinfo->item_num].object_number != WINSTON)
					continue;
			else
			{
				items[cinfo->item_num].status = INVISIBLE;
				CreatureDie(cinfo->item_num, 0);
				break;
			}
		}
	}

	if (item->hit_points <= 0)
	{
		winston->maximum_turn = 0;
		switch (item->current_anim_state)
		{
			case WINSTON_FALLDOWN:	// Waiting.
				if (item->hit_status)
					item->goal_anim_state = WINSTON_HITDOWN;
				else if (item->item_flags[0]-- < 0)
					item->goal_anim_state = WINSTON_ONFLOOR;
				break;
			case WINSTON_HITDOWN:	// Waiting.
				if (item->hit_status)
					item->goal_anim_state = WINSTON_HITDOWN;
				else if (item->item_flags[0]-- < 0)
					item->goal_anim_state = WINSTON_ONFLOOR;
				break;
			case WINSTON_ONFLOOR:
				if (item->hit_status)
					item->goal_anim_state = WINSTON_HITDOWN;
				else if (item->item_flags[0]-- < 0)
					item->goal_anim_state = WINSTON_GETUP;
				break;
			case WINSTON_GETUP:	// Waiting.
				item->hit_points = WINSTON_HP_AFTER_KO;
				if (GetRandomControl() & 1)
					winston->flags = JUST_GOT_UP;
				break;
			default:
				item->anim_number = objects[ARMY_WINSTON].anim_index + WINSTON_FALLDOWN_ANIM;
				item->frame_number = anims[item->anim_number].frame_base;
				item->current_anim_state = WINSTON_FALLDOWN;
				item->goal_anim_state = WINSTON_FALLDOWN;
				item->item_flags[0] = WINSTON_KO_TIME;
		}
	}
	else
	{
		switch (item->current_anim_state)
		{
		case WINSTON_STOP:
			winston->maximum_turn = WINSTON_TURN;
			if (winston->flags == JUST_GOT_UP)
				item->goal_anim_state = WINSTON_BRUSHOFF;
			else if (lara.target == item)
					item->goal_anim_state = WINSTON_DEF1;
			else if (info.distance > WINSTON_STOP_RANGE || !info.ahead)
			{
				if (item->goal_anim_state != WINSTON_WALK)
				{
					item->goal_anim_state = WINSTON_WALK;
					SoundEffect(345, &item->pos, 0); // huff
				}
			}
			break;

		case WINSTON_WALK:
			winston->maximum_turn = WINSTON_TURN;
			if (lara.target == item)
				item->goal_anim_state = WINSTON_STOP;
			else if (info.distance < WINSTON_STOP_RANGE)
			{
				if (info.ahead)
				{
					item->goal_anim_state = WINSTON_STOP;
					if (winston->flags & 1)
						winston->flags--;
				}
				else if (!(winston->flags&1))
				{
					// scared
					SoundEffect(344, &item->pos, 0);
					SoundEffect(347, &item->pos, 0);
					winston->flags |= 1;
				}
			}
			break;

		case WINSTON_BRUSHOFF:
			winston->maximum_turn = 0;
			winston->flags = 0;
			break;

		case WINSTON_DEF1:
			winston->maximum_turn = WINSTON_TURN;
			if (item->required_anim_state)
				item->goal_anim_state = item->required_anim_state;
			if (item->hit_status)
				item->goal_anim_state = WINSTON_HIT1;
			else if (lara.target != item)
				item->goal_anim_state = WINSTON_STOP;
//			else if (!(GetRandomControl() & 0x7F))
//				item->goal_anim_state = WINSTON_DEF2;
//			else if (!(GetRandomControl() & 0x7F))
//				item->goal_anim_state = WINSTON_DEF3;
			break;

		case WINSTON_DEF2:
			winston->maximum_turn = WINSTON_TURN;
			if (item->required_anim_state)
				item->goal_anim_state = item->required_anim_state;
			if (item->hit_status)
				item->goal_anim_state = WINSTON_HIT2;
			else if (lara.target != item)
				item->goal_anim_state = WINSTON_DEF1;
//			else if (!(GetRandomControl() & 0x7F))
//				item->goal_anim_state = WINSTON_DEF1;
			break;

		case WINSTON_DEF3:
			winston->maximum_turn = WINSTON_TURN;
			if (item->required_anim_state)
				item->goal_anim_state = item->required_anim_state;
			if (item->hit_status)
				item->goal_anim_state = WINSTON_HIT3;
			else if (lara.target != item)
				item->goal_anim_state = WINSTON_DEF1;
//			else if (!(GetRandomControl() & 0x7F))
//				item->goal_anim_state = WINSTON_DEF1;
			break;

		case WINSTON_HIT1:
			if (!(GetRandomControl() & 1))
				item->required_anim_state = WINSTON_DEF2;
			else
				item->required_anim_state = WINSTON_DEF3;
			break;

		case WINSTON_HIT2:
				item->required_anim_state = WINSTON_DEF1;
			break;

		case WINSTON_HIT3:
				item->required_anim_state = WINSTON_DEF1;
			break;

		}
	}

	// tray clink
	if (GetRandomControl() < 0x100)
		SoundEffect(347, &item->pos, 0);

#ifdef DEBUG_WINSTON
	sprintf(exit_message, "Mood: %d", winston->mood);
	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", WinstonStrings[item->current_anim_state]);
	PrintDbug(2, 3, exit_message);
	sprintf(exit_message, "%s", WinstonStrings[item->goal_anim_state]);
	PrintDbug(2, 4, exit_message);
	sprintf(exit_message, "HitStatus:%d, HPs: %d", item->hit_status, item->hit_points);
	PrintDbug(2,5, exit_message);
	sprintf(exit_message, "Targetted: %d", lara.target == item);
	PrintDbug(2,6, exit_message);
	sprintf(exit_message, "LBox:%d, LZ:%d", lara_item->box_number, info.enemy_zone);
	PrintDbug(2, 7, exit_message);
#endif


	CreatureAnimation(item_number, angle, 0);
}

void OldWinstonControl(sint16 item_number)
{
	ITEM_INFO *item;
	CREATURE_INFO *winston;
	sint16 angle;
	AI_INFO info;

	if (!CreatureActive(item_number))
		return;

	item = &items[item_number];
	winston = (CREATURE_INFO *)item->data;

	CreatureAIInfo(item, &info);
	GetCreatureMood(item, &info, VIOLENT); // ha ha
	CreatureMood(item, &info, VIOLENT); // ha ha

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

	if (item->current_anim_state == WINSTON_STOP)
	{
		if (info.distance > WINSTON_STOP_RANGE || !info.ahead)
		{
			if (item->goal_anim_state != WINSTON_WALK)
			{
				item->goal_anim_state = WINSTON_WALK;
				SoundEffect(345, &item->pos, 0); // huff
			}
		}
	}
	else
	{
		if (info.distance < WINSTON_STOP_RANGE)
		{
			if (info.ahead)
			{
				item->goal_anim_state = WINSTON_STOP;
				if (winston->flags & 1)
					winston->flags--;
			}
			else if (!(winston->flags&1))
			{
				// scared
				SoundEffect(344, &item->pos, 0);
				SoundEffect(347, &item->pos, 0);
				winston->flags |= 1;
			}
		}
	}

	if (item->touch_bits && !(winston->flags&2))
	{
		// bumped
		SoundEffect(346, &item->pos, 0);
		SoundEffect(347, &item->pos, 0);
		winston->flags |= 2;
	}
	else if (!item->touch_bits && winston->flags&2)
		winston->flags -= 2;

	// tray clink
	if (GetRandomDraw() < 0x100)
		SoundEffect(347, &item->pos, 0);

#ifdef DEBUG_WINSTON
	sprintf(exit_message, "Mood: %d", winston->mood);
	PrintDbug(2, 2, exit_message);

	sprintf(exit_message, "LBox:%d, LZ:%d", lara_item->box_number, info.enemy_zone);
	PrintDbug(2, 3, exit_message);
#endif

	CreatureAnimation(item_number, angle, 0);
}
