/*********************************************************************************************/
/*                                                                                           */
/* Macaque Monkey - TS - 1/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 "people.h"
#include "control.h"


void InitialiseMonkey(sint16 item_number);
void MonkeyControl(sint16 item_number);
void DrawMonkey(ITEM_INFO *item);

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

void *func[] = {
	&InitialiseMonkey,
	&MonkeyControl,
	&DrawMonkey,
};

#endif

extern CREATURE_INFO *baddie_slots;

//#define MONKEY_HIT_DAMAGE 80
//#define MONKEY_SWIPE_DAMAGE 100
#define MONKEY_HIT_DAMAGE 40
#define MONKEY_SWIPE_DAMAGE 50


/*********************************** TYPE DEFINITIONS ****************************************/

// Monkeys start off friendly but can nick dropped items

BITE_INFO monkey_hit = {10,10,11, 13};

enum monkey_anims {MONKEY_EMPTY, MONKEY_STOP, MONKEY_WALK, MONKEY_STAND, MONKEY_RUN, MONKEY_PICKUP, MONKEY_SIT, MONKEY_EAT, MONKEY_SCRATCH, MONKEY_ROLL, MONKEY_ANGRY,
	MONKEY_DEATH, MONKEY_ATAK_LOW, MONKEY_ATAK_HIGH, MONKEY_ATAK_JUMP, MONKEY_CLIMB4, MONKEY_CLIMB3, MONKEY_CLIMB2, MONKEY_DOWN4, MONKEY_DOWN3, MONKEY_DOWN2};

#define MONKEY_WALK_TURN (ONE_DEGREE*7)
#define MONKEY_RUN_TURN (ONE_DEGREE*11)

#define MONKEY_ATTACK_RANGE SQUARE(WALL_L/3)
#define MONKEY_JUMP_RANGE SQUARE(WALL_L*2/3)

#define MONKEY_WALK_RANGE SQUARE(WALL_L*2/3)
#define MONKEY_ROLL_RANGE SQUARE(WALL_L)

#define MONKEY_WALK_CHANCE 0x100
#define MONKEY_WAIT_CHANCE 0x100

#define MONKEY_DIE_ANIM 14
#define MONKEY_SIT_ANIM 2

#define MONKEY_CLIMB2_ANIM 19
#define MONKEY_CLIMB3_ANIM 18
#define MONKEY_CLIMB4_ANIM 17
#define MONKEY_DOWN2_ANIM  22
#define MONKEY_DOWN3_ANIM  21
#define MONKEY_DOWN4_ANIM  20

#define MONKEY_TOUCH 0x2400

//#define MONKEY_VAULT_SHIFT 260
#define MONKEY_VAULT_SHIFT 128

#define MONKEY_AWARE_DISTANCE SQUARE(WALL_L)
#define MONKEY_HIT_RADIUS (STEP_L)

//#define DEBUG_MONKEY

#ifdef DEBUG_MONKEY
extern char exit_message[];
#endif

#ifdef DEBUG_MONKEY
static char *MonkeyStrings[] = {"EMPTY", "STOP", "WALK", "STAND", "RUN", "PICKUP", "SIT", "EAT", "SCRATCH", "ROLL", "ANGRY",
	"DEATH", "ATAK_LOW", "ATAK_HIGH", "ATAK_JUMP", "CLIMB4", "CLIMB3", "CLIMB2", "DOWN4", "DOWN3", "DOWN2"};
#endif

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

void InitialiseMonkey(sint16 item_number)
{
	ITEM_INFO *item;

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

	/* Start Monkey in stop pose*/
	item->anim_number = objects[MONKEY].anim_index + MONKEY_SIT_ANIM;
	item->frame_number = anims[item->anim_number].frame_base;
	item->current_anim_state = item->goal_anim_state = MONKEY_SIT;
}

void DrawMonkey(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_MONKEY
//	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[MONKEY].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
		{
#ifdef PSX_VERSION
			InitInterpolate(frac, rate, &iMatrixStack[0]);
#else
			InitInterpolate( frac,rate );
#endif
			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...
				{
#ifdef PSX_VERSION
					if (poppush & ROT_Y)
					{
						mRotY(*extra_rotation);
						iRotY(*extra_rotation++);
					}

					if (poppush & ROT_X)
					{
						mRotX(*extra_rotation);
						iRotX(*extra_rotation++);
					}

					if (poppush & ROT_Z)
					{
						mRotZ(*extra_rotation);
						iRotZ(*extra_rotation++);
					}
#else
					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++));
#endif
				}

				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 MonkeyControl(sint16 item_number)
{
	ITEM_INFO *item, *enemy, *target, *pickup;
	CREATURE_INFO *monkey, *cinfo;
	sint16 angle, torso_y, torso_x, head, tilt, slot, i;
	sint32 lara_dx, lara_dz;
	AI_INFO info, lara_info;

	if (!CreatureActive(item_number))
		return;

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


	if (item->hit_points <= 0)
	{
		if (item->current_anim_state != MONKEY_DEATH)
		{
			item->mesh_bits = 0xffffffff; //Drop it!
			item->anim_number = objects[MONKEY].anim_index + MONKEY_DIE_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_DEATH;
		}
	}
	else
	{
	//	if (item->ai_bits)
			GetAITarget(monkey);
	/*	else*/ if (monkey->hurt_by_lara)
			monkey->enemy = lara_item;
			else
		{
			/*
			monkey->enemy = NULL;
			best_distance = 0x7fffffff;
			cinfo = baddie_slots;
			for (slot=0; slot<NUM_SLOTS; slot++, cinfo++)
			{
				if (cinfo->item_num==NO_ITEM || cinfo->item_num==item_number)
					continue;
				target = &items[cinfo->item_num];
				if (target->object_number == LARA  || target->object_number == MONKEY || target->object_number == ROBOT_SENTRY_GUN)
					continue;
				// Is this target closest?
				x = target->pos.x_pos - item->pos.x_pos;
				z = target->pos.z_pos - item->pos.z_pos;
				distance = x*x + z*z;
				if (distance < best_distance)
				{
					monkey->enemy = target;
					best_distance = distance;
				}
			}
			*/
			//Go thru item list to find a medi-kit


		}

		if (item->ai_bits != MODIFY)
		{
			if (item->carried_item != NO_ITEM)
						item->mesh_bits = 0xfffffeff; //Swap the head!
			else
						item->mesh_bits = 0xffffffff;
		}
		else
		{
			if (item->carried_item != NO_ITEM)
						item->mesh_bits = 0xffff6e6f; //Swap the head and the feet
			else
						item->mesh_bits = 0xffff6f6f; //Just swap the feet
		}

		CreatureAIInfo(item, &info);

		if (!monkey->hurt_by_lara && monkey->enemy == lara_item && objects[TIGER].loaded) //Monkeys are friendly on the first level
			monkey->enemy = NULL;

		if (monkey->enemy == lara_item)
		{
			lara_info.angle = info.angle;
			lara_info.distance = info.distance;
		}
		else
		{
			lara_dz = lara_item->pos.z_pos - item->pos.z_pos;
			lara_dx = lara_item->pos.x_pos - item->pos.x_pos;
			lara_info.angle = phd_atan(lara_dz, lara_dx) - item->pos.y_rot; //only need to fill out the bits of lara_info that will be needed by TargetVisible
			lara_info.distance = lara_dz * lara_dz + lara_dx * lara_dx;
		}

		GetCreatureMood(item, &info, VIOLENT);
		if (lara.skidoo != NO_ITEM)
			monkey->mood = ESCAPE_MOOD;
		CreatureMood(item, &info, VIOLENT);


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

#ifdef DEBUG_MONKEY
//		sprintf(exit_message, "head: %d, Target Visible?: %d", monkey->joint_rotation[1], TargetVisible(item, &info));
//		PrintDbug(2, 5, exit_message);
#endif


		enemy = monkey->enemy; //TargetVisible uses enemy, so need to fill this in as lara if we're doing other things
		monkey->enemy = lara_item;
//		if ((lara_info.distance < MONKEY_AWARE_DISTANCE || item->hit_status || TargetVisible(item, &lara_info)) && !(item->ai_bits & FOLLOW)) //Maybe move this into LONDSEC_WAIT case?
		if (item->hit_status)
			AlertAllGuards(item_number);
		monkey->enemy = enemy;

		enemy = monkey->enemy;

		switch (item->current_anim_state)
		{
			case MONKEY_SIT:
				monkey->flags = 0;

				monkey->maximum_turn = 0;

				head = lara_info.angle;

				if (item->ai_bits & GUARD)
				{
					head = AIGuard(monkey);
					if (!(GetRandomControl() & 0xF))
					{
						if (GetRandomControl() & 0x1)
							item->goal_anim_state = MONKEY_SCRATCH;
						else
							item->goal_anim_state = MONKEY_EAT;
					}
					break;
				}

				else if (item->ai_bits & PATROL1)
					item->goal_anim_state = MONKEY_WALK;

				else if (monkey->mood == ESCAPE_MOOD)
					item->goal_anim_state = MONKEY_STAND;
				else if (monkey->mood == BORED_MOOD)
				{
					if (item->required_anim_state)
						item->goal_anim_state = item->required_anim_state;
				//	else if (info.ahead)
				//		item->goal_anim_state = MONKEY_SIT;
					else if (!(GetRandomControl() & 0xF))
						item->goal_anim_state = MONKEY_WALK;
					else if (!(GetRandomControl() & 0xF))
					{
						if (GetRandomControl() & 0x1)
							item->goal_anim_state = MONKEY_SCRATCH;
						else
							item->goal_anim_state = MONKEY_EAT;
					}

				}

				else if((item->ai_bits & FOLLOW ) && (monkey->reached_goal || lara_info.distance > SQUARE(WALL_L*2)))
				{
					if (item->required_anim_state)
						item->goal_anim_state = item->required_anim_state;
					else if (info.ahead)
						item->goal_anim_state = MONKEY_SIT;
					else
						item->goal_anim_state = MONKEY_STAND;
				}
				else if (info.bite && info.distance < MONKEY_JUMP_RANGE)
					item->goal_anim_state = MONKEY_STAND;
				else if (info.bite && info.distance < MONKEY_WALK_RANGE)
					item->goal_anim_state = MONKEY_WALK;
				else
					item->goal_anim_state = MONKEY_STAND;
				break;

			case MONKEY_STAND:
				monkey->flags = 0;

				monkey->maximum_turn = 0;

				head = lara_info.angle;

				if (item->ai_bits & GUARD)
				{
					head = AIGuard(monkey);
					if (!(GetRandomControl() & 0xF))
					{
						if (GetRandomControl() & 0x1)
							item->goal_anim_state = MONKEY_ANGRY;
						else
							item->goal_anim_state = MONKEY_SIT;
					}
					break;
				}
				else if (item->ai_bits & PATROL1)
					item->goal_anim_state = MONKEY_WALK;
				else if (monkey->mood == ESCAPE_MOOD)
				{
					if (lara.target != item && info.ahead)
						item->goal_anim_state = MONKEY_STAND;
					else
						item->goal_anim_state = MONKEY_RUN;
				}
				else if (monkey->mood == BORED_MOOD)
				{
					if (item->required_anim_state)
						item->goal_anim_state = item->required_anim_state;
				//	else if (info.ahead)
				//		item->goal_anim_state = MONKEY_SIT;
					else if (!(GetRandomControl() & 0xF))
						item->goal_anim_state = MONKEY_WALK;
					else if (!(GetRandomControl() & 0xF))
					{
						if (GetRandomControl() & 0x1)
							item->goal_anim_state = MONKEY_ANGRY;
						else
							item->goal_anim_state = MONKEY_SIT;
					}

				}

				else if((item->ai_bits & FOLLOW ) && (monkey->reached_goal || lara_info.distance > SQUARE(WALL_L*2)))
				{
					if (item->required_anim_state)
						item->goal_anim_state = item->required_anim_state;
					else if (info.ahead)
						item->goal_anim_state = MONKEY_SIT;
					else
						item->goal_anim_state = MONKEY_RUN;
				}
				else if (info.bite && info.distance < MONKEY_ATTACK_RANGE)
				{
					if (lara_item->pos.y_pos < item->pos.y_pos)
						item->goal_anim_state = MONKEY_ATAK_HIGH;
					else
						item->goal_anim_state = MONKEY_ATAK_LOW;
				}
				else if (info.bite && info.distance < MONKEY_JUMP_RANGE)
					item->goal_anim_state = MONKEY_ATAK_JUMP;
				else if (info.bite && info.distance < MONKEY_WALK_RANGE)
					item->goal_anim_state = MONKEY_WALK;
				else if (info.distance < MONKEY_WALK_RANGE && monkey->enemy != lara_item && monkey->enemy != NULL
					&& monkey->enemy->object_number != AI_PATROL1 && monkey->enemy->object_number != AI_PATROL2
					&& abs(item->pos.y_pos - monkey->enemy->pos.y_pos) < STEP_L)
					item->goal_anim_state = MONKEY_PICKUP;
				else if (info.bite && info.distance < MONKEY_ROLL_RANGE)
					item->goal_anim_state = MONKEY_ROLL;
				else
					item->goal_anim_state = MONKEY_RUN;
				break;

			case MONKEY_PICKUP:
				monkey->reached_goal = 1;	//Just stand and wait
	//			i= (enemy - items) / sizeof(ITEM_INFO); //work out the item number
				if (monkey->enemy == NULL)
					break;
				else if ((monkey->enemy->object_number == MEDI_ITEM || monkey->enemy->object_number == KEY_ITEM4) && item->frame_number == anims[item->anim_number].frame_base + 12)
				{

					if (monkey->enemy->room_number == NO_ROOM || monkey->enemy->status == INVISIBLE || monkey->enemy->flags & KILLED_ITEM)
						monkey->enemy = NULL;
					else
					{
						i = monkey->enemy - items;

						item->carried_item = i;
						RemoveDrawnItem(i);
						monkey->enemy->room_number = NO_ROOM;
						monkey->enemy->carried_item = NO_ITEM;

						cinfo = baddie_slots;	//Need to stop any other monkeys targetting this pickup now we've got it

						for (slot=0; slot<NUM_SLOTS; slot++, cinfo++)
						{
							if (cinfo->item_num==NO_ITEM || cinfo->item_num==item_number)
								continue;
							target = &items[cinfo->item_num];
							if (cinfo->enemy == monkey->enemy)
									cinfo->enemy = NULL;
						}
						monkey->enemy = NULL;
						if (item->ai_bits != MODIFY)
						{
							item->ai_bits |= AMBUSH; //Run for the ambush point
							item->ai_bits |= MODIFY;
						}


					}
				}
				else if (monkey->enemy->object_number == AI_AMBUSH && item->frame_number == anims[item->anim_number].frame_base + 12)
				{
					item->ai_bits = 0;
					pickup = &items[item->carried_item];
					pickup->pos.x_pos = item->pos.x_pos;
					pickup->pos.y_pos = item->pos.y_pos;
					pickup->pos.z_pos = item->pos.z_pos;
					ItemNewRoom(item->carried_item, item->room_number);
					item->carried_item = NO_ITEM;
					pickup->ai_bits = 1;
					monkey->enemy = NULL;
				}
				else
				{
					monkey->maximum_turn = 0;
					if (abs(info.angle) <  MONKEY_WALK_TURN)
						item->pos.y_rot += info.angle;
					else if (info.angle < 0)
						item->pos.y_rot -= MONKEY_WALK_TURN;
					else
						item->pos.y_rot += MONKEY_WALK_TURN;
				}


				break;

			case MONKEY_WALK:
				head=lara_info.angle;

				monkey->maximum_turn = MONKEY_WALK_TURN;

				if (item->ai_bits & PATROL1)
				{
					item->goal_anim_state = MONKEY_WALK;
					head=0;
				}
				else if (monkey->mood == ESCAPE_MOOD)
					item->goal_anim_state = MONKEY_RUN;
				else if (monkey->mood == BORED_MOOD)
				{
					if (GetRandomControl() < MONKEY_WAIT_CHANCE)
					{
						item->goal_anim_state = MONKEY_SIT;
					}
				}
				else if (info.bite && info.distance < MONKEY_JUMP_RANGE)
					item->goal_anim_state = MONKEY_STAND;
				else //if (!info.ahead || info.distance > MONKEY_WALK_RANGE)
					item->goal_anim_state = MONKEY_STAND;
				break;

			case MONKEY_RUN:
				if (info.ahead)
					head = info.angle;

				monkey->maximum_turn = MONKEY_RUN_TURN;
				tilt = angle/2;

				if (item->ai_bits & GUARD)
					item->goal_anim_state = MONKEY_STAND;
				else if (monkey->mood == ESCAPE_MOOD)
				{
					if (lara.target != item && info.ahead)
						item->goal_anim_state = MONKEY_STAND;
					break;
				}
				else if ((item->ai_bits & FOLLOW ) && (monkey->reached_goal || lara_info.distance > SQUARE(WALL_L*2)))
					item->goal_anim_state = MONKEY_STAND;	//Maybe MONKEY_WAIT?
				else if (monkey->mood == BORED_MOOD)
					item->goal_anim_state = MONKEY_ROLL;
//				else if (info.ahead && info.distance < MONKEY_WALK_RANGE)
				else if (info.distance < MONKEY_WALK_RANGE)
					item->goal_anim_state = MONKEY_STAND;
				else if (info.bite && info.distance < MONKEY_ROLL_RANGE)
					item->goal_anim_state = MONKEY_ROLL;
				break;


			case MONKEY_ATAK_LOW:
				if (info.ahead)
				{
					torso_y = info.angle;
					torso_x = info.x_angle;
				}

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

				if (enemy == lara_item)
				{
					if (!monkey->flags && (item->touch_bits & MONKEY_TOUCH))
					{
						lara_item->hit_points -= MONKEY_HIT_DAMAGE;
						lara_item->hit_status = 1;
						CreatureEffect(item, &monkey_hit, DoBloodSplat);

						monkey->flags = 1;
					}
				}
				else
				{
					if (!monkey->flags && enemy)
					{
						if (ABS(enemy->pos.x_pos - item->pos.x_pos) < MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.y_pos - item->pos.y_pos) <= MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.z_pos - item->pos.z_pos) < MONKEY_HIT_RADIUS)
						{
							enemy->hit_points -= MONKEY_HIT_DAMAGE>>1;
							enemy->hit_status = 1;
							monkey->flags = 1;
							CreatureEffect(item, &monkey_hit, DoBloodSplat);
						}
					}
				}


				break;

			case MONKEY_ATAK_HIGH:
				if (info.ahead)
				{
					torso_y = info.angle;
					torso_x = info.x_angle;
				}

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

				if (enemy == lara_item)
				{
					if (!monkey->flags && (item->touch_bits & MONKEY_TOUCH))
					{
						lara_item->hit_points -= MONKEY_HIT_DAMAGE;
						lara_item->hit_status = 1;
						CreatureEffect(item, &monkey_hit, DoBloodSplat);

						monkey->flags = 1;
					}
				}
				else
				{
					if (!monkey->flags && enemy)
					{
						if (ABS(enemy->pos.x_pos - item->pos.x_pos) < MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.y_pos - item->pos.y_pos) <= MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.z_pos - item->pos.z_pos) < MONKEY_HIT_RADIUS)
						{
							enemy->hit_points -= MONKEY_HIT_DAMAGE>>1;
							enemy->hit_status = 1;
							monkey->flags = 1;
							CreatureEffect(item, &monkey_hit, DoBloodSplat);
						}
					}
				}


			case MONKEY_ATAK_JUMP:
				if (info.ahead)
				{
					torso_y = info.angle;
					torso_x = info.x_angle;
				}

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

				if (enemy == lara_item)
				{
					if (monkey->flags!=1 && (item->touch_bits & MONKEY_TOUCH))
					{
						lara_item->hit_points -= MONKEY_SWIPE_DAMAGE;
						lara_item->hit_status = 1;
						CreatureEffect(item, &monkey_hit, DoBloodSplat);

						monkey->flags = 1;
					}
				}
				else
				{
					if (monkey->flags!=1 && enemy)
					{
						if (ABS(enemy->pos.x_pos - item->pos.x_pos) < MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.y_pos - item->pos.y_pos) <= MONKEY_HIT_RADIUS &&
						 	ABS(enemy->pos.z_pos - item->pos.z_pos) < MONKEY_HIT_RADIUS)
						{
							enemy->hit_points -= MONKEY_SWIPE_DAMAGE>>1;
							enemy->hit_status = 1;
							monkey->flags = 1;
							CreatureEffect(item, &monkey_hit, DoBloodSplat);
						}
					}
				}


				break;
		}
	}

	CreatureTilt(item, tilt);
	CreatureJoint(item, 0, torso_y);
//	CreatureJoint(item, 1, torso_x);
//	CreatureJoint(item, 2, head);

	#ifdef DEBUG_MONKEY
	sprintf(exit_message, "Mood: %d", monkey->mood);
	PrintDbug(2, 2, exit_message);
	sprintf(exit_message, "%s", MonkeyStrings[item->current_anim_state]);
	PrintDbug(2, 3, exit_message);
	sprintf(exit_message, "%s", MonkeyStrings[item->goal_anim_state]);
	PrintDbug(2, 4, exit_message);
//	sprintf(exit_message, "MyBox:%d, LBox:%d, TBox:%d", item->box_number, lara_item->box_number, monkey->LOT.target_box);
//	PrintDbug(2, 5, exit_message);
//	sprintf(exit_message, "TX:%d, TZ:%d, LX:%d, LZ:%d", monkey->target.x, monkey->target.z, lara_item->pos.x_pos, lara_item->pos.z_pos);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "%s", MonkeyStrings[item->required_anim_state]);
//	PrintDbug(2, 6, exit_message);
//	sprintf(exit_message, "Anim Number; %d", item->anim_number - objects[MONKEY].anim_index);
//	PrintDbug(2, 6, exit_message);
	sprintf(exit_message, "Alert:%d, Goal:%d, Hurt:%d", monkey->alerted, monkey->reached_goal, monkey->hurt_by_lara);
	PrintDbug(2,6, exit_message);

	sprintf(exit_message, "AI Bits: %d", item->ai_bits);
	PrintDbug(2,7, exit_message);
	#endif

#ifdef DEBUG_MONKEY
//	sprintf(exit_message, "Torso_y: %d, Torso_x: %d, Head: %d", torso_y, torso_x, head);
//	PrintDbug(2, 2, exit_message);
//	sprintf(exit_message, "Max Turn: %d", monkey->maximum_turn);
//	PrintDbug(2, 2, exit_message);
//	sprintf(exit_message, "Angle: %d", angle);
//	PrintDbug(2, 2, exit_message);
	#endif

	/* Actually do animation allowing for collisions */
//## BUG: was still doing this when he was dying!
//	if (item->current_anim_state < MONKEY_CLIMB3) // Know CLIMB3 marks the start of the CLIMB states
	if (item->current_anim_state < MONKEY_CLIMB4) // Know CLIMB3 marks the start of the CLIMB states
	{
		switch (CreatureVault(item_number, angle, 2, MONKEY_VAULT_SHIFT))
		{
		case 2:
			/* Half block jump */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_CLIMB2_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_CLIMB2;
			break;

		case 3:
			/* 3/4 block jump */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_CLIMB3_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_CLIMB3;
			break;

		case 4:
			/* Full block jump */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_CLIMB4_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_CLIMB4;
			break;

		case -2:
			/* Full block fall */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_DOWN2_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_DOWN2;
			break;

		case -3:
			/* Full block fall */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_DOWN3_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_DOWN3;
			break;

		case -4:
			/* Full block fall */
			monkey->maximum_turn = 0;
			item->anim_number = objects[MONKEY].anim_index + MONKEY_DOWN4_ANIM;
			item->frame_number = anims[item->anim_number].frame_base;
			item->current_anim_state = MONKEY_DOWN4;
			break;
		}
	}
	else
	{
		monkey->maximum_turn = 0;
		CreatureAnimation(item_number, angle, 0);
	}
}


