/*
**	Command & Conquer Renegade(tm)
**	Copyright 2025 Electronic Arts Inc.
**
**	This program is free software: you can redistribute it and/or modify
**	it under the terms of the GNU General Public License as published by
**	the Free Software Foundation, either version 3 of the License, or
**	(at your option) any later version.
**
**	This program is distributed in the hope that it will be useful,
**	but WITHOUT ANY WARRANTY; without even the implied warranty of
**	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
**	GNU General Public License for more details.
**
**	You should have received a copy of the GNU General Public License
**	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/***********************************************************************************************
 ***              C O N F I D E N T I A L  ---  W E S T W O O D  S T U D I O S               ***
 ***********************************************************************************************
 *                                                                                             *
 *                 Project Name : combat                                                       *
 *                                                                                             *
 *                     $Archive:: /Commando/Code/Combat/mendozabossgameobj.cpp                $*
 *                                                                                             *
 *                       Author:: Patrick Smith                                                *
 *                                                                                             *
 *                     $Modtime:: 1/23/02 3:28p                                               $*
 *                                                                                             *
 *                    $Revision:: 13                                                          $*
 *                                                                                             *
 *---------------------------------------------------------------------------------------------*
 * Functions:                                                                                  *
 * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#include "mendozabossgameobj.h"
#include "wwhack.h"
#include "simpledefinitionfactory.h"
#include "persistfactory.h"
#include "combatchunkid.h"
#include "debug.h"
#include "animcontrol.h"
#include "crandom.h"
#include "weapons.h"
#include "rendobj.h"
#include "wwaudio.h"
#include "audiblesound.h"
#include "explosion.h"
#include "phys.h"
#include "pscene.h"
#include "waypath.h"
#include "waypoint.h"
#include "pathfind.h"
#include "pathmgr.h"
#include "string_ids.h"
#include "translateobj.h"
#include "translatedb.h"
#include "wwprofile.h"
#include "conversationmgr.h"
#include "activeconversation.h"
#include "conversation.h"
#include "combat.h"
#include "assetmgr.h"
#include "ccamera.h"
#include "gameobjmanager.h"
#include "transitioneffect.h"
#include "coltest.h"
#include "phys3.h"
#include "animobj.h"
#include "powerup.h"
#include "weaponbag.h"
#include "humanphys.h"
#include "physcoltest.h"
#include "objlibrary.h"
#include "hudinfo.h"


DECLARE_FORCE_LINK (MendozaBoss)


//////////////////////////////////////////////////////////////////////////
//	Constants
//////////////////////////////////////////////////////////////////////////
static const AABoxClass BOSS_AREA_BOX01 (Vector3 (-19.2585F, 27.7224F, 0.434677F), Vector3 (5.06771F, 15.6146F, 1.0F));
static const AABoxClass BOSS_AREA_BOX02 (Vector3 (-42.3353F, 32.8650F, 0.434677F), Vector3 (18.1846F, 22.7105F, 1.0F));
static const AABoxClass BOSS_AREA_BOX03 (Vector3 (-64.4650F, 29.5306F, 0.434677F), Vector3 (4.15638F, 18.2853F, 1.0F));

static Vector3		MENDOZA_END_POS (-58.088F, 15.389F, 0.334F);
static Vector3		SYDNEY_END_POS (-57.931F, 12.133F, 0.412F);
static Vector3		HELIPAD_CENTER_POS (-43.329F, 30.796F, 1.605F);

static const float	UNINITIALIZED_TIMER	= -5000.0F;
static const float	FALLDOWN_TIMER			= 6.0F;

//////////////////////////////////////////////////////////////////////////
//	Waypath IDs
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
//	Weapon and state enumerations
//////////////////////////////////////////////////////////////////////////



//////////////////////////////////////////////////////////////////////////
//	Taunt constants
//////////////////////////////////////////////////////////////////////////

static const char *TAUNT_IDS[6] =
{
	"IDS_SAKURA_BOSS_TAUNT1",
	"IDS_SAKURA_BOSS_TAUNT2",
	"IDS_SAKURA_BOSS_TAUNT3",
	"IDS_SAKURA_BOSS_TAUNT4",
	"IDS_SAKURA_BOSS_TAUNT5",
	"IDS_SAKURA_BOSS_TAUNT6"
};


//////////////////////////////////////////////////////////////////////////
//	Save/load constants
//////////////////////////////////////////////////////////////////////////
enum
{
	CHUNKID_DEF_PARENT								=	0x09230242,
	CHUNKID_DEF_VARIABLES,

	VARID_DEF_GATLING_DEF_ID						= 1,
	VARID_DEF_ROCKET_DEF_ID,
	VARID_DEF_GATLING_REV_SOUND_ID,
	VARID_DEF_ROCKET_DOOR_SOUND_ID,
	VARID_DEF_ROCKET_DESTROYED_EXPLOSION_ID
};

enum
{
	CHUNKID_PARENT										=	0x09230243,
	CHUNKID_VARIABLES,
	CHUNKID_STATE_MACHINES,
	CHUNKID_CAMERA_SPLINE,
	CHUNKID_OVERALL_STATE_MACHINE,
	CHUNKID_MENDOZA_STATE_MACHINE,
	CHUNKID_SYDNEY_STATE_MACHINE,
	CHUNKID_MOVE_STATE_MACHINE,
	CHUNKID_HEAD_STATE_MACHINE,
	CHUNKID_CAMERA_STATE_MACHINE,
	CHUNKID_ATTACK_STATE_MACHINE,

	VARID_OVERALLSTATE_TIMER					= 0,
	VARID_MENDOZASTATE_TIMER,
	VARID_CAMERASTATE_TIMER,
	VARID_CAMERASHAKE_TIMER,
	VARID_ATTACKSTATE_TIMER,
	VARID_RANDOMTARGET_TIMER,
	VARID_SYDNEYSTATE_TIMER,
	VARID_MOVESTATE_TIMER,
	VARID_NEXT_MELEE_ATTACK_TIME,
	VARID_FIREBALL_START_TIMER,
	VARID_NEXT_KNOCKDOWN_AVAILABLE_TIME,
	VARID_HAS_MELEE_ATTACK_HIT,
	VARID_LAST_MELEE_ANIM_FRAME,
	VARID_START_TIMER,
	VARID_SIDE_KICK_POS,
	VARID_SHOOT_GROUND_POS,
	VARID_ATTACKING_BONE_NAME,
	VARID_CAMERA_BONE_PTR,
	VARID_CAMERA_BONE_TM
};


//////////////////////////////////////////////////////////////////////////
//	Factories
//////////////////////////////////////////////////////////////////////////
SimplePersistFactoryClass<MendozaBossGameObjDefClass,		CHUNKID_GAME_OBJECT_DEF_MENDOZA_BOSS>						_MendozaBossGameObjDefPersistFactory;
SimplePersistFactoryClass<MendozaBossGameObjClass,			CHUNKID_GAME_OBJECT_MENDOZA_BOSS>							_MendozaBossGameObjPersistFactory;
DECLARE_DEFINITION_FACTORY(MendozaBossGameObjDefClass,	CLASSID_GAME_OBJECT_DEF_MENDOZA_BOSS, "Mendoza Boss")	_MendozaBossGameObjDefDefFactory;



//////////////////////////////////////////////////////////////////////////
//
//	MendozaBossGameObjDefClass
//
//////////////////////////////////////////////////////////////////////////
MendozaBossGameObjDefClass::MendozaBossGameObjDefClass (void)
{
	UseInnateBehavior = false;

	PARAM_SEPARATOR (MendozaBossGameObjDefClass, "Boss Settings");
	PARAM_SEPARATOR (MendozaBossGameObjDefClass, "");
	return ;
}


//////////////////////////////////////////////////////////////////////////
//
//	~MendozaBossGameObjDefClass
//
//////////////////////////////////////////////////////////////////////////
MendozaBossGameObjDefClass::~MendozaBossGameObjDefClass (void)
{	
	return ;
}


//////////////////////////////////////////////////////////////////////////
//
//	Get_Class_ID
//
//////////////////////////////////////////////////////////////////////////
uint32
MendozaBossGameObjDefClass::Get_Class_ID (void) const	
{ 
	return CLASSID_GAME_OBJECT_DEF_MENDOZA_BOSS; 
}


//////////////////////////////////////////////////////////////////////////
//
//	Create
//
//////////////////////////////////////////////////////////////////////////
PersistClass *
MendozaBossGameObjDefClass::Create (void) const
{
	MendozaBossGameObjClass *obj = new MendozaBossGameObjClass;
	obj->Init(*this);
	return obj;
}


//////////////////////////////////////////////////////////////////////////
//
//	Save
//
//////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjDefClass::Save (ChunkSaveClass &csave)
{
	csave.Begin_Chunk (CHUNKID_DEF_PARENT);
		SoldierGameObjDef::Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_DEF_VARIABLES);
		Save_Variables (csave);
	csave.End_Chunk();

	return true;
}


//////////////////////////////////////////////////////////////////////////
//
//	Load
//
//////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjDefClass::Load (ChunkLoadClass &cload)
{
	while (cload.Open_Chunk ()) {
		switch(cload.Cur_Chunk_ID ()) {

			case CHUNKID_DEF_PARENT:
				SoldierGameObjDef::Load (cload);
				break;

			case CHUNKID_DEF_VARIABLES:
				Load_Variables (cload);
				break;

			default:
				Debug_Say (("Unrecognized MendozaBossGameObjDefClass chunkID\n"));
				break;
		}

		cload.Close_Chunk ();
	}

	return true;
}


///////////////////////////////////////////////////////////////////////////
//
//	Save_Variables
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjDefClass::Save_Variables (ChunkSaveClass &csave)
{
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Load_Variables
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjDefClass::Load_Variables (ChunkLoadClass &cload)
{
	/*while (cload.Open_Micro_Chunk ()) {
		switch (cload.Cur_Micro_Chunk_ID ()) {

			default:
				Debug_Say (("Unrecognized MendozaBossGameObjDefClass Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID ()));
				break;
		}

		cload.Close_Micro_Chunk ();
	}*/

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Get_Factory
//
///////////////////////////////////////////////////////////////////////////
const PersistFactoryClass &
MendozaBossGameObjDefClass::Get_Factory (void) const
{ 
	return _MendozaBossGameObjDefPersistFactory; 
}


/*
**
**	Start of MendozaBossGameObjClass
**
*/


///////////////////////////////////////////////////////////////////////////
//
//	MendozaBossGameObjClass
//
///////////////////////////////////////////////////////////////////////////
MendozaBossGameObjClass::MendozaBossGameObjClass (void)	:
	MendozaTauntTimeLeft (0),
	AvailableTaunts (0xFFFFFF),
	OverallState (this),
	MendozaState (this),
	SydneyState (this),
	AttackState (this),
	CameraState (this),
	MoveState (this),
	HeadState (this),
	OverallStateTimer (0),
	MendozaStateTimer (0),	
	CameraShakeTimer (0),
	CameraStateTimer (0),
	StartTimer (0),
	AttackStateTimer (0),
	RandomTargetTimer (0),
	FireballStartTimer (0),
	NextKnockdownAvailableTime (0),
	SydneyStateTimer (0),
	HasMeleeAttackHit (false),
	LastMeleeAnimFrame (0),
	NextMeleeAttackTime (0),
	MoveStateTimer (0),
	CameraBoneModel (NULL),
	Sydney (NULL),
	MendozaPos (0, 0, 0),
	StarPos (0, 0, 0),
	ShootGroundPos (0, 0, 0),
	SideKickPos (0, 0, 0)
{
	Shuffle_Taunt_List ();
	TauntList[0] = 1;//IDS_SAKURA_BOSS_TAUNT1;
	TauntList[1] = 2;//IDS_SAKURA_BOSS_TAUNT2;
	TauntList[2] = 3;//IDS_SAKURA_BOSS_TAUNT3;
	TauntList[3] = 4;//IDS_SAKURA_BOSS_TAUNT4;
	TauntList[4] = 5;//IDS_SAKURA_BOSS_TAUNT5;
	TauntList[5] = 6;//IDS_SAKURA_BOSS_TAUNT6;

	//
	//	Register the Overall states with its state machine
	//	
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_FLYING_SIDEKICK);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_MELEE_ATTACK);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_RANGED_ATTACK);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_FIREBALL_ATTACK);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_FIND_HEALTH);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_SYDNEY_BOLTS);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_RUN_AFTER_SYDNEY);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_TOY_WITH_SYDNEY);
	ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_DEATH_SEQUENCE);
	
	//
	//	Register the Move states with its state machine
	//
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_STOP);
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_GET_CLOSE_TO_PLAYER);
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_ATTACK_PATTERN1);
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_ATTACK_PATTERN2);
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_GOTO_HELIPAD);	
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_RUN_TO_HEALTH);
	ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_CHASE_SYDNEY);

	//
	//	Register the Mendoza states with its state machine
	//
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_STANDING);
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_FALLING);
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_KIPPING);
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_PACK_EXPLODING);
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_DYING);
	ADD_STATE_TO_MACHINE (MendozaState, MENDOZA_STATE_DEAD);
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	
	//
	//	Register the Sydney states with its state machine
	//
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_WAITING);
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_BOLTING);
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_TRIPPING);
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_GETTING_UP);	
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_COWERING);
	ADD_STATE_TO_MACHINE (SydneyState, SYDNEY_STATE_STRIKE_A_POSE);	

	//
	//	Register the Head states with its state machine
	//
	ADD_STATE_TO_MACHINE (HeadState, HEAD_STATE_NONE);
	ADD_STATE_TO_MACHINE (HeadState, HEAD_STATE_LOOKING_AT_STAR);
	ADD_STATE_TO_MACHINE (HeadState, HEAD_STATE_LOOKING_AT_SYDNEY);

	//
	//	Register the attack states with its state machine
	//
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_NONE);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_FLYING_SIDEKICK);	
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_CRESENT_KICK);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_SIDE_KICK);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_SIDE_KICK_RETRACT);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_MELEE_PUNCH);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_FLAMETHROWER);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_FIREBALL);	
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_HANDGUN);
	ADD_STATE_TO_MACHINE (AttackState, ATTACK_STATE_SYDNEY);
	AttackState.Set_State (ATTACK_STATE_NONE);	

	//
	//	Register the camera states with its state machine
	//
	CameraState.Add_State (NULL,													NULL,		On_CAMERA_STATE_NORMAL_Begin,					NULL);
	CameraState.Add_State (On_CAMERA_STATE_FACE_ZOOM_Think,				NULL,		On_CAMERA_STATE_FACE_ZOOM_Begin,				NULL);
	CameraState.Add_State (On_CAMERA_STATE_WAYPATH_FOLLOW_Think,		NULL,		On_CAMERA_STATE_WAYPATH_FOLLOW_Begin,		NULL);
	CameraState.Add_State (On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Think,	NULL,		On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Begin,	NULL);	
	CameraState.Set_State (CAMERA_STATE_NORMAL);

	//
	//	Create the camera bone model...
	//
	CameraBoneModel = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("CAMBONE");
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	~MendozaBossGameObjClass
//
///////////////////////////////////////////////////////////////////////////
MendozaBossGameObjClass::~MendozaBossGameObjClass (void)
{
	REF_PTR_RELEASE (CameraBoneModel);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Get_Factory
//
///////////////////////////////////////////////////////////////////////////
const PersistFactoryClass &
MendozaBossGameObjClass::Get_Factory (void) const 
{
	return _MendozaBossGameObjPersistFactory;
}


////////////////////////////////////////////////////////////////
//
//	Init
//
////////////////////////////////////////////////////////////////
void MendozaBossGameObjClass::Init (void)
{
	Init ( Get_Definition ());
	return ;
}

///////////////////////////////////////////////////////////////////////////
//
//	Init
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Init (const MendozaBossGameObjDefClass &definition)
{
	SoldierGameObj::Init (definition);
	Initialize_Boss ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Get_Definition
//
///////////////////////////////////////////////////////////////////////////
const MendozaBossGameObjDefClass &
MendozaBossGameObjClass::Get_Definition (void) const
{
	return (const MendozaBossGameObjDefClass &)BaseGameObj::Get_Definition ();
}


///////////////////////////////////////////////////////////////////////////
//
//	Save
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::Save (ChunkSaveClass & csave)
{
	csave.Begin_Chunk (CHUNKID_PARENT);
		SoldierGameObj::Save (csave);
	csave.End_Chunk ();

	//
	//	Save the state machines to their own chunk
	//
	csave.Begin_Chunk (CHUNKID_OVERALL_STATE_MACHINE);
		OverallState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_MENDOZA_STATE_MACHINE);
		MendozaState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_SYDNEY_STATE_MACHINE);
		SydneyState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_MOVE_STATE_MACHINE);
		MoveState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_HEAD_STATE_MACHINE);
		HeadState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_CAMERA_STATE_MACHINE);
		CameraState.Save (csave);
	csave.End_Chunk ();

	csave.Begin_Chunk (CHUNKID_ATTACK_STATE_MACHINE);
		AttackState.Save (csave);		
	csave.End_Chunk ();

	//
	//	Save the camera spline
	//
	csave.Begin_Chunk (CHUNKID_CAMERA_SPLINE);
		CameraSpline.Save (csave);
	csave.End_Chunk ();
	
	csave.Begin_Chunk (CHUNKID_VARIABLES);
		Save_Variables (csave);
	csave.End_Chunk ();
	return true;
}


///////////////////////////////////////////////////////////////////////////
//
//	Load
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::Load (ChunkLoadClass &cload)
{
	while (cload.Open_Chunk ()) {
		switch(cload.Cur_Chunk_ID ()) {

			case CHUNKID_PARENT:
				SoldierGameObj::Load (cload);
				break;

			case CHUNKID_OVERALL_STATE_MACHINE:
				OverallState.Load (cload);
				break;

			case CHUNKID_MENDOZA_STATE_MACHINE:
				MendozaState.Load (cload);
				break;

			case CHUNKID_SYDNEY_STATE_MACHINE:
				SydneyState.Load (cload);
				break;

			case CHUNKID_MOVE_STATE_MACHINE:
				MoveState.Load (cload);
				break;

			case CHUNKID_HEAD_STATE_MACHINE:
				HeadState.Load (cload);
				break;

			case CHUNKID_CAMERA_STATE_MACHINE:
				CameraState.Load (cload);
				break;

			case CHUNKID_ATTACK_STATE_MACHINE:
				AttackState.Load (cload);		
				break;

			//
			//	Load the state machines from their chunk
			//
			case CHUNKID_STATE_MACHINES:
				OverallState.Load (cload);
				MendozaState.Load (cload);
				SydneyState.Load (cload);
				MoveState.Load (cload);
				HeadState.Load (cload);
				CameraState.Load (cload);
				AttackState.Load (cload);		
				break;

			//
			//	Load the camera spline
			//
			case CHUNKID_CAMERA_SPLINE:
				CameraSpline.Load (cload);
				break;

			case CHUNKID_VARIABLES:
				Load_Variables (cload);
				break;

			default:
				Debug_Say (("Unrecognized MendozaBossGameObjClass chunk ID\n"));
				break;

		}

		cload.Close_Chunk ();
	}

	SaveLoadSystemClass::Register_Post_Load_Callback (this);
	return true;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_Post_Load
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_Post_Load (void)
{	
	SoldierGameObj::On_Post_Load ();
	Initialize_Boss ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Initialize_Boss
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Initialize_Boss (void)
{
	//
	//	Find Sydney
	//
	PhysicalGameObj *game_obj = GameObjManager::Find_PhysicalGameObj (101010);
	if (game_obj != NULL) {
		Sydney = game_obj->As_SoldierGameObj ();
		
		//
		//	Turn off her innate AI...
		//
		Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ()->Innate_Disable ();
	}

	return ;	
}


///////////////////////////////////////////////////////////////////////////
//
//	Save_Variables
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Save_Variables (ChunkSaveClass &csave)
{
	Matrix3D cam_tm = CameraBoneModel->Get_Transform ();
	WRITE_MICRO_CHUNK (csave, VARID_CAMERA_BONE_PTR,					CameraBoneModel);
	WRITE_MICRO_CHUNK (csave, VARID_CAMERA_BONE_TM,						cam_tm);

	WRITE_MICRO_CHUNK (csave, VARID_OVERALLSTATE_TIMER,				OverallStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_MENDOZASTATE_TIMER,				MendozaStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_CAMERASTATE_TIMER,					CameraStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_CAMERASHAKE_TIMER,					CameraShakeTimer);
	WRITE_MICRO_CHUNK (csave, VARID_ATTACKSTATE_TIMER,					AttackStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_RANDOMTARGET_TIMER,				RandomTargetTimer);
	WRITE_MICRO_CHUNK (csave, VARID_SYDNEYSTATE_TIMER,					SydneyStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_MOVESTATE_TIMER,					MoveStateTimer);
	WRITE_MICRO_CHUNK (csave, VARID_NEXT_MELEE_ATTACK_TIME,			NextMeleeAttackTime);
	WRITE_MICRO_CHUNK (csave, VARID_FIREBALL_START_TIMER,				FireballStartTimer);
	WRITE_MICRO_CHUNK (csave, VARID_NEXT_KNOCKDOWN_AVAILABLE_TIME,	NextKnockdownAvailableTime);
	WRITE_MICRO_CHUNK (csave, VARID_HAS_MELEE_ATTACK_HIT,				HasMeleeAttackHit);
	WRITE_MICRO_CHUNK (csave, VARID_LAST_MELEE_ANIM_FRAME,			LastMeleeAnimFrame);
	WRITE_MICRO_CHUNK (csave, VARID_START_TIMER,							StartTimer);
	WRITE_MICRO_CHUNK (csave, VARID_SIDE_KICK_POS,						SideKickPos);
	WRITE_MICRO_CHUNK (csave, VARID_SHOOT_GROUND_POS,					ShootGroundPos);
	WRITE_MICRO_CHUNK_WWSTRING (csave, VARID_ATTACKING_BONE_NAME,	AttackingBoneName);	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Load_Variables
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Load_Variables (ChunkLoadClass &cload)
{
	RenderObjClass *old_camera_bone_ptr = NULL;
	Matrix3D cam_tm (1);

	while (cload.Open_Micro_Chunk ()) {
		switch (cload.Cur_Micro_Chunk_ID ()) {

			READ_MICRO_CHUNK (cload, VARID_CAMERA_BONE_PTR,						old_camera_bone_ptr);
			READ_MICRO_CHUNK (cload, VARID_CAMERA_BONE_TM,						cam_tm);

			READ_MICRO_CHUNK (cload, VARID_OVERALLSTATE_TIMER,					OverallStateTimer);
			READ_MICRO_CHUNK (cload, VARID_MENDOZASTATE_TIMER,					MendozaStateTimer);
			READ_MICRO_CHUNK (cload, VARID_CAMERASTATE_TIMER,					CameraStateTimer);
			READ_MICRO_CHUNK (cload, VARID_CAMERASHAKE_TIMER,					CameraShakeTimer);
			READ_MICRO_CHUNK (cload, VARID_ATTACKSTATE_TIMER,					AttackStateTimer);
			READ_MICRO_CHUNK (cload, VARID_RANDOMTARGET_TIMER,					RandomTargetTimer);
			READ_MICRO_CHUNK (cload, VARID_SYDNEYSTATE_TIMER,					SydneyStateTimer);
			READ_MICRO_CHUNK (cload, VARID_MOVESTATE_TIMER,						MoveStateTimer);
			READ_MICRO_CHUNK (cload, VARID_NEXT_MELEE_ATTACK_TIME,			NextMeleeAttackTime);
			READ_MICRO_CHUNK (cload, VARID_FIREBALL_START_TIMER,				FireballStartTimer);
			READ_MICRO_CHUNK (cload, VARID_NEXT_KNOCKDOWN_AVAILABLE_TIME,	NextKnockdownAvailableTime);
			READ_MICRO_CHUNK (cload, VARID_HAS_MELEE_ATTACK_HIT,				HasMeleeAttackHit);
			READ_MICRO_CHUNK (cload, VARID_LAST_MELEE_ANIM_FRAME,				LastMeleeAnimFrame);
			READ_MICRO_CHUNK (cload, VARID_START_TIMER,							StartTimer);
			READ_MICRO_CHUNK (cload, VARID_SIDE_KICK_POS,						SideKickPos);
			READ_MICRO_CHUNK (cload, VARID_SHOOT_GROUND_POS,					ShootGroundPos);
			READ_MICRO_CHUNK_WWSTRING (cload, VARID_ATTACKING_BONE_NAME,	AttackingBoneName);	

			default:
				Debug_Say (("Unrecognized MendozaBossGameObjClass Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID ()));
				break;
		}

		cload.Close_Micro_Chunk ();
	}

	//
	//	Register the camera bone pointers...
	//
	if (old_camera_bone_ptr != NULL) {			
		SaveLoadSystemClass::Register_Pointer (old_camera_bone_ptr, CameraBoneModel);
		CameraBoneModel->Set_Transform (cam_tm);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Apply_Control
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Apply_Control (void)
{
	SoldierGameObj::Apply_Control ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Think (void)
{	
	WWPROFILE ("Mendoza Think");	

	bool ok_to_think = true;

//
//	Don't do this in the editor
//
#ifdef PARAM_EDITING_ON
	ok_to_think = false;
#endif
	
	if (COMBAT_STAR == NULL || Sydney == NULL) {
		ok_to_think = false;
	}

	if (ok_to_think) {

		//
		//	Get the position of both Mendoza and the star (this information
		// is used throughout the AI)
		//
		Get_Position (&MendozaPos);
		COMBAT_STAR->Get_Position (&StarPos);

		//
		//	Check to see if its OK to kick off the boss logic
		//
		if (StartTimer > UNINITIALIZED_TIMER) {
			StartTimer -= TimeManager::Get_Frame_Seconds ();
			if (StartTimer <= 0) {
				Spawn_Health_Powerups ();
				StartTimer = UNINITIALIZED_TIMER;
				OverallState.Set_State (OVERALL_STATE_FLYING_SIDEKICK);
			}
		} else {

			//
			//	Decrement the "global" timer that determines when its OK
			// for Mendoza to fall down due to a frontal hit
			//
			NextKnockdownAvailableTime -= TimeManager::Get_Frame_Seconds ();

			//
			//	Let the state machines think
			//
			OverallState.Think ();
			MendozaState.Think ();
			MoveState.Think ();
			HeadState.Think ();
			CameraState.Think ();
			AttackState.Think ();
			SydneyState.Think ();
		}	
	}

	//
	//	Give Mendoza 100 extra health points so he doesn't get "killed" due to any
	// "special" damage such as fire or electricity
	//
	float old_health		= DefenseObject.Get_Health ();
	float old_health_max	= DefenseObject.Get_Health_Max ();
	old_health			+= 100.0F;
	old_health_max		+= 100.0F;
	DefenseObject.Set_Health_Max (old_health_max);
	DefenseObject.Set_Health (old_health);	

	//
	//	Let the soldier think
	//
	SoldierGameObj::Think ();

	//
	//	Restore his health
	//
	float curr_health = DefenseObject.Get_Health ();
	curr_health		-= 100.0F;
	old_health_max	-= 100.0F;
	DefenseObject.Set_Health (max (curr_health, 1.0F));
	DefenseObject.Set_Health_Max (old_health_max);	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Shuffle_Taunt_List
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Shuffle_Taunt_List (void)
{
	::memset (TauntList, 0, sizeof (TauntList));
	
	//
	//	Grab an entry from the taunt id list
	//
	for (int index = 0; index < MAX_TAUNTS; index ++) {

		//
		//	Choose a random list entry to plug this taunt ID into
		//
		int list_index = 0;
		do
		{
			list_index = FreeRandom.Get_Int (MAX_TAUNTS);
		} while (TauntList[list_index] != 0);

		//
		//	Stick this taunt ID into the list
		//
		TauntList[list_index] = index + 1;
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Apply_Damage_Extended
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Apply_Damage_Extended
(
	const OffenseObjectClass &		damager,
	float									scale,
	const Vector3 &					direction,
	const char *						collision_box_name
)
{
	if (	!CombatManager::I_Am_Server () ||
			OverallState.Get_State () == OVERALL_STATE_DEATH_SEQUENCE)
	{
		return ;
	}

	//
	//	Give Mendoza 100 extra health points so he doesn't get "killed"
	//
	float old_health		= DefenseObject.Get_Health ();

	//
	//	Apply the damage
	//
	DefenseObject.Set_Can_Object_Die (false);
	SoldierGameObj::Apply_Damage_Extended (damager, scale, direction, collision_box_name);

	//
	//	Readjust the current and old health
	//
	float curr_health	= DefenseObject.Get_Health ();

	//
	//	If Sydney is cowering in front of Mendoza then we should trigger
	// the end sequence soon...
	//
	if (SydneyState.Get_State () == SYDNEY_STATE_COWERING) {
		if (FreeRandom.Get_Int (4) == 1) {
			OverallState.Set_State (OVERALL_STATE_DEATH_SEQUENCE);
		}
	} else {

		//
		//	Calculate what our health percents were both before and after this damage
		//
		float old_health_percent	= old_health / DefenseObject.Get_Health_Max ();
		float health_percent			= curr_health / DefenseObject.Get_Health_Max ();
		
		//
		//	At 25% health we trigger the "chase after Sydney" event which has different behavior
		//
		if (health_percent > 0.25F) {

			//
			//	Were we shot in the front? (If so we may want to trigger our fall down event)
			//
			if (	health_percent > 0.3F &&
					NextKnockdownAvailableTime <= 0 &&
					OverallState.Get_State () >= OVERALL_STATE_MELEE_ATTACK)
			{
				Vector3 relative_direction = Get_Transform ().Inverse_Rotate_Vector (direction);
				relative_direction.Normalize ();
				if (relative_direction.X < -0.7F && (FreeRandom.Get_Int (5) == 1)) {
					MendozaState.Set_State (MENDOZA_STATE_FALLING);
				}
				NextKnockdownAvailableTime = FALLDOWN_TIMER;
			}

			//
			//	If Mendoza's health crosses the 75% mark, then switch to a ranged attack
			//
			if (old_health_percent > 0.75F && health_percent <= 0.75F) {
				OverallState.Set_State (OVERALL_STATE_RANGED_ATTACK);
			}

		} else {

			//
			//	Did we just change over to this state?
			//
			if (old_health_percent > 0.25F) {
				OverallState.Set_State (OVERALL_STATE_SYDNEY_BOLTS);
			}			
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_STANDING_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_STANDING_Begin (void)
{
	MendozaStateTimer = 0;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_STANDING_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_STANDING_Think (void)
{
	if (COMBAT_STAR == NULL) {
		return ;
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_FALLING_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_FALLING_Begin (void)
{
	Set_Animation ("S_A_HUMAN.H_A_635A", false);
	AttackState.Halt_State ();
	MoveState.Halt_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_FALLING_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_FALLING_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		MendozaState.Set_State (MENDOZA_STATE_KIPPING, true);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_FALLING_Request_End
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::On_MENDOZA_STATE_FALLING_Request_End (int /*new_state*/)
{
	return false;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_KIPPING_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_KIPPING_Begin (void)
{
	Set_Blended_Animation ("S_A_HUMAN.H_A_H12C", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);
	((HumanAnimControlClass *)Get_Anim_Control ())->Set_Anim_Speed_Scale (2.0F);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MENDOZA_STATE_KIPPING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MENDOZA_STATE_KIPPING) (void)
{
	//
	//	Resume the state's we halted
	//	
	MoveState.Resume_State ();
	AttackState.Set_State (ATTACK_STATE_HANDGUN);
	AttackState.Resume_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_KIPPING_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_KIPPING_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		MendozaState.Set_State (MENDOZA_STATE_STANDING, true);
		HumanState.Set_State (HumanStateClass::ANIMATION);
		((HumanAnimControlClass *)Get_Anim_Control ())->Set_Anim_Speed_Scale (1.0F);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_KIPPING_Request_End
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::On_MENDOZA_STATE_KIPPING_Request_End (int /*new_state*/)
{
	return false;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_PACK_EXPLODING_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_PACK_EXPLODING_Begin (void)
{
	//
	//	Create the explosion aggregate to attach to Mendoza
	//
	RenderObjClass *die_aggregate = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("AG_MENDOZA_DIE");	
	if (die_aggregate != NULL) {
		
		//
		//	Play the animation on the object
		//
		HAnimClass *anim = WW3DAssetManager::Get_Instance ()->Get_HAnim ("AG_MENDOZA_DIE.AG_MENDOZA_DIE");
		if (anim != NULL) {
			die_aggregate->Set_Animation (anim, 0, RenderObjClass::ANIM_MODE_ONCE);
			REF_PTR_RELEASE (anim);
		}
		
		//
		//	Attach the object to the back of Mendoza
		//		
		Peek_Model ()->Add_Sub_Object_To_Bone (die_aggregate, "BACKGUNBONE");
		REF_PTR_RELEASE (die_aggregate);
	}

	//
	//	Snap Sydney to the right position
	//
	SydneyState.Set_State (SYDNEY_STATE_STRIKE_A_POSE);

	//
	//	Stay in this state for 8 more seconds
	//
	MendozaStateTimer		= 8.0F;
	CameraShakeTimer		= 8.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_REQUEST_END(MENDOZA_STATE_PACK_EXPLODING)
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::STATE_IMPL_REQUEST_END(MENDOZA_STATE_PACK_EXPLODING) (int state)
{
	return false;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_PACK_EXPLODING_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_PACK_EXPLODING_Think (void)
{
	float old_timer = MendozaStateTimer;

	CameraShakeTimer -= TimeManager::Get_Frame_Real_Seconds ();
	if (CameraShakeTimer <= 0 && CameraShakeTimer > UNINITIALIZED_TIMER) {

		COMBAT_SCENE->Add_Camera_Shake (MendozaPos, 50.0, 1.0F, 0.25F);
		
		CameraShakeTimer = UNINITIALIZED_TIMER;
	}

	MendozaStateTimer -= TimeManager::Get_Frame_Real_Seconds ();	
	if (MendozaStateTimer <= 0) {

		//
		//	Kick into the dying state
		//
		MendozaState.Set_State (MENDOZA_STATE_DYING, true);
	} else if (old_timer >= 7.5F && MendozaStateTimer < 7.5F) {

		//
		//	Force Mendoza to be on fire
		//
		Set_Special_Damage_Mode (ArmorWarheadManager::SPECIAL_DAMAGE_TYPE_SUPER_FIRE);
		SpecialDamageTimer = 100.0F;		
		Set_Blended_Animation ("S_A_HUMAN.H_A_FLMA", true);

		//
		//	Play the on-fire sound
		//
		Attach_Fire_Sound ();
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_DYING_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_DYING_Begin (void)
{
	//
	//	Start the falling to your knees animation
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_FLMB", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);

	//
	//	Look at the dying Mendoza for a few seconds
	//
	MendozaStateTimer = 7.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_DYING_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_DYING_Think (void)
{
	MendozaStateTimer -= TimeManager::Get_Frame_Real_Seconds ();
	if (MendozaStateTimer <= 0) {

		//
		//	Set the dead state
		//
		MendozaState.Set_State (MENDOZA_STATE_DEAD);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_DEAD_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_DEAD_Begin (void)
{
	//
	//	Give the user 15 seconds before the level ends
	//
	MendozaStateTimer = 10.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_MENDOZA_STATE_DEAD_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_MENDOZA_STATE_DEAD_Think (void)
{
	MendozaStateTimer -= TimeManager::Get_Frame_Real_Seconds ();
	if (MendozaStateTimer <= 0) {
		
		//
		//	For right now, just restore everything so we can do it again...
		//
		MendozaState.Set_State (MENDOZA_STATE_STANDING);
		Set_Special_Damage_Mode (ArmorWarheadManager::SPECIAL_DAMAGE_TYPE_NONE);
		HumanState.Set_State (HumanStateClass::ANIMATION);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_NORMAL_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_NORMAL_Begin (void)
{
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_FACE_ZOOM_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_FACE_ZOOM_Begin (void)
{
	//
	//	Attach the camera to a dummy object we can move around
	//	
	CameraBoneModel->Set_Transform (COMBAT_CAMERA->Get_Transform ());
	COMBAT_CAMERA->Set_Host_Model (CameraBoneModel);

	//
	//	Slow time down...
	//
	TimeManager::Set_Time_Scale (0.25F);
	GameObjManager::Activate_Cinematic_Freeze (false);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_FACE_ZOOM_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_FACE_ZOOM_Think (void)
{
	//
	//	Determine the current and destination points
	//
	Vector3 curr_pos = CameraBoneModel->Get_Transform ().Get_Translation ();
	Vector3 dest_pos = Peek_Model ()->Get_Bone_Transform ("C HEAD").Get_Translation ();
	dest_pos += Vector3 (0, 0, 0.125F);

	//
	//	Get the vector from our current position to our destination
	//
	Vector3 vector = dest_pos - curr_pos;
	if (vector.Length () < 5.0F && MendozaState.Get_State () != MENDOZA_STATE_PACK_EXPLODING) {
		MendozaState.Set_State (MENDOZA_STATE_PACK_EXPLODING, true);
	} else if (vector.Length () < 1.15F) {

		//
		//	Snap Mendoza to the right position
		//
		Matrix3D new_tm (MENDOZA_END_POS);
		new_tm.Rotate_Z (DEG_TO_RADF (270.0F));
		Set_Transform (new_tm);
		
		//
		//	Detonate the backpack and start following the waypath
		//		
		CameraState.Set_State (CAMERA_STATE_WAYPATH_FOLLOW, true);
	} else {
		
		//
		//	Move closer to the target
		//
		vector.Normalize ();
		float time = TimeManager::Get_Frame_Real_Seconds () * 8.0F;
		Vector3 new_pos = curr_pos + (vector * time);

		//
		//	Look at the target
		//
		Matrix3D new_tm;
		new_tm.Look_At (new_pos, dest_pos, 0);

		//
		//	Update the camera's position and orientation
		//
		CameraBoneModel->Set_Transform (new_tm);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_WAYPATH_FOLLOW_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_WAYPATH_FOLLOW_Begin (void)
{
	//
	//	Restore time
	//
	TimeManager::Set_Time_Scale (1.0F);		

	//
	//	Reset the spline
	//
	CameraSpline.Clear_Keys ();

	//
	//	Get the waypath we're going to follow
	//
	WaypathClass *waypath = PathfindClass::Get_Instance ()->Find_Waypath (3000100);
	WWASSERT (waypath != NULL);

	//
	//	Add the points from the waypath to the spline
	//
	float percent = 0.0F;
	float percent_inc = 1.0F / waypath->Get_Point_Count ();
	for (int index = 0; index < waypath->Get_Point_Count (); index ++) {
		
		//
		//	Add this point to the spline
		//
		WaypointClass *waypoint = waypath->Get_Point (index);
		WWASSERT (waypoint != NULL);
		CameraSpline.Add_Key (waypoint->Get_Position (), percent);
		
		//
		//	Increment the percent
		//
		percent += percent_inc;
	}

	//
	//	Let the camera follow the path for 8 seconds
	//
	CameraStateTimer = 8.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_WAYPATH_FOLLOW_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_WAYPATH_FOLLOW_Think (void)
{
	//
	//	Evaluate the spline at the current "time"
	//
	float percent = 1.0F - WWMath::Clamp (CameraStateTimer / 8.0F, 0.0F, 1.0F);
	Vector3 camera_position;
	CameraSpline.Evaluate (percent, &camera_position);

	float camera_twist = 0.0F;
	if (percent > 0.77F) {
		camera_twist = ((percent - 0.77F) / 0.33F) * DEG_TO_RADF (-30.0F);
	}

	Vector3 dest_pos = Peek_Model ()->Get_Bone_Transform ("C HEAD").Get_Translation ();

	if (percent < 0.22F) {
		dest_pos += Get_Transform ().Rotate_Vector (Vector3 (2.0F, 0, 0));
	} else if (percent >= 0.22F && percent < 0.55F) {
		float dist = 2.0F * (1.0F - ((percent - 0.22F) / 0.33F));
		dest_pos += Get_Transform ().Rotate_Vector (Vector3 (dist, 0, 0));
	}

	//
	//	Move along the spline, looking at the character's head
	//	
	Matrix3D new_tm;
	new_tm.Look_At (camera_position, dest_pos, camera_twist);
	CameraBoneModel->Set_Transform (new_tm);
	
	//
	//	Kick out of this state when finished
	//
	CameraStateTimer -= TimeManager::Get_Frame_Real_Seconds ();
	if (CameraStateTimer <= 0) {
		CameraState.Set_State (CAMERA_STATE_LOOK_AT_DEAD_BOSS, true);
	}
		
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Begin (void)
{
	//
	//	Look at Mendoza for a few seconds
	//
	CameraStateTimer = 7.0F;
	TimeManager::Set_Time_Scale (0.5F);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_CAMERA_STATE_LOOK_AT_DEAD_BOSS_Think (void)
{
	//
	//	Kick out of this state when finished
	//
	CameraStateTimer -= TimeManager::Get_Frame_Real_Seconds ();
	if (CameraStateTimer <= 0) {
		CameraState.Set_State (CAMERA_STATE_NORMAL, true);

		//
		//	Restore the camera state
		//
		TimeManager::Set_Time_Scale (1.0F);
		COMBAT_CAMERA->Set_Host_Model (NULL);
		REF_PTR_RELEASE (CameraBoneModel);

		//
		//	Trigger mission success
		//
		CombatManager::Mission_Complete (true);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Attach_Sound
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Attach_Sound (const char *sound_name, const char *bone_name)
{
	//
	//	Create the sound object from its preset
	//
	AudibleSoundClass *sound = WWAudioClass::Get_Instance ()->Create_Sound (sound_name);
	if (sound != NULL) {

		//
		//	Attach the sound to the object
		//
		sound->Attach_To_Object (Peek_Model (), bone_name);

		//
		//	Add the sound to the world and release our hold on it
		//
		sound->Add_To_Scene ();
		REF_PTR_RELEASE (sound);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Attach_Fire_Sound
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Attach_Fire_Sound (void)
{
	//
	//	Create the sound object from its preset
	//
	AudibleSoundClass *sound = WWAudioClass::Get_Instance ()->Create_Sound ("SFX.Fire_Small_01");
	if (sound != NULL) {

		//
		//	Attach the sound to the object
		//
		sound->Attach_To_Object (Peek_Model ());

		//
		//	Add the sound to the world and release our hold on it
		//
		sound->Add_To_Scene ();
		REF_PTR_RELEASE (sound);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_NONE_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_NONE_Begin (void)
{	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_NONE_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_NONE_Think (void)
{
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_Begin (void)
{
	NextMeleeAttackTime = WWMath::Random_Float (0.125F, 0.7F);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_Think (void)
{
	//
	//	Is it time to attack the player again?
	//
	NextMeleeAttackTime -= TimeManager::Get_Frame_Seconds ();
	if (NextMeleeAttackTime <= 0) {

		//
		//	Is Mendoza close to the player?
		//
		float dist2 = (MendozaPos - StarPos).Length2 ();
		if (dist2 < 4.0F) {		
			
			//
			//	Pick random melee attack...
			//
			int attack_id = FreeRandom.Get_Int (3);
			if (attack_id == 0) {
				AttackState.Set_State (ATTACK_STATE_MELEE_CRESENT_KICK);
			} else if (attack_id == 1) {
				AttackState.Set_State (ATTACK_STATE_MELEE_SIDE_KICK);
			} else if (attack_id == 2) {
				AttackState.Set_State (ATTACK_STATE_MELEE_PUNCH);
			}
		}
	}


	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN) (void)
{
	//
	//	Kill the action
	//
	Get_Action ()->Reset (100);
	HasMeleeAttackHit		= false;
	LastMeleeAnimFrame	= 0;

	//
	//	Aim for the player
	//
	SideKickPos = StarPos;
	Set_Targeting (StarPos, false);

	//
	//	Play the run animation
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_A0A1", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);

	//
	//	Stop the animation at frame 4
	//
	Get_Anim_Control()->Set_Mode (ANIM_MODE_TARGET, 0);
	Get_Anim_Control()->Set_Target_Frame (4);

	Peek_Physical_Object ()->Enable_Objects_Simulation (false);	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN) (void)
{
	//
	//	Move onto the kick if the animation is complete
	//
	if (Get_Anim_Control ()->Is_Complete ()) {
		AttackState.Set_State (ATTACK_STATE_MELEE_FLYING_SIDEKICK);
	} else {

		//
		//	Get a direction vector between Mendoza and his destination
		//
		Vector3 dir_vector	= (SideKickPos - MendozaPos);
		dir_vector.Normalize ();

		const float SIDEKICK_RATE = 10.0F;

		//
		//	Fly through the air to our target
		//
		float rate = SIDEKICK_RATE * TimeManager::Get_Frame_Seconds ();
		Fly_Move (dir_vector * rate);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_MELEE_FLYING_SIDEKICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_MELEE_FLYING_SIDEKICK) (void)
{
	HasMeleeAttackHit		= false;
	LastMeleeAnimFrame	= 0;

	//
	//	Play the side kick animation
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_FLYKICK", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_MELEE_FLYING_SIDEKICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_MELEE_FLYING_SIDEKICK) (void)
{
	//
	//	Now, play the animation backwards a few frams to simulate "landing"
	//
	int curr_frame = Get_Anim_Control()->Get_Current_Frame ();
	Set_Blended_Animation ("S_A_HUMAN.H_A_FLYKICK", false);
	Get_Anim_Control()->Set_Mode (ANIM_MODE_TARGET, curr_frame);
	Get_Anim_Control()->Set_Target_Frame (0);

	//
	//	Release our lock on the human state
	//
	HumanState.Set_State (HumanStateClass::ANIMATION);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_MELEE_FLYING_SIDEKICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_MELEE_FLYING_SIDEKICK) (void)
{
	//
	//	Get a direction vector between Mendoza and his destination
	//
	Vector3 dir_vector	= (SideKickPos - MendozaPos);
	float dist2				= dir_vector.Length2 ();
	dir_vector.Normalize ();

	//
	//	Are we close to our goal?
	//
	bool is_finished = false;
	if (dist2 < 0.2F) {
		is_finished = true;
	} else {

		const float SIDEKICK_RATE = 10.0F;

		//
		//	Fly through the air to our target
		//
		float rate = SIDEKICK_RATE * TimeManager::Get_Frame_Seconds ();
		if (Fly_Move (dir_vector * rate)) {
			is_finished = true;
		}

		//
		//	Apply any damage done by the foot that's kicking...
		//
		if (HasMeleeAttackHit == false) {
			HasMeleeAttackHit = Apply_Bone_Collision_Damage ("C L FOOT");
		}
	}

	//
	//	If we're finished, then reset back to normal Melee state
	//
	if (is_finished) {
		Peek_Physical_Object ()->Enable_Objects_Simulation (true);	
		OverallState.Set_State (OVERALL_STATE_MELEE_ATTACK);	
	}

	//
	//	Cache the last frame number...
	//
	LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();	
	return ;
}






///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_CRESENT_KICK_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_CRESENT_KICK_Begin (void)
{
	//
	//	Kill the action
	//
	//Get_Action ()->Reset (100.0F);
	MoveState.Halt_State ();
	HasMeleeAttackHit		= false;
	LastMeleeAnimFrame	= 0;

	//
	//	Aim for the player
	//
	Set_Targeting (StarPos, false);

	//
	//	Play the kick backwards so it becomes a reverse-cresent kick (which
	// looks a lot better).
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_CRESENTKICK", false, 0, true);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);

	//
	//	Play the whoosh sound...
	//
	Attach_Sound ("Fight Whoosh Sound Twiddler", "ROOTTRANSFORM");
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_MELEE_CRESENT_KICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_MELEE_CRESENT_KICK) (void)
{
	//
	//	Release our lock on the human state
	//
	HumanState.Set_State (HumanStateClass::ANIMATION);
	MoveState.Resume_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_CRESENT_KICK_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_CRESENT_KICK_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		
		//
		//	Reset back to general melee state
		//
		HumanState.Set_State (HumanStateClass::ANIMATION);
		AttackState.Set_State (ATTACK_STATE_MELEE);
	} else if (Get_Anim_Control ()->Get_Current_Frame () < 7.0F) {
		
		//
		//	Apply any damage done by the foot that's kicking...
		//
		if (HasMeleeAttackHit == false) {
			HasMeleeAttackHit = Apply_Bone_Collision_Damage ("C R FOOT");
		}
	}

	//
	//	Cache the last frame number...
	//
	LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_SIDE_KICK_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_SIDE_KICK_Begin (void)
{
	//
	//	Kill the action
	//
	//Get_Action ()->Reset (100.0F);
	MoveState.Halt_State ();
	HasMeleeAttackHit = false;

	//
	//	Aim for the player
	//
	Set_Targeting (StarPos, false);

	//
	//	Do the kick!
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_SIDEKICK", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);

	//
	//	Play the whoosh sound...
	//
	Attach_Sound ("Fight Whoosh Sound Twiddler", "ROOTTRANSFORM");
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_MELEE_SIDE_KICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_MELEE_SIDE_KICK) (void)
{
	//
	//	Release our lock on the human state
	//
	HumanState.Set_State (HumanStateClass::ANIMATION);
	MoveState.Resume_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_SIDE_KICK_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_SIDE_KICK_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		
		//
		//	Now retract the kick...
		//		
		AttackState.Set_State (ATTACK_STATE_MELEE_SIDE_KICK_RETRACT);

	} else if (Get_Anim_Control ()->Get_Current_Frame () > 6.0F) {
		
		//
		//	Apply any damage done by the foot that's kicking...
		//
		if (HasMeleeAttackHit == false) {
			HasMeleeAttackHit =Apply_Bone_Collision_Damage ("C L FOOT");
		}
	}

	//
	//	Cache the last frame number...
	//
	LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_SIDE_KICK_RETRACT_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_SIDE_KICK_RETRACT_Begin (void)
{
	//
	//	Play the kick backwards... :>
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_SIDEKICK", false, 0, true);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_MELEE_SIDE_KICK_RETRACT)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_MELEE_SIDE_KICK_RETRACT) (void)
{
	//
	//	Release our lock on the human state
	//
	HumanState.Set_State (HumanStateClass::ANIMATION);
	MoveState.Resume_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_SIDE_KICK_RETRACT_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_SIDE_KICK_RETRACT_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		
		//
		//	Reset back to general melee state
		//
		HumanState.Set_State (HumanStateClass::ANIMATION);
		AttackState.Set_State (ATTACK_STATE_MELEE);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_PUNCH_Begin
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_PUNCH_Begin (void)
{
	//
	//	Kill the action
	//
	//Get_Action ()->Reset (100.0F);
	MoveState.Halt_State ();
	HasMeleeAttackHit		= false;
	LastMeleeAnimFrame	= 0;

	//
	//	Aim for the player
	//
	Set_Targeting (StarPos, false);

	//
	//	Play the punch animation
	//
	Set_Blended_Animation ("S_A_HUMAN.H_A_PunchCombo", false);
	HumanState.Set_State (HumanStateClass::LOCKED_ANIMATION);
	AttackingBoneName = "C R HAND";

	//
	//	Play the whoosh sound...
	//
	Attach_Sound ("Fight Whoosh Sound Twiddler", "ROOTTRANSFORM");
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_MELEE_PUNCH)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_MELEE_PUNCH) (void)
{
	//
	//	Release our lock on the human state
	//
	HumanState.Set_State (HumanStateClass::ANIMATION);
	MoveState.Resume_State ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	On_ATTACK_STATE_MELEE_PUNCH_Think
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::On_ATTACK_STATE_MELEE_PUNCH_Think (void)
{
	if (Get_Anim_Control ()->Is_Complete ()) {
		
		//
		//	Reset back to general melee state
		//		
		AttackState.Set_State (ATTACK_STATE_MELEE);

	} else {

		float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();

		//
		//	Handy macro
		//
		#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)

		//
		//	Determine what frame we've passed
		//
		bool is_new_attack = true;
		if (PASSED_FRAME (10.0F)) {
			AttackingBoneName = "C R HAND";
		} else if (PASSED_FRAME (13.0F)) {
			AttackingBoneName = "C R HAND";
		} else if (PASSED_FRAME (21.0F)) {
			AttackingBoneName = "C R HAND";
		} else if (PASSED_FRAME (30.0F)) {
			AttackingBoneName = "C L HAND";
		} else if (PASSED_FRAME (42.0F)) {
			AttackingBoneName = "C R HAND";
		} else {
			is_new_attack = false;
		}

		//
		//	Play the "whoosh" sound...  :)
		//
		if (is_new_attack) {
			HasMeleeAttackHit = false;
			Attach_Sound ("Fight Whoosh Sound Twiddler", "ROOTTRANSFORM");
		}

		if (curr_frame >= 13.0F && curr_frame < 45.0F) {

			//
			//	Apply any damage done by the foot that's kicking...
			//
			if (HasMeleeAttackHit == false) {
				HasMeleeAttackHit = Apply_Bone_Collision_Damage (AttackingBoneName);
			}
		}
	}

	//
	//	Cache the last frame number...
	//
	LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();	
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_FLAMETHROWER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_FLAMETHROWER) (void)
{
	//
	//	Switch to the flamethrower...
	//
	WeaponBag->Select_Weapon_ID (Get_Definition ().WeaponDefID);
	AttackStateTimer = 0.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_FLAMETHROWER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_FLAMETHROWER) (void)
{
	//
	//	Stop firing the flamethrower
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY, false);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_FLAMETHROWER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_FLAMETHROWER) (void)
{
	//
	//	Get the player's position relative to Mendoza
	//
	Vector3 relative_position;
	Matrix3D::Inverse_Transform_Vector (Get_Transform (), StarPos, &relative_position);

	bool turn_on_weapon = false;

	//
	//	Is the player within 10 meters of Mendoza?
	//
	if ((MendozaPos - StarPos).Length2 () < 100.0F) {
		
		//
		//	Is the player mostly in front of Mendoza?
		//
		if (relative_position.X > 0 && WWMath::Fabs (relative_position.Y) < 5.0F) {
			turn_on_weapon = true;
		}		
	}

	//
	//	Turn on or off the flamethrower
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY, turn_on_weapon);
	return ;
}





///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_FIREBALL)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_FIREBALL) (void)
{
	//
	//	Switch to the flamethrower...
	//
	WeaponBag->Select_Weapon_ID (Get_Definition ().WeaponDefID);
	AttackStateTimer	= WWMath::Random_Float (5.0F, 9.0F);
	RandomTargetTimer	= 0;
	ShootGroundPos		= StarPos;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_FIREBALL)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_FIREBALL) (void)
{
	//
	//	Stop firing the fireball launcher
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY,	false);
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY, false);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_FIREBALL)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_FIREBALL) (void)
{
	//
	//	Target somewhere around the star
	//
	RandomTargetTimer -= TimeManager::Get_Frame_Seconds ();
	if (RandomTargetTimer <= 0) {
		RandomTargetTimer = WWMath::Random_Float (0.25F, 0.6F);
		ShootGroundPos = StarPos;
		ShootGroundPos.X += WWMath::Random_Float (-1.0F, 1.0F);
		ShootGroundPos.Y += WWMath::Random_Float (-1.0F, 1.0F);
		ShootGroundPos.Z += WWMath::Random_Float (0.0F, 2.0F);
	}
	Set_Targeting (ShootGroundPos, true);

	//
	//	Determine if its safe for Mendoza to fire his Fireball launcher
	//
	bool is_safe_to_fire = false;
	Vector3 weapon_hit_pos;
	if (WeaponBag->Get_Weapon ()->Cast_Weapon_Down_Muzzle (weapon_hit_pos)) {
		float hit_distance = (MendozaPos - weapon_hit_pos).Length2 ();
		if (hit_distance > 8.0F) {
			is_safe_to_fire = true;
		}
	}

	//
	//	Get the player's position relative to Mendoza
	//
	Vector3 relative_position;
	Matrix3D::Inverse_Transform_Vector (Get_Transform (), StarPos, &relative_position);	

	//
	//	Is the player mostly in front of Mendoza?
	//
	bool turn_on_weapon = false;
	if ((relative_position.X > 0) && WWMath::Fabs (relative_position.Y) < 7.0F) {
		turn_on_weapon = true;
	}

	//
	//	Turn on or off the fireball launcher (or flamethrower)
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY,	turn_on_weapon && is_safe_to_fire);
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY,	turn_on_weapon && !is_safe_to_fire);

	//
	//	Check to see if we're finished with this state...
	//
	AttackStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (AttackStateTimer <= 0) {
		OverallState.Set_State (OVERALL_STATE_RANGED_ATTACK);
	}

	return ;
}





///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_HANDGUN)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_HANDGUN) (void)
{
	//
	//	Switch to the handgun...
	//
	WeaponBag->Select_Weapon_ID (Get_Definition ().SecondaryWeaponDefID);
	AttackStateTimer = 2.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_HANDGUN)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_HANDGUN) (void)
{
	//
	//	Stop firing the handgun
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY, false);
	WeaponBag->Deselect ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_HANDGUN)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_HANDGUN) (void)
{
	bool turn_on_weapon = false;

	//
	//	Get the player's position relative to Mendoza
	//
	Vector3 relative_position;
	Matrix3D::Inverse_Transform_Vector (Get_Transform (), StarPos, &relative_position);

	//
	//	Is the player in front of Mendoza?
	//	
	if (relative_position.X > 0) {
		turn_on_weapon = true;
	}

	//
	//	Turn on or off the handgun
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_PRIMARY, turn_on_weapon);

	//
	//	Switch back to the normal attack state if we're finished
	//
	AttackStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (AttackStateTimer <= 0) {

		//
		//	Determine which attack state to revert to
		//
		if (OverallState.Get_State () == OVERALL_STATE_MELEE_ATTACK) {
			AttackState.Set_State (ATTACK_STATE_MELEE);
		} else if (OverallState.Get_State () == OVERALL_STATE_RANGED_ATTACK) {
			AttackState.Set_State (ATTACK_STATE_FLAMETHROWER);
		} else if (OverallState.Get_State () == OVERALL_STATE_FIREBALL_ATTACK) {
			AttackState.Set_State (ATTACK_STATE_FIREBALL);
		}		
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(ATTACK_STATE_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(ATTACK_STATE_SYDNEY) (void)
{
	//
	//	Switch to the handgun...
	//
	WeaponBag->Select_Weapon_ID (Get_Definition ().WeaponDefID);

	//
	//	Set the timer so the first think call will cause the action...
	//
	AttackStateTimer = 0;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(ATTACK_STATE_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(ATTACK_STATE_SYDNEY) (void)
{
	//
	//	Stop firing...
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY, false);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(ATTACK_STATE_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(ATTACK_STATE_SYDNEY) (void)
{
	AttackStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (AttackStateTimer <= 0) {
		AttackStateTimer = WWMath::Random_Float (0.5F, 1.5F);

		//
		//	Get her position
		//
		Sydney.Get_Ptr ()->Get_Position (&ShootGroundPos);

		const float RADIUS = 2.0F;

		//
		//	Pick a random position in a circle around her feet
		//
		float angle = WWMath::Random_Float (DEG_TO_RADF (0.0F), DEG_TO_RADF (180.0F));
		ShootGroundPos.X += WWMath::Fast_Cos (angle) * RADIUS;
		ShootGroundPos.Y += WWMath::Fast_Sin (angle) * RADIUS;
	}

	//
	//	Target the ground at Sydney's feet
	//
	Set_Targeting (ShootGroundPos, true);

	//
	//	Fire the weapon...
	//
	Set_Boolean_Control (ControlClass::BOOLEAN_WEAPON_FIRE_SECONDARY, true);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Fly_Move
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::Fly_Move (const Vector3 &vector)
{
	//
	//	Get Mendoza's collision box
	//
	AABoxClass collision_box = Peek_Physical_Object ()->As_HumanPhysClass ()->Get_Collision_Box ();
	collision_box.Center += MendozaPos;
	
	//
	//	Check to see if we've hit something
	//
	CastResultStruct result;
	AABoxCollisionTestClass col_test (collision_box, vector, &result, COLLISION_TYPE_PHYSICAL);
	
	//
	//	Find where we hit
	//
	bool retval = COMBAT_STAR->Peek_Model ()->Cast_AABox (col_test);
	if (result.StartBad == false) {
		
		//
		//	Calculate where to move to...
		//
		Vector3 new_pos = MendozaPos + (vector * (result.Fraction * 0.99F));

		//
		//	Move Mendoza
		//
		Set_Position (new_pos);
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////////
//
//	Apply_Bone_Collision_Damage
//
///////////////////////////////////////////////////////////////////////////
bool
MendozaBossGameObjClass::Apply_Bone_Collision_Damage (const char *bone_name)
{
	int bone_index = Peek_Model ()->Get_Bone_Index (bone_name);

	//
	//	Lookup the current and last positions of the bone in question
	//
	Matrix3D last_bone_tm;
	Matrix3D curr_bone_tm;
	((Animatable3DObjClass *)Peek_Model ())->Simple_Evaluate_Bone (bone_index, &curr_bone_tm);
	((Animatable3DObjClass *)Peek_Model ())->Simple_Evaluate_Bone (bone_index, LastMeleeAnimFrame, &last_bone_tm);

	//
	//	Calculate where the bone moved
	//
	Vector3 move_vector = curr_bone_tm.Get_Translation () - last_bone_tm.Get_Translation ();

	//
	//	Build a box around the bone that we can use for collision detection
	//
	AABoxClass bone_box;
	bone_box.Center = curr_bone_tm.Get_Translation ();
	bone_box.Extent.Set (0.2F, 0.2F, 0.2F);

	//
	//	Try to find where (if anywhere) we hit the player
	//
	CastResultStruct result;
	result.ComputeContactPoint = true;
	AABoxCollisionTestClass col_test (bone_box, move_vector, &result, COLLISION_TYPE_PROJECTILE);
	
	//
	//	Find where we hit
	//
	bool retval = COMBAT_STAR->Peek_Model ()->Cast_AABox (col_test);
	if (retval) {

		//
		//	Dig the name of the mesh out
		//
		StringClass obj_name;
		if (col_test.CollidedRenderObj != NULL) {
			obj_name = col_test.CollidedRenderObj->Get_Name ();
		}
		
		//
		//	Apply 10 points of "steel" damage to the player
		//
		OffenseObjectClass offense_obj (5.0F, 1);
		COMBAT_STAR->Apply_Damage_Extended (offense_obj, 1.0F, Vector3 (-1, 0, 0), obj_name);

		//
		//	Knock the player back a little bit
		//
		Vector3 delta_vector = move_vector;
		delta_vector.Normalize ();
		COMBAT_STAR->Peek_Physical_Object ()->As_Phys3Class ()->Collide (delta_vector * 0.75F);		

		//
		//	Play the hit sound...
		//
		Attach_Sound ("Fight Impact Sound Twiddler", "ROOTTRANSFORM");
	}

	return retval;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_FLYING_SIDEKICK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_FLYING_SIDEKICK) (void)
{
	//
	//	Pull the strings to get the melee battle to begin
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	MoveState.Set_State (MOVE_STATE_STOP);
	AttackState.Set_State (ATTACK_STATE_MELEE_FLYING_SIDEKICK_RUN);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	SydneyState.Set_State (SYDNEY_STATE_WAITING);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_STAR);

	//
	//	Get rid of the weapon in his hands
	//
	WeaponBag->Deselect ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_MELEE_ATTACK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_MELEE_ATTACK) (void)
{
	//
	//	Pull the strings to get the melee battle to begin
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	MoveState.Set_State (MOVE_STATE_GET_CLOSE_TO_PLAYER);
	AttackState.Set_State (ATTACK_STATE_MELEE);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	SydneyState.Set_State (SYDNEY_STATE_WAITING);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_STAR);

	//
	//	Get rid of the weapon in his hands
	//
	WeaponBag->Deselect ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_RANGED_ATTACK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_RANGED_ATTACK) (void)
{
	//
	//	Pull the strings to get the ranged battle to begin
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	MoveState.Set_State (MOVE_STATE_ATTACK_PATTERN1);
	AttackState.Set_State (ATTACK_STATE_FLAMETHROWER);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_STAR);

	OverallStateTimer	= 0;

	//
	//	Reset the fireball launcher state timer as necessary.
	// We want to ensure this state happens from time to time,
	// however we don't want it happening all the time.
	//
	if (FireballStartTimer == 0) {
		FireballStartTimer = WWMath::Random_Float (6.0F, 12.0F);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_RANGED_ATTACK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_RANGED_ATTACK) (void)
{
	//
	//	Every half second check to see if Mendoza should try to find a powerup
	// to pickup...
	//
	OverallStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (OverallStateTimer <= 0) {
		OverallStateTimer = 0.5F;
		
		//
		//	Take a random roll of the dice to decide whether or not to try to pickup health...
		//
		float curr_health		= DefenseObject.Get_Health () / DefenseObject.Get_Health_Max ();
		int probability		= int(curr_health * 20.0F);
		if (FreeRandom.Get_Int (probability) == 1) {
			OverallState.Set_State (OVERALL_STATE_FIND_HEALTH);
		}

	} else {

		//
		//	Is it time to change to the "fireball" attack?
		//
		FireballStartTimer -= TimeManager::Get_Frame_Seconds ();
		if (FireballStartTimer <= 0) {
			FireballStartTimer = WWMath::Random_Float (6.0F, 12.0F);

			//
			//	Do the fireball attack
			//
			OverallState.Set_State (OVERALL_STATE_FIREBALL_ATTACK);
		}		
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_FIREBALL_ATTACK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_FIREBALL_ATTACK) (void)
{
	//
	//	Pull the strings to get the ranged battle to begin
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	MoveState.Set_State (MOVE_STATE_GOTO_HELIPAD);
	AttackState.Set_State (ATTACK_STATE_NONE);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_STAR);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_FIREBALL_ATTACK)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_FIREBALL_ATTACK) (void)
{
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_FIND_HEALTH)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_FIND_HEALTH) (void)
{
	//
	//	Reset the states
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	AttackState.Set_State (ATTACK_STATE_NONE);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	MoveState.Set_State (MOVE_STATE_RUN_TO_HEALTH, true);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_STAR);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_FIND_HEALTH)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_FIND_HEALTH) (void)
{
	//
	//	Return to attacking the star if we've found our health
	//
	if (Get_Action ()->Is_Active () == false) {
		OverallState.Set_State (OVERALL_STATE_RANGED_ATTACK);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_SYDNEY_BOLTS)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_SYDNEY_BOLTS) (void)
{
	OverallStateTimer = 3.0F;

	//
	//	Stand still and look at Sydney
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	AttackState.Set_State (ATTACK_STATE_NONE);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	MoveState.Set_State (MOVE_STATE_STOP);
	SydneyState.Set_State (SYDNEY_STATE_BOLTING);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_SYDNEY);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_SYDNEY_BOLTS)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_SYDNEY_BOLTS) (void)
{
	OverallStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (OverallStateTimer <= 0) {

		//
		//	Start chasing Sydney
		//
		OverallState.Set_State (OVERALL_STATE_RUN_AFTER_SYDNEY);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_RUN_AFTER_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_RUN_AFTER_SYDNEY) (void)
{
	//
	//	Start chasing Sydney
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	AttackState.Set_State (ATTACK_STATE_NONE);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	MoveState.Set_State (MOVE_STATE_CHASE_SYDNEY);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_SYDNEY);

	//
	//	Clue the player in that they need to assist Sydney
	//
	HUDInfo::Set_HUD_Help_Text (TRANSLATE (IDS_MENDOZA_BOSS_HELP_SYDNEY), Vector3 (1.0F, 0.0F, 0.0F));
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_RUN_AFTER_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_RUN_AFTER_SYDNEY) (void)
{
	//
	//	If Mendoza is within 2 meters of his goal, then switch to his "toying" state...
	//
	float dist = (MendozaPos - MENDOZA_END_POS).Length ();
	if (dist < 2.0F) {
		OverallState.Set_State (OVERALL_STATE_TOY_WITH_SYDNEY);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_TOY_WITH_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_TOY_WITH_SYDNEY) (void)
{
	//
	//	Stand still so we can take pot-shots at Sydney
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING);
	AttackState.Set_State (ATTACK_STATE_SYDNEY);
	CameraState.Set_State (CAMERA_STATE_NORMAL);
	//MoveState.Set_State (MOVE_STATE_STOP);
	HeadState.Set_State (HEAD_STATE_LOOKING_AT_SYDNEY);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(OVERALL_STATE_TOY_WITH_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_TOY_WITH_SYDNEY) (void)
{
	if (MoveState.Get_State () != MOVE_STATE_STOP) {
		
		//
		//	If Mendoza has gotten close enough to his goal, then make him stop...
		//
		float dist = (MendozaPos - MENDOZA_END_POS).Length ();
		if (dist < 1.0F) {
			MoveState.Set_State (MOVE_STATE_STOP);
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(OVERALL_STATE_DEATH_SEQUENCE)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_DEATH_SEQUENCE) (void)
{
	//
	//	Set the defense object to "blamo" so the game object won't die prematurely...
	//
	DefenseObject.Set_Skin ((ArmorType)1);
	DefenseObject.Set_Shield_Type ((ArmorType)1);

	//
	//	Force the states necessary for the death sequence
	//
	MendozaState.Set_State (MENDOZA_STATE_STANDING,		true);
	AttackState.Set_State (ATTACK_STATE_NONE,				true);
	CameraState.Set_State (CAMERA_STATE_FACE_ZOOM,		true);
	MoveState.Set_State (MOVE_STATE_STOP,					true);
	HeadState.Set_State (HEAD_STATE_NONE,					true);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_WAITING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_WAITING) (void)
{
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_BOLTING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_BOLTING) (void)
{
	//
	//	Make Sydney bolt to her "end" position
	//
	ActionParamsStruct params;
	params.Set_Basic ((long)0, 100, 777);
	params.Set_Movement (SYDNEY_END_POS, 1.0F, 0.5F);
	Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ()->Get_Action ()->Goto (params);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(SYDNEY_STATE_BOLTING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(SYDNEY_STATE_BOLTING) (void)
{
	Vector3 syd_pos;
	Sydney.Get_Ptr ()->Get_Position (&syd_pos);

	//
	//	Determine how far away Sydney is from her goal...
	//
	float dist = (SYDNEY_END_POS - syd_pos).Length ();

	//
	//	If Sydney is within a few meters of her goal, then make her trip.  :)
	//
	if (dist <= 5.0F) {
		SydneyState.Set_State (SYDNEY_STATE_TRIPPING);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_TRIPPING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_TRIPPING) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	Play the animation of Sydney tripping
	//
	sydney->Set_Blended_Animation ("S_A_HUMAN.H_A_690A", false, 7.0F);
	sydney->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
	((HumanAnimControlClass *)sydney->Get_Anim_Control ())->Set_Anim_Speed_Scale (2.0F);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(SYDNEY_STATE_TRIPPING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(SYDNEY_STATE_TRIPPING) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	If Sydney finished tripping, and Mendoza is standing over her,
	//	then switch her to the cowering state
	//
	if (	sydney->Get_Anim_Control ()->Is_Complete () &&
			OverallState.Get_State () == OVERALL_STATE_TOY_WITH_SYDNEY)
	{
		SydneyState.Set_State (SYDNEY_STATE_GETTING_UP);
		sydney->Get_Human_State ()->Set_State (HumanStateClass::ANIMATION);
		((HumanAnimControlClass *)sydney->Get_Anim_Control ())->Set_Anim_Speed_Scale (1.0F);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_GETTING_UP)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_GETTING_UP) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	Play the animation of Sydney getting up
	//
	sydney->Set_Blended_Animation ("S_A_HUMAN.H_A_H11C", false);
	sydney->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(SYDNEY_STATE_GETTING_UP)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(SYDNEY_STATE_GETTING_UP) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	If Sydney finished getting up, then switch her to the cowering state
	//
	if (sydney->Get_Anim_Control ()->Is_Complete ()) {		
		sydney->Get_Human_State ()->Set_State (HumanStateClass::ANIMATION);
		SydneyState.Set_State (SYDNEY_STATE_COWERING);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_COWERING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_COWERING) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();
	sydney->Get_Action ()->Reset (100);

	//
	//	Play the "cowering" animation, but stop at frame 7
	//
	sydney->Set_Blended_Animation ("S_A_HUMAN.H_A_A0A0_L50", false);
	sydney->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);

	//
	//	Stop the animation at frame 7
	//
	sydney->Get_Anim_Control()->Set_Mode (ANIM_MODE_TARGET, 0);
	sydney->Get_Anim_Control()->Set_Target_Frame (7);

	SydneyStateTimer = 1.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(SYDNEY_STATE_COWERING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(SYDNEY_STATE_COWERING) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	Release our lock on the animation state
	//
	sydney->Get_Human_State ()->Set_State (HumanStateClass::ANIMATION);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(SYDNEY_STATE_COWERING)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(SYDNEY_STATE_COWERING) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	Make Sydney face Mendoza
	//
	sydney->Set_Targeting (MENDOZA_END_POS, false);

	//
	//	Loop a different part of her cowering animation as necessary...
	//
	SydneyStateTimer -= TimeManager::Get_Frame_Seconds ();
	if (SydneyStateTimer <= 0) {
		SydneyStateTimer = WWMath::Random_Float (1.0F, 2.0F);

		//
		//	Toggle the frame range so she keeps flinching
		//
		if (sydney->Get_Anim_Control()->Get_Target_Frame () == 7) {
			sydney->Get_Anim_Control()->Set_Target_Frame (12);
		} else {
			sydney->Get_Anim_Control()->Set_Target_Frame (7);
		}

		//
		//	Apply some damage to Sydney...
		//
		OffenseObjectClass off (2.0F, 1);
		sydney->Apply_Damage (off, 1.0F);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(SYDNEY_STATE_STRIKE_A_POSE)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(SYDNEY_STATE_STRIKE_A_POSE) (void)
{
	SoldierGameObj *sydney = Sydney.Get_Ptr ()->As_PhysicalGameObj ()->As_SoldierGameObj ();

	//
	//	Set the posed animation
	//
	sydney->Set_Animation ("S_B_HUMAN.H_B_A0A0_14", true);

	//
	//	Snap Sydney to the right position
	//
	Matrix3D syd_tm (SYDNEY_END_POS);
	syd_tm.Rotate_Z (DEG_TO_RADF (90.0F));
	sydney->Set_Transform (syd_tm);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_CHASE_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_CHASE_SYDNEY) (void)
{
	//
	//	Move to our "end" position which should make us look like we're
	// either chasing Sydney or cutting her off...
	//
	ActionParamsStruct params;
	params.Set_Basic ((long)0, 100, 777);
	params.Set_Movement (MENDOZA_END_POS, 0.75F, 0.5F);
	Get_Action ()->Goto (params);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_STOP)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_STOP) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_GET_CLOSE_TO_PLAYER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_GET_CLOSE_TO_PLAYER) (void)
{
	MoveStateTimer = 0.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MOVE_STATE_GET_CLOSE_TO_PLAYER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MOVE_STATE_GET_CLOSE_TO_PLAYER) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(MOVE_STATE_GET_CLOSE_TO_PLAYER)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_GET_CLOSE_TO_PLAYER) (void)
{
	//
	//	Is it time to track down the player again?
	//
	MoveStateTimer	-= TimeManager::Get_Frame_Seconds ();
	if (MoveStateTimer <= 0) {
		MoveStateTimer = 1.0F;

		//
		//	Track down the player (if possible)
		//
		if (COMBAT_STAR != NULL && (StarPos.X > -70.0F)) {
			ActionParamsStruct params;
			params.Set_Basic ((long)0, 100, 777);
			params.Set_Movement (COMBAT_STAR, 1.0F, 1.0F);
			params.MoveFollow		= true;
			Get_Action ()->Goto (params);
		} else if (COMBAT_STAR != NULL) {

			//
			//	If the player goes out of range, then switch to the fireball attack
			//
			OverallState.Set_State (OVERALL_STATE_FIREBALL_ATTACK);
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_ATTACK_PATTERN1)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_ATTACK_PATTERN1) (void)
{
	MoveStateTimer = 0.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MOVE_STATE_ATTACK_PATTERN1)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MOVE_STATE_ATTACK_PATTERN1) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(MOVE_STATE_ATTACK_PATTERN1)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_ATTACK_PATTERN1) (void)
{
	//
	//	Make sure we are always facing the player...
	//
	Vector3 target_pos = StarPos;
	target_pos.Z += 1.0F;
	Set_Targeting (target_pos, true);

	//
	//	Is it time to move somewhere else?
	//
	MoveStateTimer	-= TimeManager::Get_Frame_Seconds ();
	if (MoveStateTimer <= 0) {
		MoveStateTimer = WWMath::Random_Float (1.0F, 7.0F);

		if (StarPos.X > -70.0F) {
			
			//
			//	Simply find a random spot next to the player to move to...
			//
			Vector3 position;
			if (PathfindClass::Get_Instance ()->Find_Random_Spot (StarPos, 10.0F, &position)) {

				float speed = WWMath::Random_Float (0.25, 1.0F);

				//
				//	Move to this random spot, but use a random speed as well
				//
				ActionParamsStruct params;
				params.Set_Basic ((long)0, 100, 777);
				params.Set_Movement (position, speed, 1.0F);
				params.IgnoreFacing = true;
				Get_Action ()->Goto (params);			
			}
		} else {
			
			//
			//	If the player goes out of range, then switch to the fireball attack
			//
			OverallState.Set_State (OVERALL_STATE_FIREBALL_ATTACK);
		}
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_ATTACK_PATTERN2)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_ATTACK_PATTERN2) (void)
{
	MoveStateTimer = 0.0F;
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MOVE_STATE_ATTACK_PATTERN2)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MOVE_STATE_ATTACK_PATTERN2) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(MOVE_STATE_ATTACK_PATTERN2)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_ATTACK_PATTERN2) (void)
{
	//
	//	Is it time to move somewhere else?
	//
	MoveStateTimer	-= TimeManager::Get_Frame_Seconds ();
	if (MoveStateTimer <= 0) {
		MoveStateTimer = WWMath::Random_Float (1.0F, 5.0F);

		if (StarPos.X > -70.0F) {

			//
			//	Simply find a random spot to move to...
			//
			Vector3 position;
			if (PathfindClass::Get_Instance ()->Find_Random_Spot (StarPos, 10.0F, &position)) {

				float speed = WWMath::Random_Float (0.25, 1.0F);

				//
				//	Move to this random spot, but use a random speed as well
				//
				ActionParamsStruct params;
				params.Set_Basic ((long)0, 100, 777);
				params.Set_Movement (position, speed, 1.0F);
				params.IgnoreFacing = true;
				Get_Action ()->Goto (params);
			}

		} else {
			
			//
			//	If the player goes out of range, then switch to the fireball attack
			//
			OverallState.Set_State (OVERALL_STATE_FIREBALL_ATTACK);
		}
	}

	return ;
}




///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_GOTO_HELIPAD)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_GOTO_HELIPAD) (void)
{
	//
	//	Move to the center of the helipad (with all haste)
	//
	ActionParamsStruct params;
	params.Set_Basic ((long)0, 100, 777);
	params.Set_Movement (HELIPAD_CENTER_POS, 1.0F, 0.5F);
	Get_Action ()->Goto (params);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MOVE_STATE_GOTO_HELIPAD)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MOVE_STATE_GOTO_HELIPAD) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(MOVE_STATE_GOTO_HELIPAD)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_GOTO_HELIPAD) (void)
{
	float dist2 = (MendozaPos - HELIPAD_CENTER_POS).Length2 ();

	//
	//	If we've gotten there, then start attacking...
	//
	if (dist2 <= 1.0F) {
		AttackState.Set_State (ATTACK_STATE_FIREBALL, true);
		MoveState.Set_State (MOVE_STATE_STOP);
	}

	return ;
}



///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(MOVE_STATE_RUN_TO_HEALTH)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_RUN_TO_HEALTH) (void)
{
	//
	//	First, find the "best" health powerup in the region...
	//
	PowerUpGameObj *powerup = Find_Best_Powerup ();
	if (powerup != NULL) {

		//
		//	Get the position of the powerup
		//
		Vector3 position;
		powerup->Get_Position (&position);

		//
		//	Now, move to the spot where the powerup is (at all haste)
		//
		ActionParamsStruct params;
		params.Set_Basic ((long)0, 100, 777);
		params.Set_Movement (position, 1.0F, 0.125F);
		Get_Action ()->Goto (params);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_END(MOVE_STATE_RUN_TO_HEALTH)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_END(MOVE_STATE_RUN_TO_HEALTH) (void)
{
	//
	//	Simply stop any action
	//
	Get_Action ()->Reset (100);
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Find_Best_Powerup
//
///////////////////////////////////////////////////////////////////////////
PowerUpGameObj *
MendozaBossGameObjClass::Find_Best_Powerup (void)
{
	if (COMBAT_STAR == NULL) {
		return NULL;
	}

	PowerUpGameObj *best_powerup	= NULL;
	float best_powerup_rating		= 100.0F;

	//
	//	Loop over all the game objects in the world (looking for powerups)
	//
	SLNode<BaseGameObj> *obj_node = NULL;
	for (obj_node = GameObjManager::Get_Game_Obj_List ()->Head (); obj_node; obj_node = obj_node->Next ()) {
		
		//
		//	Is this a powerup?
		//
		PhysicalGameObj *phys_game_obj = obj_node->Data ()->As_PhysicalGameObj ();
		if (phys_game_obj != NULL && phys_game_obj->As_PowerUpGameObj () != NULL) {
			PowerUpGameObj *powerup = phys_game_obj->As_PowerUpGameObj ();
			if (powerup != NULL) {

				//
				//	Get the position of the powerup
				//
				Vector3 powerup_pos;
				powerup->Get_Position (&powerup_pos);
				
				//
				//	Is this powerup in the boss area?
				//
				if (	BOSS_AREA_BOX01.Contains (powerup_pos) || 
						BOSS_AREA_BOX02.Contains (powerup_pos) || 
						BOSS_AREA_BOX03.Contains (powerup_pos))
				{
					powerup_pos.Z = 0;

					//
					//	Calculate how far this powerup is from Mendoza and the player
					//
					float dist_to_me		= (powerup_pos - MendozaPos).Length () / 10.0F;
					float dist_to_star	= (powerup_pos - StarPos).Length () / 10.0F;
					dist_to_star			= WWMath::Clamp (1.0F - dist_to_star, 0.0F, 1.0F);

					//
					//	Is this the powerup that's closest to Mendoza and farthest from the player?
					//
					float rating = (dist_to_me * 0.5F) + (dist_to_star * 0.5F);
					if (rating < best_powerup_rating) {
						best_powerup			= powerup;
						best_powerup_rating	= rating;
					}
				}
			}
		}
	}

	return best_powerup;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_BEGIN(HEAD_STATE_NONE)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_BEGIN(HEAD_STATE_NONE) (void)
{
	Cancel_Look_At ();
	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(HEAD_STATE_LOOKING_AT_STAR)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(HEAD_STATE_LOOKING_AT_STAR) (void)
{
	//
	//	Look at the star's head
	//
	Vector3 position (StarPos);
	position.Z += 1.7F;

	if (Is_Looking () == false) {
		Look_At (position, 100);
	} else {
		Update_Look_At (position);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	STATE_IMPL_THINK(HEAD_STATE_LOOKING_AT_SYDNEY)
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::STATE_IMPL_THINK(HEAD_STATE_LOOKING_AT_SYDNEY) (void)
{
	Vector3 syd_pos;
	Sydney.Get_Ptr ()->Get_Position (&syd_pos);

	//
	//	Look at the Sydney's head
	//
	syd_pos.Z += 1.7F;

	if (Is_Looking () == false) {
		Look_At (syd_pos, 100);
	} else {
		Update_Look_At (syd_pos);
	}

	return ;
}


///////////////////////////////////////////////////////////////////////////
//
//	Spawn_Health_Powerups
//
///////////////////////////////////////////////////////////////////////////
void
MendozaBossGameObjClass::Spawn_Health_Powerups (void)
{
	const int POWERUP_COUNT = 15;

	//
	//	Create some health powerups
	//
	for (int index = 0; index < POWERUP_COUNT; index ++) {

		//
		//	Pick a random part of the level to create the powerup in...
		//
		const AABoxClass *area_box = NULL;
		int area_id = FreeRandom.Get_Int (3);
		if (area_id == 0) {
			area_box = &BOSS_AREA_BOX01;
		} else if (area_id == 1) {
			area_box = &BOSS_AREA_BOX02;
		} else {
			area_box = &BOSS_AREA_BOX03;
		}

		//
		//	Pick a random spot in this area
		//
		Vector3 rand_pos;
		rand_pos.X = area_box->Center.X + WWMath::Random_Float (-area_box->Extent.X * 0.95F, area_box->Extent.X * 0.95F);
		rand_pos.Y = area_box->Center.Y + WWMath::Random_Float (-area_box->Extent.Y * 0.95F, area_box->Extent.Y * 0.95F);
		rand_pos.Z = area_box->Center.Z;

		//
		//	Ensure this is a valid spot to walk
		//
		if (PathfindClass::Get_Instance ()->Find_Random_Spot (rand_pos, 1.0F, &rand_pos)) {
			
			//
			//	Build a ray-test to determine at what height to position the powerup
			//
			rand_pos.Z			+= 10.0F;
			Vector3 delta		(0, 0, -20.0F);
			Vector3 end_pos	= rand_pos + delta;

			LineSegClass ray_cast (rand_pos, end_pos);
			CastResultStruct result;
			PhysRayCollisionTestClass ray_test (ray_cast, &result, TERRAIN_ONLY_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL);
			COMBAT_SCENE->Cast_Ray (ray_test);
			
			//
			//	Calculate the powerup's new position
			//
			Vector3 powerup_pos = rand_pos + (delta * (result.Fraction * 0.99F));
			
			//
			//	Create and position the object
			//
			PhysicalGameObj *powerup = ObjectLibraryManager::Create_Object ("POW_Health_025");
			if (powerup != NULL) {
				powerup->Start_Observers ();
				powerup->Set_Position (powerup_pos);
			}
		}
	}

	return ;
}

