4556 lines
119 KiB
C++
4556 lines
119 KiB
C++
|
/*
|
||
|
** 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/raveshawbossgameobj.cpp $*
|
||
|
* *
|
||
|
* Author:: Patrick Smith *
|
||
|
* *
|
||
|
* $Modtime:: 1/20/02 4:40p $*
|
||
|
* *
|
||
|
* $Revision:: 14 $*
|
||
|
* *
|
||
|
*---------------------------------------------------------------------------------------------*
|
||
|
* Functions: *
|
||
|
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
|
||
|
|
||
|
#include "raveshawbossgameobj.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"
|
||
|
#include "stealtheffect.h"
|
||
|
#include "damageablestaticphys.h"
|
||
|
#include "boxrobj.h"
|
||
|
|
||
|
|
||
|
DECLARE_FORCE_LINK (RaveshawBoss)
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// ManualTransitionEffectClass
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
class ManualTransitionEffectClass : public TransitionEffectClass
|
||
|
{
|
||
|
public:
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
// Public constructors/destructors
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
ManualTransitionEffectClass (void)
|
||
|
{
|
||
|
RenderBaseMaterial = true;
|
||
|
RenderTransitionMaterial = true;
|
||
|
IntensityScale = 0;
|
||
|
RemoveOnComplete = false;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
// Public methods
|
||
|
///////////////////////////////////////////////////////////////////
|
||
|
|
||
|
//
|
||
|
// Inherited
|
||
|
//
|
||
|
void Timestep (float dt)
|
||
|
{
|
||
|
//
|
||
|
// Stolen from base class
|
||
|
//
|
||
|
Vector2 uv_rate = MinUVRate + IntensityScale * IntensityScale * (MaxUVRate - MinUVRate);
|
||
|
UVOffset += uv_rate * dt;
|
||
|
UVOffset.X = fmod(UVOffset.X , 2.0f);
|
||
|
UVOffset.Y = fmod(UVOffset.Y , 2.0f);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Manual control
|
||
|
//
|
||
|
void Enable_Effect (bool onoff) { RenderTransitionMaterial = onoff; }
|
||
|
bool Is_Effect_Enabled (void) const { return RenderTransitionMaterial; }
|
||
|
|
||
|
void Set_Intensity (float value) { IntensityScale = value; }
|
||
|
float Get_Intensity (void) const { return IntensityScale; }
|
||
|
|
||
|
};
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Constants
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
static const float UNINITIALIZED_TIMER = -5000.0F;
|
||
|
|
||
|
static const Vector3 TIBERIUM_POS (-130.499F, 483.243F, -189.617F);
|
||
|
static const float TIBERIUM_RADIUS = 1.35F;
|
||
|
static const float SAFE_JUMP_RADIUS = 12.0F;
|
||
|
static const float CAMERA_RADIUS = 10.0F;
|
||
|
|
||
|
static const float HEAL_TIME = 3.0F;
|
||
|
static const float EFFECT_FADE_TIME = 12.0F;
|
||
|
static const float EFFECT_INTENSITY = 0.75F;
|
||
|
|
||
|
static const char *ARC_BONE_NAMES[6] =
|
||
|
{
|
||
|
"BONE02",
|
||
|
"BONE03",
|
||
|
"BONE04",
|
||
|
"BONE05",
|
||
|
"BONE06",
|
||
|
"BONE07",
|
||
|
};
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Waypath IDs
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
static const int CATWALK_WAYPATH_ID = 3000100;
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// 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_TIBERIUM_EFFECT,
|
||
|
CHUNKID_OVERALL_STATE_MACHINE,
|
||
|
CHUNKID_RAVESHAW_STATE_MACHINE,
|
||
|
CHUNKID_ENGORGED_STATE_MACHINE,
|
||
|
CHUNKID_MOVE_STATE_MACHINE,
|
||
|
CHUNKID_STEALTH_SOLDIER_STATE_MACHINE,
|
||
|
CHUNKID_THROWN_OBJ_STATE_MACHINE,
|
||
|
CHUNKID_JUMP_STATE_MACHINE,
|
||
|
CHUNKID_LIGHTNING_ROD_STATE_MACHINE,
|
||
|
CHUNKID_STEALTH_SOLDIER,
|
||
|
CHUNKID_HAVOC_STATE_MACHINE,
|
||
|
|
||
|
XXX_VARID_STEALTH_SOLIDER_PTR = 0,
|
||
|
VARID_THROWN_OBJECT_PTR,
|
||
|
VARID_IS_TIBERIUM_EFFECT_APPLIED,
|
||
|
VARID_CURRENT_DEST_POS,
|
||
|
VARID_OVERALL_STATE_TIMER,
|
||
|
VARID_ENGORGED_STATE_TIMER,
|
||
|
VARID_MOVE_STATE_TIMER,
|
||
|
VARID_BODY_SLAM_TIMER,
|
||
|
VARID_RAVESHAW_STATE_TIMER,
|
||
|
VARID_STEALTHSOLDIER_STATE_TIMER,
|
||
|
VARID_LIGHTNINGROD_STATE_TIMER,
|
||
|
VARID_START_TIMER,
|
||
|
VARID_LAST_MELEE_ANIM_FRAME,
|
||
|
VARID_HAS_MELEE_ATTACK_HIT,
|
||
|
VARID_FLYING_OBJECT_VECTOR,
|
||
|
VARID_FLYING_OBJECT_DEST,
|
||
|
VARID_FLYING_DIST,
|
||
|
VARID_RELOBJ_TM,
|
||
|
VARID_ARC_OBJ_PTR,
|
||
|
VARID_CURR_JUMP_POS,
|
||
|
VARID_CAMERA_BONE_PTR,
|
||
|
VARID_CAMERA_BONE_TM,
|
||
|
VARID_RESTORE_FIRST_PERSON,
|
||
|
};
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
// Factories
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
SimplePersistFactoryClass<RaveshawBossGameObjDefClass, CHUNKID_GAME_OBJECT_DEF_RAVESHAW_BOSS> _RaveshawBossGameObjDefPersistFactory;
|
||
|
SimplePersistFactoryClass<RaveshawBossGameObjClass, CHUNKID_GAME_OBJECT_RAVESHAW_BOSS> _RaveshawBossGameObjPersistFactory;
|
||
|
DECLARE_DEFINITION_FACTORY(RaveshawBossGameObjDefClass, CLASSID_GAME_OBJECT_DEF_RAVESHAW_BOSS, "Raveshaw Boss") _RaveshawBossGameObjDefDefFactory;
|
||
|
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// RaveshawBossGameObjDefClass
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
RaveshawBossGameObjDefClass::RaveshawBossGameObjDefClass (void)
|
||
|
{
|
||
|
UseInnateBehavior = false;
|
||
|
|
||
|
PARAM_SEPARATOR (RaveshawBossGameObjDefClass, "Boss Settings");
|
||
|
PARAM_SEPARATOR (RaveshawBossGameObjDefClass, "");
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ~RaveshawBossGameObjDefClass
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
RaveshawBossGameObjDefClass::~RaveshawBossGameObjDefClass (void)
|
||
|
{
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Class_ID
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
uint32
|
||
|
RaveshawBossGameObjDefClass::Get_Class_ID (void) const
|
||
|
{
|
||
|
return CLASSID_GAME_OBJECT_DEF_RAVESHAW_BOSS;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Create
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
PersistClass *
|
||
|
RaveshawBossGameObjDefClass::Create (void) const
|
||
|
{
|
||
|
RaveshawBossGameObjClass *obj = new RaveshawBossGameObjClass;
|
||
|
obj->Init(*this);
|
||
|
return obj;
|
||
|
}
|
||
|
|
||
|
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Save
|
||
|
//
|
||
|
//////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
RaveshawBossGameObjDefClass::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
|
||
|
RaveshawBossGameObjDefClass::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 RaveshawBossGameObjDefClass chunkID\n"));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cload.Close_Chunk ();
|
||
|
}
|
||
|
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Save_Variables
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjDefClass::Save_Variables (ChunkSaveClass &csave)
|
||
|
{
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Load_Variables
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjDefClass::Load_Variables (ChunkLoadClass &cload)
|
||
|
{
|
||
|
/*while (cload.Open_Micro_Chunk ()) {
|
||
|
switch (cload.Cur_Micro_Chunk_ID ()) {
|
||
|
|
||
|
default:
|
||
|
Debug_Say (("Unrecognized RaveshawBossGameObjDefClass Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID ()));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cload.Close_Micro_Chunk ();
|
||
|
}*/
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Factory
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
const PersistFactoryClass &
|
||
|
RaveshawBossGameObjDefClass::Get_Factory (void) const
|
||
|
{
|
||
|
return _RaveshawBossGameObjDefPersistFactory;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
**
|
||
|
** Start of RaveshawBossGameObjClass
|
||
|
**
|
||
|
*/
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// RaveshawBossGameObjClass
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
RaveshawBossGameObjClass::RaveshawBossGameObjClass (void) :
|
||
|
RaveshawTauntTimeLeft (0),
|
||
|
AvailableTaunts (0xFFFFFF),
|
||
|
OverallState (this),
|
||
|
RaveshawState (this),
|
||
|
EngorgedState (this),
|
||
|
MoveState (this),
|
||
|
StealthSoldierState (this),
|
||
|
HavocState (this),
|
||
|
ThrownObjectState (this),
|
||
|
JumpState (this),
|
||
|
LightningRodState (this),
|
||
|
OverallStateTimer (0),
|
||
|
StealthSoldierStateTimer (0),
|
||
|
LightningRodStateTimer (0),
|
||
|
RaveshawStateTimer (0),
|
||
|
EngorgedStateTimer (0),
|
||
|
MoveStateTimer (0),
|
||
|
BodySlamTimer (0),
|
||
|
TiberiumEffect (NULL),
|
||
|
IsTiberiumEffectApplied (false),
|
||
|
StealthSoldier (NULL),
|
||
|
StealthEffect (NULL),
|
||
|
ThrownObject (NULL),
|
||
|
RaveshawPos (0, 0, 0),
|
||
|
StarPos (0, 0, 0),
|
||
|
StartTimer (0),
|
||
|
FlyingDist (0),
|
||
|
FlyingObjectVector (0, 0, 0),
|
||
|
FlyingObjectDest (0, 0, 0),
|
||
|
LastMeleeAnimFrame (0),
|
||
|
HasMeleeAttackHit (false),
|
||
|
CameraBoneModel (NULL),
|
||
|
RestoreFirstPerson (true)
|
||
|
{
|
||
|
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;
|
||
|
|
||
|
::memset (ArcObjects, 0, sizeof (ArcObjects));
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
ArcLifeRemaining[index] = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Register the Overall states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_NOTHING);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_HEALING);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_THROWING_OBJECT);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_THROWING_SOLDIER);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_THROWING_STAR);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_GRAB_STAR);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_JUMP_TO_CATWALK);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_ON_CATWALK);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_BODYSLAM);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_CHASE_STAR);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_DAZED);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_FLEE);
|
||
|
ADD_STATE_TO_MACHINE (OverallState, OVERALL_STATE_DEATH_SEQUENCE);
|
||
|
|
||
|
//
|
||
|
// Register the Raveshaw states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_NOTHING);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_ROAR);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_GRAB_TIBERIUM);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_GRAB_SOLDIER);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_THROW_SOLDIER);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_GRAB_OBJECT);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_THROW_OBJECT);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_GRAB_STAR);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_BODYSLAM);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_JUMP_DOWN);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_STUMBLE);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_LOOK_CONFUSED);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_DYING);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_FALL);
|
||
|
ADD_STATE_TO_MACHINE (RaveshawState, RAVESHAW_STATE_DEATH_LANDING);
|
||
|
|
||
|
//
|
||
|
// Register the Move states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_STOP);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_GOTO_TIBERIUM);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_GOTO_CATWALK);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_JUMP_TO_CATWALK);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_CIRCLE_CATWALK);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_GOTO_THROW_OBJECT);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_JUMP_TO_STAR);
|
||
|
ADD_STATE_TO_MACHINE (MoveState, MOVE_STATE_FOLLOW_STAR);
|
||
|
|
||
|
//
|
||
|
// Register the Engorged states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (EngorgedState, ENGORGED_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (EngorgedState, ENGORGED_STATE_ABSORBING_TIBERIUM);
|
||
|
ADD_STATE_TO_MACHINE (EngorgedState, ENGORGED_STATE_FADING);
|
||
|
|
||
|
//
|
||
|
// Register the Jump states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (JumpState, JUMP_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (JumpState, JUMP_STATE_CROUCHING);
|
||
|
ADD_STATE_TO_MACHINE (JumpState, JUMP_STATE_JUMPING);
|
||
|
ADD_STATE_TO_MACHINE (JumpState, JUMP_STATE_LANDING);
|
||
|
JumpState.Set_State (JUMP_STATE_NONE);
|
||
|
|
||
|
//
|
||
|
// Register the Stealth Soldier states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (StealthSoldierState, STEALTH_SOLDIER_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (StealthSoldierState, STEALTH_SOLDIER_STATE_DISPLAY);
|
||
|
ADD_STATE_TO_MACHINE (StealthSoldierState, STEALTH_SOLDIER_STATE_FLYING);
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
|
||
|
//
|
||
|
// Register the Stealth Soldier states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (HavocState, HAVOC_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (HavocState, HAVOC_STATE_GRABBED);
|
||
|
ADD_STATE_TO_MACHINE (HavocState, HAVOC_STATE_FLYING);
|
||
|
HavocState.Set_State (HAVOC_STATE_NONE);
|
||
|
|
||
|
//
|
||
|
// Register the Thrown object states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (ThrownObjectState, THROWN_OBJECT_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (ThrownObjectState, THROWN_OBJECT_STATE_PICKUP);
|
||
|
ADD_STATE_TO_MACHINE (ThrownObjectState, THROWN_OBJECT_STATE_FLYING);
|
||
|
ThrownObjectState.Set_State (THROWN_OBJECT_STATE_NONE);
|
||
|
|
||
|
//
|
||
|
// Register the Lightning Rod states with its state machine
|
||
|
//
|
||
|
ADD_STATE_TO_MACHINE (LightningRodState, LIGHTNING_ROD_STATE_NONE);
|
||
|
ADD_STATE_TO_MACHINE (LightningRodState, LIGHTNING_ROD_STATE_ACTIVE);
|
||
|
LightningRodState.Set_State (LIGHTNING_ROD_STATE_NONE);
|
||
|
|
||
|
//
|
||
|
// Allocate a new stealth effect to use...
|
||
|
//
|
||
|
StealthEffect = NEW_REF (StealthEffectClass, ());
|
||
|
|
||
|
//
|
||
|
// Allocate a new tiberium effect to use...
|
||
|
//
|
||
|
TiberiumEffect = NEW_REF (ManualTransitionEffectClass, ());
|
||
|
TextureClass *texture = WW3DAssetManager::Get_Instance ()->Get_Texture ("bluetibeffect.tga");
|
||
|
TiberiumEffect->Set_Texture (texture);
|
||
|
REF_PTR_RELEASE (texture);
|
||
|
|
||
|
//
|
||
|
// Create the camera bone model...
|
||
|
//
|
||
|
CameraBoneModel = WW3DAssetManager::Get_Instance ()->Create_Render_Obj ("CAMBONE");
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// ~RaveshawBossGameObjClass
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
RaveshawBossGameObjClass::~RaveshawBossGameObjClass (void)
|
||
|
{
|
||
|
REF_PTR_RELEASE (TiberiumEffect);
|
||
|
REF_PTR_RELEASE (StealthEffect);
|
||
|
REF_PTR_RELEASE (CameraBoneModel);
|
||
|
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
ArcObjects[index] = NULL;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Factory
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
const PersistFactoryClass &
|
||
|
RaveshawBossGameObjClass::Get_Factory (void) const
|
||
|
{
|
||
|
return _RaveshawBossGameObjPersistFactory;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Init
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
void RaveshawBossGameObjClass::Init (void)
|
||
|
{
|
||
|
Init ( Get_Definition ());
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Init
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Init (const RaveshawBossGameObjDefClass &definition)
|
||
|
{
|
||
|
SoldierGameObj::Init (definition);
|
||
|
|
||
|
//
|
||
|
// Make Raveshaw big and beefy...
|
||
|
//
|
||
|
Peek_Model ()->Scale (1.5F);
|
||
|
|
||
|
//
|
||
|
// Make a list of the lightning rods in the area
|
||
|
//
|
||
|
Collect_Lightning_Rods ();
|
||
|
Create_Arc_Effects ();
|
||
|
Prepare_Arc_Effect_Data ();
|
||
|
|
||
|
//
|
||
|
// Start fresh...
|
||
|
//
|
||
|
Get_Action ()->Reset (100);
|
||
|
StartTimer = 2.0F;
|
||
|
|
||
|
//
|
||
|
// Determine which state to do...
|
||
|
//
|
||
|
Determine_New_Overall_State ();
|
||
|
Get_Human_State ()->Set_Human_Anim_Override ("Raveshaw Boss Override");
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Definition
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
const RaveshawBossGameObjDefClass &
|
||
|
RaveshawBossGameObjClass::Get_Definition (void) const
|
||
|
{
|
||
|
return (const RaveshawBossGameObjDefClass &)BaseGameObj::Get_Definition ();
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Save
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
RaveshawBossGameObjClass::Save (ChunkSaveClass & csave)
|
||
|
{
|
||
|
csave.Begin_Chunk (CHUNKID_PARENT);
|
||
|
SoldierGameObj::Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
//
|
||
|
// Save the tiberium effect to its own chunk
|
||
|
//
|
||
|
csave.Begin_Chunk (CHUNKID_STEALTH_SOLDIER);
|
||
|
StealthSoldier.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
//
|
||
|
// Save the tiberium effect to its own chunk
|
||
|
//
|
||
|
csave.Begin_Chunk (CHUNKID_TIBERIUM_EFFECT);
|
||
|
TiberiumEffect->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_RAVESHAW_STATE_MACHINE);
|
||
|
RaveshawState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_ENGORGED_STATE_MACHINE);
|
||
|
EngorgedState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_MOVE_STATE_MACHINE);
|
||
|
MoveState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_STEALTH_SOLDIER_STATE_MACHINE);
|
||
|
StealthSoldierState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_HAVOC_STATE_MACHINE);
|
||
|
HavocState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_THROWN_OBJ_STATE_MACHINE);
|
||
|
ThrownObjectState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_JUMP_STATE_MACHINE);
|
||
|
JumpState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
csave.Begin_Chunk (CHUNKID_LIGHTNING_ROD_STATE_MACHINE);
|
||
|
LightningRodState.Save (csave);
|
||
|
csave.End_Chunk ();
|
||
|
|
||
|
//
|
||
|
// Save the variables
|
||
|
//
|
||
|
csave.Begin_Chunk (CHUNKID_VARIABLES);
|
||
|
Save_Variables (csave);
|
||
|
csave.End_Chunk ();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Load
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
RaveshawBossGameObjClass::Load (ChunkLoadClass &cload)
|
||
|
{
|
||
|
while (cload.Open_Chunk ()) {
|
||
|
switch(cload.Cur_Chunk_ID ()) {
|
||
|
|
||
|
case CHUNKID_PARENT:
|
||
|
SoldierGameObj::Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_STEALTH_SOLDIER:
|
||
|
StealthSoldier.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_TIBERIUM_EFFECT:
|
||
|
TiberiumEffect->Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_OVERALL_STATE_MACHINE:
|
||
|
OverallState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_RAVESHAW_STATE_MACHINE:
|
||
|
RaveshawState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_ENGORGED_STATE_MACHINE:
|
||
|
EngorgedState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_MOVE_STATE_MACHINE:
|
||
|
MoveState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_STEALTH_SOLDIER_STATE_MACHINE:
|
||
|
StealthSoldierState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_HAVOC_STATE_MACHINE:
|
||
|
HavocState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_THROWN_OBJ_STATE_MACHINE:
|
||
|
ThrownObjectState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_JUMP_STATE_MACHINE:
|
||
|
JumpState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_LIGHTNING_ROD_STATE_MACHINE:
|
||
|
LightningRodState.Load (cload);
|
||
|
break;
|
||
|
|
||
|
case CHUNKID_VARIABLES:
|
||
|
Load_Variables (cload);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Debug_Say (("Unrecognized RaveshawBossGameObjClass chunk ID\n"));
|
||
|
break;
|
||
|
|
||
|
}
|
||
|
|
||
|
cload.Close_Chunk ();
|
||
|
}
|
||
|
|
||
|
SaveLoadSystemClass::Register_Post_Load_Callback (this);
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// On_Post_Load
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::On_Post_Load (void)
|
||
|
{
|
||
|
SoldierGameObj::On_Post_Load ();
|
||
|
|
||
|
//
|
||
|
// Make Raveshaw big and beefy...
|
||
|
//
|
||
|
Peek_Model ()->Scale (1.5F);
|
||
|
|
||
|
//
|
||
|
// Make a list of the lightning rods in the area
|
||
|
//
|
||
|
Collect_Lightning_Rods ();
|
||
|
Prepare_Arc_Effect_Data ();
|
||
|
|
||
|
//
|
||
|
// Override the walking animations for this guy
|
||
|
//
|
||
|
Get_Human_State ()->Set_Human_Anim_Override ("Raveshaw Boss Override");
|
||
|
|
||
|
//
|
||
|
// Apply the blue tiberium effect as necessary
|
||
|
//
|
||
|
if (IsTiberiumEffectApplied) {
|
||
|
Peek_Physical_Object ()->Add_Effect_To_Me (TiberiumEffect);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Save_Variables
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Save_Variables (ChunkSaveClass &csave)
|
||
|
{
|
||
|
//
|
||
|
// Save a pointer for each arc-object
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_ARC_OBJ_PTR, ArcObjects[index]);
|
||
|
}
|
||
|
|
||
|
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_RESTORE_FIRST_PERSON, RestoreFirstPerson);
|
||
|
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_THROWN_OBJECT_PTR, ThrownObject);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_IS_TIBERIUM_EFFECT_APPLIED, IsTiberiumEffectApplied);
|
||
|
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_CURRENT_DEST_POS, CurrentDestPos);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_OVERALL_STATE_TIMER, OverallStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_ENGORGED_STATE_TIMER, EngorgedStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_MOVE_STATE_TIMER, MoveStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_BODY_SLAM_TIMER, BodySlamTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_RAVESHAW_STATE_TIMER, RaveshawStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_STEALTHSOLDIER_STATE_TIMER, StealthSoldierStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_LIGHTNINGROD_STATE_TIMER, LightningRodStateTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_START_TIMER, StartTimer);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_LAST_MELEE_ANIM_FRAME, LastMeleeAnimFrame);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_HAS_MELEE_ATTACK_HIT, HasMeleeAttackHit);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_FLYING_OBJECT_VECTOR, FlyingObjectVector);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_FLYING_OBJECT_DEST, FlyingObjectDest);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_FLYING_DIST, FlyingDist);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_RELOBJ_TM, RelObjTM);
|
||
|
WRITE_MICRO_CHUNK (csave, VARID_CURR_JUMP_POS, CurrentJumpToPos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Load_Variables
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Load_Variables (ChunkLoadClass &cload)
|
||
|
{
|
||
|
RenderObjClass *old_camera_bone_ptr = NULL;
|
||
|
Matrix3D cam_tm (1);
|
||
|
int arc_obj_index = 0;
|
||
|
|
||
|
while (cload.Open_Micro_Chunk ()) {
|
||
|
switch (cload.Cur_Micro_Chunk_ID ()) {
|
||
|
|
||
|
case VARID_ARC_OBJ_PTR:
|
||
|
LOAD_MICRO_CHUNK (cload, ArcObjects[arc_obj_index++]);
|
||
|
break;
|
||
|
|
||
|
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_RESTORE_FIRST_PERSON, RestoreFirstPerson);
|
||
|
|
||
|
READ_MICRO_CHUNK (cload, VARID_THROWN_OBJECT_PTR, ThrownObject);
|
||
|
READ_MICRO_CHUNK (cload, VARID_IS_TIBERIUM_EFFECT_APPLIED, IsTiberiumEffectApplied);
|
||
|
|
||
|
READ_MICRO_CHUNK (cload, VARID_CURRENT_DEST_POS, CurrentDestPos);
|
||
|
READ_MICRO_CHUNK (cload, VARID_OVERALL_STATE_TIMER, OverallStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_ENGORGED_STATE_TIMER, EngorgedStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_MOVE_STATE_TIMER, MoveStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_BODY_SLAM_TIMER, BodySlamTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_RAVESHAW_STATE_TIMER, RaveshawStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_STEALTHSOLDIER_STATE_TIMER, StealthSoldierStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_LIGHTNINGROD_STATE_TIMER, LightningRodStateTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_START_TIMER, StartTimer);
|
||
|
READ_MICRO_CHUNK (cload, VARID_LAST_MELEE_ANIM_FRAME, LastMeleeAnimFrame);
|
||
|
READ_MICRO_CHUNK (cload, VARID_HAS_MELEE_ATTACK_HIT, HasMeleeAttackHit);
|
||
|
READ_MICRO_CHUNK (cload, VARID_FLYING_OBJECT_VECTOR, FlyingObjectVector);
|
||
|
READ_MICRO_CHUNK (cload, VARID_FLYING_OBJECT_DEST, FlyingObjectDest);
|
||
|
READ_MICRO_CHUNK (cload, VARID_FLYING_DIST, FlyingDist);
|
||
|
READ_MICRO_CHUNK (cload, VARID_RELOBJ_TM, RelObjTM);
|
||
|
READ_MICRO_CHUNK (cload, VARID_CURR_JUMP_POS, CurrentJumpToPos);
|
||
|
|
||
|
default:
|
||
|
Debug_Say (("Unrecognized RaveshawBossGameObjClass Variable chunkID %d\n", cload.Cur_Micro_Chunk_ID ()));
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
cload.Close_Micro_Chunk ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Remap the arc-object pointers
|
||
|
//
|
||
|
for (int index = 0; index < arc_obj_index; index ++) {
|
||
|
REQUEST_POINTER_REMAP ((void **)&ArcObjects[index]);
|
||
|
}
|
||
|
|
||
|
if (ThrownObject != NULL) {
|
||
|
REQUEST_POINTER_REMAP ((void **)&ThrownObject);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// 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
|
||
|
RaveshawBossGameObjClass::Apply_Control (void)
|
||
|
{
|
||
|
SoldierGameObj::Apply_Control ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Think
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Think (void)
|
||
|
{
|
||
|
WWPROFILE ("Raveshaw 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 || COMBAT_STAR->Is_Dead () || COMBAT_STAR->Is_Destroyed ()) {
|
||
|
ok_to_think = false;
|
||
|
}
|
||
|
|
||
|
if (ok_to_think) {
|
||
|
|
||
|
Verify_Stealth_Soldier ();
|
||
|
|
||
|
//
|
||
|
// Get the position of both Raveshaw and the star (this information
|
||
|
// is used throughout the AI)
|
||
|
//
|
||
|
Get_Position (&RaveshawPos);
|
||
|
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) {
|
||
|
StartTimer = UNINITIALIZED_TIMER;
|
||
|
OverallState.Set_State (OVERALL_STATE_CHASE_STAR);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Let the state machines think
|
||
|
//
|
||
|
OverallState.Think ();
|
||
|
RaveshawState.Think ();
|
||
|
MoveState.Think ();
|
||
|
EngorgedState.Think ();
|
||
|
StealthSoldierState.Think ();
|
||
|
HavocState.Think ();
|
||
|
ThrownObjectState.Think ();
|
||
|
JumpState.Think ();
|
||
|
LightningRodState.Think ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Give Raveshaw 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 ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Verify_Stealth_Soldier
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Verify_Stealth_Soldier (void)
|
||
|
{
|
||
|
if (StealthSoldierState.Get_State () == STEALTH_SOLDIER_STATE_NONE) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Check to see if the stealth soldier has been destroyed...
|
||
|
//
|
||
|
SoldierGameObj *stealth_soldier = Peek_Stealth_Soldier ();
|
||
|
if ( stealth_soldier != NULL &&
|
||
|
(stealth_soldier->Is_Dead () || stealth_soldier->Is_Destroyed ()))
|
||
|
{
|
||
|
//
|
||
|
// Get rid of the stealth soldier
|
||
|
//
|
||
|
stealth_soldier->Peek_Physical_Object ()->Remove_Effect_From_Me (StealthEffect);
|
||
|
stealth_soldier->Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
stealth_soldier->Set_Delete_Pending ();
|
||
|
StealthSoldier = NULL;
|
||
|
|
||
|
OverallState.Set_State (OVERALL_STATE_NOTHING);
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_ROAR);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
Determine_New_Overall_State ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Shuffle_Taunt_List
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::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
|
||
|
RaveshawBossGameObjClass::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 ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Apply the damage
|
||
|
//
|
||
|
DefenseObject.Set_Can_Object_Die (false);
|
||
|
SoldierGameObj::Apply_Damage_Extended (damager, scale, direction, collision_box_name);
|
||
|
|
||
|
//
|
||
|
// Get the boss's current health
|
||
|
//
|
||
|
float curr_health = DefenseObject.Get_Health ();
|
||
|
|
||
|
if (FreeRandom.Get_Int (7) == 1) {
|
||
|
//
|
||
|
// Play a hurt sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Hurt_Twidder", Get_Transform ());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// If he's circling the catwalk, and badly damaged, then
|
||
|
// proceed to his death
|
||
|
//
|
||
|
if (MoveState.Get_State () == MOVE_STATE_CIRCLE_CATWALK && curr_health <= 20.0F) {
|
||
|
if (FreeRandom.Get_Int (5) == 1) {
|
||
|
OverallState.Set_State (OVERALL_STATE_DEATH_SEQUENCE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Attach_Sound
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::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 ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_HEALING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_HEALING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Pull the strings to get the mutant to run to the blue tiberium
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_GOTO_TIBERIUM);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_THROWING_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_THROWING_OBJECT) (void)
|
||
|
{
|
||
|
ThrownObject = Find_Object_To_Throw ();
|
||
|
if (ThrownObject != NULL) {
|
||
|
|
||
|
//
|
||
|
// Pull the strings to get the mutant to grab a stealth soldier...
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_GOTO_THROW_OBJECT);
|
||
|
} else {
|
||
|
OverallState.Set_State (OVERALL_STATE_CHASE_STAR);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_THROWING_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_THROWING_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Pull the strings to get the mutant to grab a stealth soldier...
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_GRAB_SOLDIER);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_GRAB_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_GRAB_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Pull the strings to get the mutant to grab the player
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_GRAB_STAR);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_CHASE_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_CHASE_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Pull the strings to get the mutant to run to the blue tiberium
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_FOLLOW_STAR);
|
||
|
|
||
|
//
|
||
|
// Chase the player for a random amount of time
|
||
|
//
|
||
|
OverallStateTimer = WWMath::Random_Float (6.0F, 20.0F);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(OVERALL_STATE_CHASE_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(OVERALL_STATE_CHASE_STAR) (void)
|
||
|
{
|
||
|
const float ARMS_REACH = 3.8F;
|
||
|
|
||
|
//
|
||
|
// Check to see if Raveshaw is close enough to the player to do some damage.
|
||
|
//
|
||
|
float dist2 = (RaveshawPos - StarPos).Length2 ();
|
||
|
if (dist2 <= ARMS_REACH && JumpState.Get_State () == JUMP_STATE_NONE) {
|
||
|
|
||
|
//
|
||
|
// Grab for the star
|
||
|
//
|
||
|
OverallState.Set_State (OVERALL_STATE_GRAB_STAR);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_JUMP_TO_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_JUMP_TO_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// Pull the strings to get the mutant to run to a spot where he
|
||
|
// can jump to the catwalk
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_GOTO_CATWALK);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_ON_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_ON_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// Get the mutant to run around the catwalk for a bit...
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_CIRCLE_CATWALK);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_BODYSLAM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_BODYSLAM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Get Raveshaw to do his bodyslam
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_BODYSLAM);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(OVERALL_STATE_DEATH_SEQUENCE)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(OVERALL_STATE_DEATH_SEQUENCE) (void)
|
||
|
{
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_DYING);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_STOP)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_STOP) (void)
|
||
|
{
|
||
|
Get_Action ()->Reset (100);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_GOTO_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_GOTO_TIBERIUM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Find the "closest" position around the tiberium for Raveshaw to run to
|
||
|
//
|
||
|
Vector3 dir_vector = (RaveshawPos - TIBERIUM_POS);
|
||
|
dir_vector.Normalize ();
|
||
|
CurrentDestPos = TIBERIUM_POS + (TIBERIUM_RADIUS * dir_vector);
|
||
|
|
||
|
//
|
||
|
// Make the mutant move to that position
|
||
|
//
|
||
|
ActionParamsStruct params;
|
||
|
params.Set_Basic ((long)0, 100, 777);
|
||
|
params.Set_Movement (CurrentDestPos, 0.6F, 0.5F);
|
||
|
Get_Action ()->Goto (params);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_GOTO_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_GOTO_TIBERIUM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Put Raveshaw in the "healing" state
|
||
|
//
|
||
|
if (Get_Action ()->Is_Active () == false) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_GRAB_TIBERIUM);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_GOTO_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_GOTO_CATWALK) (void)
|
||
|
{
|
||
|
//const float MIN_JUMP_DIST = 4.0F;
|
||
|
//const float MAX_JUMP_DIST = 10.0F;
|
||
|
|
||
|
//
|
||
|
// Find the closest catwlk position to our current position
|
||
|
//
|
||
|
Find_Closest_Catwalk_Pos (RaveshawPos, &CurrentJumpToPos);
|
||
|
|
||
|
//
|
||
|
// Detemine what the "most" aligned ground position would be...
|
||
|
//
|
||
|
Vector3 dir_vector = (CurrentJumpToPos - TIBERIUM_POS);
|
||
|
dir_vector.Normalize ();
|
||
|
CurrentDestPos.X = CurrentJumpToPos.X + (dir_vector.X * 8.0F);
|
||
|
CurrentDestPos.Y = CurrentJumpToPos.Y + (dir_vector.Y * 8.0F);
|
||
|
CurrentDestPos.Z = TIBERIUM_POS.Z;
|
||
|
|
||
|
//
|
||
|
// Make the mutant move into position
|
||
|
//
|
||
|
ActionParamsStruct params;
|
||
|
params.Set_Basic ((long)0, 100, 777);
|
||
|
params.Set_Movement (CurrentDestPos, 0.6F, 0.5F);
|
||
|
Get_Action ()->Goto (params);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Find_Closest_Catwalk_Pos
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Find_Closest_Catwalk_Pos (const Vector3 &curr_pos, Vector3 *catwalk_pos)
|
||
|
{
|
||
|
float best_dist2 = 99999.0F;
|
||
|
|
||
|
//
|
||
|
// Get the catwalk waypath
|
||
|
//
|
||
|
WaypathClass *waypath = PathfindClass::Get_Instance ()->Find_Waypath (CATWALK_WAYPATH_ID);
|
||
|
WWASSERT (waypath != NULL);
|
||
|
|
||
|
//
|
||
|
// Now find the closest point which is in-between the waypath points
|
||
|
//
|
||
|
for (int index = 0; index < waypath->Get_Point_Count (); index ++) {
|
||
|
|
||
|
//
|
||
|
// Determine what the current and next waypath points are
|
||
|
//
|
||
|
int curr_index = index;
|
||
|
int next_index = index + 1;
|
||
|
if (index + 1 >= waypath->Get_Point_Count ()) {
|
||
|
next_index = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the position of the current and next waypoint
|
||
|
//
|
||
|
Vector3 curr_waypath_pos = waypath->Get_Point (curr_index)->Get_Position ();
|
||
|
Vector3 next_waypath_pos = waypath->Get_Point (next_index)->Get_Position ();
|
||
|
|
||
|
//
|
||
|
// Evaluate this jump to position (is it the closest?)
|
||
|
//
|
||
|
Vector3 jump_to_pos = curr_waypath_pos + ((next_waypath_pos - curr_waypath_pos) * 0.5F);
|
||
|
Vector3 dir_vector = (curr_pos - jump_to_pos);
|
||
|
dir_vector.Z = 0;
|
||
|
float dist2 = dir_vector.Length2 ();
|
||
|
if (dist2 < best_dist2) {
|
||
|
best_dist2 = dist2;
|
||
|
(*catwalk_pos) = jump_to_pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_GOTO_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_GOTO_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// Face the tiberium as necessary
|
||
|
//
|
||
|
float dist2 = (RaveshawPos - CurrentDestPos).Length2 ();
|
||
|
if (dist2 < 4.0F) {
|
||
|
Get_Action ()->Get_Parameters ().IgnoreFacing = true;
|
||
|
Set_Targeting (TIBERIUM_POS);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Put Raveshaw in the jump to position stage
|
||
|
//
|
||
|
if (Get_Action ()->Is_Active () == false) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
MoveState.Set_State (MOVE_STATE_JUMP_TO_CATWALK);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_JUMP_TO_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_JUMP_TO_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// Simply cause the physics to jump to the specified point
|
||
|
//
|
||
|
Jump_To_Point (CurrentJumpToPos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_JUMP_TO_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_JUMP_TO_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// The state ends when the mutant lands
|
||
|
//
|
||
|
if (JumpState.Get_State () == JUMP_STATE_NONE) {
|
||
|
OverallState.Set_State (OVERALL_STATE_ON_CATWALK);
|
||
|
}
|
||
|
|
||
|
Set_Targeting (TIBERIUM_POS);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_CIRCLE_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_CIRCLE_CATWALK) (void)
|
||
|
{
|
||
|
MoveStateTimer = 0.0F;
|
||
|
BodySlamTimer = WWMath::Random_Float (1.0F, 5.0F);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_CIRCLE_CATWALK)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_CIRCLE_CATWALK) (void)
|
||
|
{
|
||
|
//
|
||
|
// Always try to face the star
|
||
|
//
|
||
|
Set_Targeting (StarPos);
|
||
|
|
||
|
//
|
||
|
// Calculate Raveshaw's remaining health
|
||
|
//
|
||
|
float health = DefenseObject.Get_Health ();
|
||
|
float health_percent = health / DefenseObject.Get_Health_Max ();
|
||
|
|
||
|
//
|
||
|
// Is it time to bodyslam?
|
||
|
//
|
||
|
BodySlamTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (health_percent > 0.05F && BodySlamTimer <= 0) {
|
||
|
OverallState.Set_State (OVERALL_STATE_BODYSLAM);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Is it time to choose a new spot on the catwalk?
|
||
|
//
|
||
|
MoveStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (MoveStateTimer <= 0) {
|
||
|
MoveStateTimer = 0.5F;
|
||
|
|
||
|
//
|
||
|
// Find the closest catwalk position to our current position
|
||
|
//
|
||
|
Find_Closest_Catwalk_Pos (StarPos, &CurrentDestPos);
|
||
|
|
||
|
//
|
||
|
// Now, simply make the mutant move to this position
|
||
|
//
|
||
|
ActionParamsStruct params;
|
||
|
params.Set_Basic ((long)0, 100, 777);
|
||
|
params.Set_Movement (CurrentDestPos, 0.5F, 0.5F);
|
||
|
params.IgnoreFacing = true;
|
||
|
Get_Action ()->Goto (params);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_GOTO_THROW_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_GOTO_THROW_OBJECT) (void)
|
||
|
{
|
||
|
//
|
||
|
// Walk to the position of the throw object
|
||
|
//
|
||
|
ActionParamsStruct params;
|
||
|
params.Set_Basic ((long)0, 100, 777);
|
||
|
params.Set_Movement (ThrownObject, 0.5F, 1.25F);
|
||
|
Get_Action ()->Goto (params);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_GOTO_THROW_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_GOTO_THROW_OBJECT) (void)
|
||
|
{
|
||
|
Vector3 obj_pos;
|
||
|
ThrownObject->Get_Position (&obj_pos);
|
||
|
if ((RaveshawPos - obj_pos).Length2 () < 3.0F || Get_Action ()->Is_Active () == false) {
|
||
|
//}
|
||
|
|
||
|
//
|
||
|
// Stop and pick up the object once we get there
|
||
|
//
|
||
|
//if (Get_Action ()->Is_Active () == false) {
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_GRAB_OBJECT);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_JUMP_TO_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_JUMP_TO_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Stop any current action and jump to the star's position
|
||
|
//
|
||
|
Get_Action ()->Reset (100);
|
||
|
Jump_To_Point (StarPos);
|
||
|
//Peek_Human_Phys ()->Jump_To_Point (StarPos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_JUMP_TO_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_JUMP_TO_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Face the star
|
||
|
//
|
||
|
Set_Targeting (StarPos);
|
||
|
|
||
|
//
|
||
|
// The state ends when the mutant lands
|
||
|
//
|
||
|
if (JumpState.Get_State () == JUMP_STATE_NONE) {
|
||
|
MoveState.Set_State (MOVE_STATE_FOLLOW_STAR);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(MOVE_STATE_FOLLOW_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(MOVE_STATE_FOLLOW_STAR) (void)
|
||
|
{
|
||
|
MoveStateTimer = 0.0F;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(MOVE_STATE_FOLLOW_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(MOVE_STATE_FOLLOW_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Simply stop any action
|
||
|
//
|
||
|
Get_Action ()->Reset (100);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(MOVE_STATE_FOLLOW_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(MOVE_STATE_FOLLOW_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Is it time to track down the player again?
|
||
|
//
|
||
|
MoveStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (MoveStateTimer <= 0) {
|
||
|
MoveStateTimer = 0.75F;
|
||
|
|
||
|
//
|
||
|
// Should we jump to the player's position?
|
||
|
//
|
||
|
float dist2 = (RaveshawPos - StarPos).Length2 ();
|
||
|
if ((dist2 > 64.0F) && FreeRandom.Get_Int (5) == 1) {
|
||
|
MoveState.Set_State (MOVE_STATE_JUMP_TO_STAR);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Track down the player
|
||
|
//
|
||
|
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);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_NOTHING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_NOTHING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Choose a random time to do something a little different (i.e. roar, etc)
|
||
|
//
|
||
|
RaveshawStateTimer = WWMath::Random_Float (5.0F, 15.0F);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_NOTHING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_NOTHING) (void)
|
||
|
{
|
||
|
RaveshawStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (RaveshawStateTimer <= 0) {
|
||
|
|
||
|
//
|
||
|
// Just throw your head back and roar
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_ROAR);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_ROAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_ROAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the roar animation and sound
|
||
|
//
|
||
|
Set_Blended_Animation ("S_C_HUMAN.H_C_A0A0_L07", false);
|
||
|
Attach_Sound ("Rav_Long_Yell_Twiddler", "C HEAD");
|
||
|
|
||
|
//
|
||
|
// Stop whatever action he's doing (temporarily)
|
||
|
//
|
||
|
Get_Action ()->Pause (true);
|
||
|
JumpState.Halt_State ();
|
||
|
MoveState.Halt_State ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_ROAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_ROAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
|
||
|
//
|
||
|
// Resume the action
|
||
|
//
|
||
|
MoveState.Resume_State ();
|
||
|
JumpState.Resume_State ();
|
||
|
Get_Action ()->Pause (false);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_ROAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_ROAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Reset the state when complete
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_TIBERIUM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the grab the tiberium animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_HEAL", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 34
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (34);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_GRAB_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_GRAB_TIBERIUM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_TIBERIUM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Face the tiberium
|
||
|
//
|
||
|
Set_Targeting (TIBERIUM_POS);
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (9.0F)) {
|
||
|
|
||
|
//
|
||
|
// Start healing
|
||
|
//
|
||
|
EngorgedState.Set_State (ENGORGED_STATE_ABSORBING_TIBERIUM);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Loop the animation between frames 12 and 34
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 12);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (34);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the grab the soldier animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_GRABTHROW", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 27
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (27);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_GRAB_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_GRAB_SOLDIER) (void)
|
||
|
{
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Is it time to show the soldier?
|
||
|
//
|
||
|
if ( StealthSoldierState.Get_State () == STEALTH_SOLDIER_STATE_NONE &&
|
||
|
Get_Anim_Control ()->Is_Complete ())
|
||
|
{
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_DISPLAY);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure we face the star...
|
||
|
//
|
||
|
if (StealthSoldierState.Get_State () != STEALTH_SOLDIER_STATE_NONE) {
|
||
|
Set_Targeting (StarPos);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_THROW_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_THROW_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the throw the soldier animation
|
||
|
//
|
||
|
/*Set_Blended_Animation ("S_A_HUMAN.GRABTHROW", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Start the animation at frame 27
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_ONCE, 27);*/
|
||
|
|
||
|
//
|
||
|
// Advance to frame 49
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Target_Frame (49);
|
||
|
|
||
|
//
|
||
|
// Play an exertion sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Exert_01", Get_Transform ());
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_THROW_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_THROW_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_THROW_SOLDIER)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_THROW_SOLDIER) (void)
|
||
|
{
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (36.0F)) {
|
||
|
|
||
|
//
|
||
|
// Let the soldier fly!
|
||
|
//
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_FLYING);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Decide on what to do when finished
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
Determine_New_Overall_State ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_OBJECT) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the pickup the object animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_THROW", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 22
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (22);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_OBJECT) (void)
|
||
|
{
|
||
|
//
|
||
|
// Throw the object
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_THROW_OBJECT);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (9.0F)) {
|
||
|
|
||
|
//
|
||
|
// Pickup the object
|
||
|
//
|
||
|
ThrownObjectState.Set_State (THROWN_OBJECT_STATE_PICKUP);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_THROW_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_THROW_OBJECT) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the throw the object animation
|
||
|
//
|
||
|
//Set_Blended_Animation ("S_A_HUMAN.A_HOST_L3A", false);
|
||
|
//Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 29
|
||
|
//
|
||
|
//Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
//Get_Anim_Control ()->Set_Target_Frame (29);
|
||
|
|
||
|
RaveshawStateTimer = 1.0F;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_THROW_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_THROW_OBJECT) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_THROW_OBJECT)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_THROW_OBJECT) (void)
|
||
|
{
|
||
|
if (RaveshawStateTimer != UNINITIALIZED_TIMER) {
|
||
|
RaveshawStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (RaveshawStateTimer <= 0) {
|
||
|
RaveshawStateTimer = UNINITIALIZED_TIMER;
|
||
|
|
||
|
//
|
||
|
// Finish the animation
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Target_Frame (58);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (36.0F)) {
|
||
|
|
||
|
//
|
||
|
// Let the object fly!
|
||
|
//
|
||
|
ThrownObjectState.Set_State (THROWN_OBJECT_STATE_FLYING);
|
||
|
}
|
||
|
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
|
||
|
//
|
||
|
// Decide on what to do next...
|
||
|
//
|
||
|
Determine_New_Overall_State ();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Make sure to face the star
|
||
|
//
|
||
|
Set_Targeting (StarPos);
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_GRAB_STAR) (void)
|
||
|
{
|
||
|
HasMeleeAttackHit = false;
|
||
|
LastMeleeAnimFrame = 0.0F;
|
||
|
|
||
|
//
|
||
|
// Play the grab the star animation
|
||
|
//
|
||
|
//Set_Blended_Animation ("S_A_HUMAN.RAV_HIT", false);
|
||
|
//Set_Blended_Animation ("S_C_HUMAN.H_C_A0A0_L02", false);
|
||
|
//
|
||
|
// Play the grab the soldier animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_GRABTHROW", false, 14.0F);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
((HumanAnimControlClass *)Get_Anim_Control ())->Set_Anim_Speed_Scale (0.5F);
|
||
|
|
||
|
//
|
||
|
// Grab the player
|
||
|
//
|
||
|
HavocState.Set_State (HAVOC_STATE_GRABBED);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_GRAB_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_GRAB_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_STAR)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_GRAB_STAR) (void)
|
||
|
{
|
||
|
//
|
||
|
// Decide on something new to do if finished
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
Determine_New_Overall_State ();
|
||
|
} else {
|
||
|
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (37.0F)) {
|
||
|
HavocState.Set_State (HAVOC_STATE_FLYING);
|
||
|
} else if (PASSED_FRAME (25.0F)) {
|
||
|
((HumanAnimControlClass *)Get_Anim_Control ())->Set_Anim_Speed_Scale (1.0F);
|
||
|
}
|
||
|
|
||
|
LastMeleeAnimFrame = curr_frame;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Always try to face the star
|
||
|
//
|
||
|
//Set_Targeting (StarPos);
|
||
|
|
||
|
/*float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
if (curr_frame >= 7.0F) {
|
||
|
|
||
|
//
|
||
|
// Decide on something new to do if finished
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
Determine_New_Overall_State ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Apply hefty damage if we connect
|
||
|
//
|
||
|
if (HasMeleeAttackHit == false) {
|
||
|
HasMeleeAttackHit |= Apply_Bone_Collision_Damage (15.0F, "C R HAND");
|
||
|
HasMeleeAttackHit |= Apply_Bone_Collision_Damage (15.0F, "C L HAND");
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
}*/
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_BODYSLAM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_BODYSLAM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Find the "closest" position around the tiberium for Raveshaw to run to
|
||
|
//
|
||
|
Vector3 star_vector_from_tib = (StarPos - TIBERIUM_POS);
|
||
|
star_vector_from_tib.Z = 0;
|
||
|
|
||
|
//
|
||
|
// Check to see if the player is in the right spot for a body slam
|
||
|
//
|
||
|
if (star_vector_from_tib.Length2 () < (SAFE_JUMP_RADIUS * SAFE_JUMP_RADIUS)) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_JUMP_DOWN);
|
||
|
} else {
|
||
|
HasMeleeAttackHit = false;
|
||
|
LastMeleeAnimFrame = 0.0F;
|
||
|
|
||
|
//
|
||
|
// Play the bodyslam animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.H_A_BODYSLAM", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 69
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (69);
|
||
|
|
||
|
//
|
||
|
// Play a yell sound.
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Body_Slam_Yell", Get_Transform ());
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(RAVESHAW_STATE_BODYSLAM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(RAVESHAW_STATE_BODYSLAM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_BODYSLAM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_BODYSLAM) (void)
|
||
|
{
|
||
|
//
|
||
|
// Have we finished the body slam?
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
if (curr_frame >= 174.0F) {
|
||
|
|
||
|
//
|
||
|
// Determine which state to goto next...
|
||
|
//
|
||
|
Determine_New_Overall_State ();
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
|
||
|
if (PASSED_FRAME (37.0F)) {
|
||
|
|
||
|
//
|
||
|
// Get the mutant to jump to the star's position
|
||
|
//
|
||
|
Peek_Human_Phys ()->Jump_To_Point (StarPos);
|
||
|
} else if (PASSED_FRAME (90.0F)) {
|
||
|
|
||
|
//
|
||
|
// Create an explision when he lands
|
||
|
//
|
||
|
DefinitionClass *definition = DefinitionMgrClass::Find_Named_Definition ("Explosion_Raveshaw_Bodyslam");
|
||
|
if (definition != NULL) {
|
||
|
|
||
|
//
|
||
|
// Position the explosion at the mutants pelvis
|
||
|
//
|
||
|
const Matrix3D &pelvis_tm = Peek_Model ()->Get_Bone_Transform ("C PELVIS");
|
||
|
ExplosionManager::Create_Explosion_At (definition->Get_ID (), pelvis_tm.Get_Translation (), NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do we need to check for the ground?
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Get_Target_Frame () != 174.0F) {
|
||
|
|
||
|
//
|
||
|
// Now determine if the mutant is within a few feet of the ground
|
||
|
//
|
||
|
float distance = Get_Distance_From_Ground ();
|
||
|
if (distance < 1.0F) {
|
||
|
Get_Anim_Control ()->Set_Target_Frame (174.0F);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Apply massive damage if we connect
|
||
|
//
|
||
|
Apply_Bone_Collision_Damage (500.0F, "C PELVIS");
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_JUMP_DOWN)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_JUMP_DOWN) (void)
|
||
|
{
|
||
|
//
|
||
|
// Find the "closest" position to the star that Raveshaw can jump to
|
||
|
//
|
||
|
Vector3 dir_vector = (StarPos - TIBERIUM_POS);
|
||
|
dir_vector.Normalize ();
|
||
|
CurrentDestPos = TIBERIUM_POS + (SAFE_JUMP_RADIUS * dir_vector);
|
||
|
|
||
|
//
|
||
|
// Now, jump to this position
|
||
|
//
|
||
|
Jump_To_Point (CurrentDestPos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_JUMP_DOWN)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_JUMP_DOWN) (void)
|
||
|
{
|
||
|
//
|
||
|
// Apply massive damage if we connect
|
||
|
//
|
||
|
Apply_Bone_Collision_Damage (500.0F, "C L FOOT");
|
||
|
Apply_Bone_Collision_Damage (500.0F, "C R FOOT");
|
||
|
|
||
|
//
|
||
|
// The state ends when the mutant lands
|
||
|
//
|
||
|
if (JumpState.Get_State () == JUMP_STATE_NONE) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_NOTHING);
|
||
|
OverallState.Set_State (OVERALL_STATE_CHASE_STAR);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_DYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_DYING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the crouching animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_DEATH", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 49
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (49);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_DYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_DYING) (void)
|
||
|
{
|
||
|
/*Vector3 delta_vector = RaveshawPos - TIBERIUM_POS;
|
||
|
|
||
|
Vector3 dir_vector = (RaveshawPos - TIBERIUM_POS);
|
||
|
dir_vector.Normalize ();
|
||
|
Vector3 target_pos = TIBERIUM_POS + (8.0F * dir_vector);*/
|
||
|
|
||
|
Vector3 target_pos (0, 0, 0);
|
||
|
Find_Death_Facing_Pos (&target_pos);
|
||
|
Set_Targeting (target_pos);
|
||
|
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (43.0F)) {
|
||
|
|
||
|
//
|
||
|
// Start falling when the animation gets to the correct frame
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_FALL);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Cache the last frame number...
|
||
|
//
|
||
|
LastMeleeAnimFrame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_FALL)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_FALL) (void)
|
||
|
{
|
||
|
RaveshawStateTimer = 0.125F;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_FALL)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_FALL) (void)
|
||
|
{
|
||
|
RaveshawStateTimer += TimeManager::Get_Frame_Seconds ();
|
||
|
float velocity = (22.0F * RaveshawStateTimer);
|
||
|
|
||
|
Vector3 new_pos = RaveshawPos;
|
||
|
new_pos.Z -= velocity * TimeManager::Get_Frame_Seconds ();
|
||
|
|
||
|
//
|
||
|
// Simply stop falling when he reaches the "ground". (We hard-code the ground's
|
||
|
// Z-position for simplicity.)
|
||
|
//
|
||
|
const float FLOOR_POS1 = -189.1F;
|
||
|
const float FLOOR_POS2 = -191.0F;
|
||
|
|
||
|
if ( (new_pos.X >= -133.1F && new_pos.Z <= FLOOR_POS1) ||
|
||
|
(new_pos.X < -133.1F && new_pos.Z <= FLOOR_POS2))
|
||
|
{
|
||
|
if (new_pos.X >= -133.1F) {
|
||
|
new_pos.Z = FLOOR_POS1;
|
||
|
} else {
|
||
|
new_pos.Z = FLOOR_POS2;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move onto the "landing" state
|
||
|
//
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_DEATH_LANDING);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Move Raveshaw
|
||
|
//
|
||
|
Set_Position (new_pos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(RAVESHAW_STATE_DEATH_LANDING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(RAVESHAW_STATE_DEATH_LANDING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the rest of the animation
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Target_Frame (63);
|
||
|
RaveshawStateTimer = UNINITIALIZED_TIMER;
|
||
|
|
||
|
//
|
||
|
// Play a landing sound.
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Death_Fall", Get_Transform ());
|
||
|
COMBAT_SCENE->Add_Camera_Shake (RaveshawPos, 40.0, 0.75F, 0.125F);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(RAVESHAW_STATE_DEATH_LANDING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(RAVESHAW_STATE_DEATH_LANDING) (void)
|
||
|
{
|
||
|
if (RaveshawStateTimer != UNINITIALIZED_TIMER) {
|
||
|
RaveshawStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (RaveshawStateTimer <= 0) {
|
||
|
//
|
||
|
// Trigger mission success
|
||
|
//
|
||
|
CombatManager::Mission_Complete (true);
|
||
|
}
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// When the animation's complete, sit and wait for
|
||
|
// a couple of seconds
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
RaveshawStateTimer = 2.0F;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(ENGORGED_STATE_ABSORBING_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(ENGORGED_STATE_ABSORBING_TIBERIUM) (void)
|
||
|
{
|
||
|
EngorgedStateTimer = HEAL_TIME;
|
||
|
LightningRodState.Set_State (LIGHTNING_ROD_STATE_ACTIVE);
|
||
|
|
||
|
//
|
||
|
// Configure the effect
|
||
|
//
|
||
|
TiberiumEffect->Set_Intensity (0.0F);
|
||
|
Peek_Physical_Object ()->Add_Effect_To_Me (TiberiumEffect);
|
||
|
IsTiberiumEffectApplied = true;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(ENGORGED_STATE_ABSORBING_TIBERIUM)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(ENGORGED_STATE_ABSORBING_TIBERIUM) (void)
|
||
|
{
|
||
|
const float HEAL_RATE = 50.0F;
|
||
|
|
||
|
//
|
||
|
// If he's finished absorbing the tiberium, then start chasing the player
|
||
|
//
|
||
|
EngorgedStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (EngorgedStateTimer <= 0) {
|
||
|
EngorgedState.Set_State (ENGORGED_STATE_FADING);
|
||
|
OverallState.Set_State (OVERALL_STATE_CHASE_STAR);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Configure the intensity
|
||
|
//
|
||
|
float percent = 1.0F - WWMath::Clamp ((EngorgedStateTimer / HEAL_TIME), 0.0F, 1.0F);
|
||
|
TiberiumEffect->Set_Intensity (percent * EFFECT_INTENSITY);
|
||
|
|
||
|
//
|
||
|
// Heal the mutant a little bit
|
||
|
//
|
||
|
float health = DefenseObject.Get_Health ();
|
||
|
health += HEAL_RATE * TimeManager::Get_Frame_Seconds ();
|
||
|
DefenseObject.Set_Health (health);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(ENGORGED_STATE_FADING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(ENGORGED_STATE_FADING) (void)
|
||
|
{
|
||
|
LightningRodState.Set_State (ENGORGED_STATE_NONE);
|
||
|
EngorgedStateTimer = TiberiumEffect->Get_Intensity () * EFFECT_FADE_TIME;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(ENGORGED_STATE_FADING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(ENGORGED_STATE_FADING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Remove the blue shimmering effect
|
||
|
//
|
||
|
Peek_Physical_Object ()->Remove_Effect_From_Me (TiberiumEffect);
|
||
|
IsTiberiumEffectApplied = false;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(ENGORGED_STATE_FADING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(ENGORGED_STATE_FADING) (void)
|
||
|
{
|
||
|
//
|
||
|
// If he's finished absorbing the tiberium, then start chasing the player
|
||
|
//
|
||
|
EngorgedStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (EngorgedStateTimer <= 0) {
|
||
|
EngorgedState.Set_State (ENGORGED_STATE_NONE);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Configure the intensity
|
||
|
//
|
||
|
float percent = WWMath::Clamp ((EngorgedStateTimer / EFFECT_FADE_TIME), 0.0F, 1.0F);
|
||
|
TiberiumEffect->Set_Intensity (percent * EFFECT_INTENSITY);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(JUMP_STATE_CROUCHING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(JUMP_STATE_CROUCHING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the crouching animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_JUMP", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Stop the animation at frame 10
|
||
|
//
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 0);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (10);
|
||
|
|
||
|
//
|
||
|
// Stop any current action
|
||
|
//
|
||
|
Get_Action ()->Pause (true);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(JUMP_STATE_CROUCHING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(JUMP_STATE_CROUCHING) (void)
|
||
|
{
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
JumpState.Set_State (JUMP_STATE_JUMPING);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(JUMP_STATE_JUMPING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(JUMP_STATE_JUMPING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the jumping animation
|
||
|
//
|
||
|
Set_Blended_Animation ("S_A_HUMAN.H_A_A0D0", false);
|
||
|
//Get_Anim_Control ()->Set_Target_Frame (11);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
//
|
||
|
// Jump to the given position
|
||
|
//
|
||
|
Peek_Human_Phys ()->Jump_To_Point (CurrentJumpToPos);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(JUMP_STATE_JUMPING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(JUMP_STATE_JUMPING) (void)
|
||
|
{
|
||
|
Vector3 velocity;
|
||
|
Peek_Human_Phys ()->Get_Velocity (&velocity);
|
||
|
|
||
|
//
|
||
|
// Is Raveshaw close to the ground?
|
||
|
//
|
||
|
if (velocity.Z < 0 && Get_Distance_From_Ground () < 2.0F) {
|
||
|
JumpState.Set_State (JUMP_STATE_LANDING);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(JUMP_STATE_LANDING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(JUMP_STATE_LANDING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Play the landing animation
|
||
|
//
|
||
|
//Set_Blended_Animation ("S_A_HUMAN.H_A_A0L0", false, 0.0F, true);
|
||
|
//Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
Set_Blended_Animation ("S_A_HUMAN.RAV_JUMP", false);
|
||
|
Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
Get_Anim_Control ()->Set_Mode (ANIM_MODE_TARGET, 11);
|
||
|
Get_Anim_Control ()->Set_Target_Frame (31);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(JUMP_STATE_LANDING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(JUMP_STATE_LANDING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Release our lock on the animation state
|
||
|
//
|
||
|
Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
|
||
|
//
|
||
|
// Resume the current action
|
||
|
//
|
||
|
Get_Action ()->Pause (false);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(JUMP_STATE_LANDING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(JUMP_STATE_LANDING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Handy macro
|
||
|
//
|
||
|
float curr_frame = Get_Anim_Control ()->Get_Current_Frame ();
|
||
|
#define PASSED_FRAME(frame) (LastMeleeAnimFrame < frame && curr_frame >= frame)
|
||
|
if (PASSED_FRAME (20.0F)) {
|
||
|
|
||
|
//
|
||
|
// Play the landing sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Land_On_Metal", Get_Transform ());
|
||
|
COMBAT_SCENE->Add_Camera_Shake (RaveshawPos, 40.0, 0.75F, 0.125F);
|
||
|
}
|
||
|
|
||
|
LastMeleeAnimFrame = curr_frame;
|
||
|
|
||
|
//
|
||
|
// End the state when the animation is complete
|
||
|
//
|
||
|
if (Get_Anim_Control ()->Is_Complete ()) {
|
||
|
JumpState.Set_State (JUMP_STATE_NONE);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(HAVOC_STATE_GRABBED)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(HAVOC_STATE_GRABBED) (void)
|
||
|
{
|
||
|
if (COMBAT_STAR != NULL) {
|
||
|
COMBAT_STAR->Peek_Physical_Object ()->Enable_Objects_Simulation (false);
|
||
|
COMBAT_STAR->Control_Enable (false);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Now snap to 3rd person so we are rendered
|
||
|
//
|
||
|
RestoreFirstPerson = CombatManager::Is_First_Person ();
|
||
|
CombatManager::Set_First_Person (false);
|
||
|
|
||
|
//
|
||
|
// Lock Havoc into a struggling state
|
||
|
//
|
||
|
COMBAT_STAR->Set_Blended_Animation ("S_A_HUMAN.STL_STRUGGLE", true);
|
||
|
COMBAT_STAR->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(HAVOC_STATE_GRABBED)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(HAVOC_STATE_GRABBED) (void)
|
||
|
{
|
||
|
Link_Player_To_Hands ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(HAVOC_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(HAVOC_STATE_FLYING) (void)
|
||
|
{
|
||
|
Vector3 dir_vector = Get_Transform ().Get_X_Vector ();
|
||
|
dir_vector.Z = 0.2F;
|
||
|
dir_vector.Normalize ();
|
||
|
|
||
|
//
|
||
|
// Calculate the direction that the soldier will fly through the air
|
||
|
//
|
||
|
FlyingObjectVector = dir_vector * 15.0F;
|
||
|
FlyingDist = FlyingObjectVector.Length ();
|
||
|
FlyingObjectDest = StarPos + FlyingObjectVector;
|
||
|
FlyingObjectVector.Normalize ();
|
||
|
|
||
|
//
|
||
|
// Restore control to the player
|
||
|
//
|
||
|
COMBAT_STAR->Control_Enable (true);
|
||
|
CombatManager::Set_First_Person (RestoreFirstPerson);
|
||
|
|
||
|
//
|
||
|
// Release Havoc from his struggles
|
||
|
//
|
||
|
COMBAT_STAR->Get_Human_State ()->Stop_Scripted_Animation ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(HAVOC_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(HAVOC_STATE_FLYING) (void)
|
||
|
{
|
||
|
const float RATE = 15.0F;
|
||
|
|
||
|
float percent = RATE * TimeManager::Get_Frame_Seconds ();
|
||
|
Vector3 move_vector = FlyingObjectVector * percent;
|
||
|
|
||
|
//
|
||
|
// Simulate gravity
|
||
|
//
|
||
|
Vector3 delta = StarPos - FlyingObjectDest;
|
||
|
delta.Z = 0;
|
||
|
float dist = delta.Length ();
|
||
|
float dist_percent = 1.0F - WWMath::Clamp ((dist / FlyingDist), 0.0F, 1.0F);
|
||
|
|
||
|
if (dist_percent > 0.3F) {
|
||
|
move_vector.Z -= (dist_percent - 0.3F) * (8.0F * TimeManager::Get_Frame_Seconds ());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Do the move and check to see if we hit anything
|
||
|
//
|
||
|
if (Fly_Move (COMBAT_STAR, move_vector)) {
|
||
|
|
||
|
//
|
||
|
// Restore physics simulation
|
||
|
//
|
||
|
COMBAT_STAR->Peek_Physical_Object ()->Enable_Objects_Simulation (true);
|
||
|
|
||
|
//
|
||
|
// Apply some damage to the player
|
||
|
//
|
||
|
OffenseObjectClass offense_obj (20.0F, 1);
|
||
|
COMBAT_STAR->Apply_Damage_Extended (offense_obj, 1.0F);
|
||
|
|
||
|
//
|
||
|
// Restore Havoc's state
|
||
|
//
|
||
|
HavocState.Set_State (HAVOC_STATE_NONE);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(STEALTH_SOLDIER_STATE_DISPLAY)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(STEALTH_SOLDIER_STATE_DISPLAY) (void)
|
||
|
{
|
||
|
//
|
||
|
// Create the stealth solider and position its neck at Raveshaw's hand
|
||
|
//
|
||
|
Create_Stealth_Soldier (Matrix3D (1));
|
||
|
Link_Stealth_Soldier_To_Hand ();
|
||
|
|
||
|
//
|
||
|
// Check to see if the stealth soldier has been destroyed...
|
||
|
//
|
||
|
SoldierGameObj *stealth_soldier = Peek_Stealth_Soldier ();
|
||
|
if (stealth_soldier == NULL) {
|
||
|
OverallState.Set_State (OVERALL_STATE_NOTHING);
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_ROAR);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
Determine_New_Overall_State ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Play a looping animation on the soldier
|
||
|
//
|
||
|
stealth_soldier->Set_Blended_Animation ("S_A_HUMAN.STL_STRUGGLE", true);
|
||
|
stealth_soldier->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
|
||
|
StealthSoldierStateTimer = 3.0F;
|
||
|
|
||
|
//
|
||
|
// Play the stealth broken sound and the gurgle sound
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Stealth_Broken", Get_Transform ());
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Throat_Grab_Twiddler", Get_Transform ());
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(STEALTH_SOLDIER_STATE_DISPLAY)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(STEALTH_SOLDIER_STATE_DISPLAY) (void)
|
||
|
{
|
||
|
//
|
||
|
// Move the soldier with Ravesahw
|
||
|
//
|
||
|
Link_Stealth_Soldier_To_Hand ();
|
||
|
|
||
|
//
|
||
|
// Is it time for the soldier to be thrown yet?
|
||
|
//
|
||
|
StealthSoldierStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (StealthSoldierStateTimer <= 0) {
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_THROW_SOLDIER);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(STEALTH_SOLDIER_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(STEALTH_SOLDIER_STATE_FLYING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Check to see if the stealth soldier has been destroyed...
|
||
|
//
|
||
|
SoldierGameObj *stealth_soldier = Peek_Stealth_Soldier ();
|
||
|
if (stealth_soldier == NULL) {
|
||
|
OverallState.Set_State (OVERALL_STATE_NOTHING);
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_ROAR);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
Determine_New_Overall_State ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
Vector3 solider_pos;
|
||
|
stealth_soldier->Get_Position (&solider_pos);
|
||
|
|
||
|
//
|
||
|
// Calculate the direction that the soldier will fly through the air
|
||
|
//
|
||
|
FlyingObjectDest = StarPos;
|
||
|
FlyingObjectVector = (StarPos - solider_pos);
|
||
|
FlyingDist = FlyingObjectVector.Length ();
|
||
|
FlyingObjectVector.Normalize ();
|
||
|
|
||
|
//
|
||
|
// Check to see which animation we should be play.
|
||
|
// (Fly forwards, fly backwards, fly right, fly left)
|
||
|
//
|
||
|
Vector3 relative_vector = stealth_soldier->Get_Transform ().Inverse_Rotate_Vector (FlyingObjectVector);
|
||
|
if (WWMath::Fabs (relative_vector.X) > WWMath::Fabs (relative_vector.Y)) {
|
||
|
if (relative_vector.X > 0) {
|
||
|
stealth_soldier->Set_Blended_Animation ("S_A_HUMAN.H_A_FLY1", true);
|
||
|
stealth_soldier->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
} else {
|
||
|
stealth_soldier->Set_Blended_Animation ("S_A_HUMAN.H_A_FLY2", true);
|
||
|
stealth_soldier->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
}
|
||
|
} else {
|
||
|
if (relative_vector.Y > 0) {
|
||
|
stealth_soldier->Set_Blended_Animation ("S_A_HUMAN.H_A_FLY4", true);
|
||
|
stealth_soldier->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
} else {
|
||
|
stealth_soldier->Set_Blended_Animation ("S_A_HUMAN.H_A_FLY3", true);
|
||
|
stealth_soldier->Get_Human_State ()->Set_State (HumanStateClass::LOCKED_ANIMATION);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(STEALTH_SOLDIER_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(STEALTH_SOLDIER_STATE_FLYING) (void)
|
||
|
{
|
||
|
//
|
||
|
// Check to see if the stealth soldier has been destroyed...
|
||
|
//
|
||
|
SoldierGameObj *stealth_soldier = Peek_Stealth_Soldier ();
|
||
|
if (stealth_soldier == NULL) {
|
||
|
OverallState.Set_State (OVERALL_STATE_NOTHING);
|
||
|
RaveshawState.Set_State (RAVESHAW_STATE_ROAR);
|
||
|
MoveState.Set_State (MOVE_STATE_STOP);
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
Determine_New_Overall_State ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
const float RATE = 15.0F;
|
||
|
|
||
|
Vector3 soldier_pos;
|
||
|
stealth_soldier->Get_Position (&soldier_pos);
|
||
|
|
||
|
float dist = (soldier_pos - FlyingObjectDest).Length ();
|
||
|
float dist_percent = (dist / FlyingDist);
|
||
|
|
||
|
float percent = RATE * TimeManager::Get_Frame_Seconds ();
|
||
|
Vector3 move_vector = FlyingObjectVector * percent;
|
||
|
|
||
|
move_vector.Z += (dist_percent - 0.5F) * (4.0F * TimeManager::Get_Frame_Seconds ());
|
||
|
|
||
|
//
|
||
|
// Do the move and check to see if we hit anything
|
||
|
//
|
||
|
if (Fly_Move (stealth_soldier, move_vector)) {
|
||
|
|
||
|
//
|
||
|
// Kill the soldier (which should create a very large explosion)
|
||
|
//
|
||
|
OffenseObjectClass offense_obj (10000.0F, 1);
|
||
|
stealth_soldier->Apply_Damage_Extended (offense_obj, 1.0F);
|
||
|
|
||
|
//
|
||
|
// Restore our state
|
||
|
//
|
||
|
StealthSoldierState.Set_State (STEALTH_SOLDIER_STATE_NONE);
|
||
|
stealth_soldier->Peek_Physical_Object ()->Remove_Effect_From_Me (StealthEffect);
|
||
|
StealthSoldier = NULL;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(THROWN_OBJECT_STATE_PICKUP)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(THROWN_OBJECT_STATE_PICKUP) (void)
|
||
|
{
|
||
|
if (ThrownObject == NULL) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the transform of Raveshaw's right hand
|
||
|
//
|
||
|
const Matrix3D &r_hand_tm = Peek_Model ()->Get_Bone_Transform ("C R HAND");
|
||
|
|
||
|
//
|
||
|
// Now, calculate the object's transform relative to Raveshaw's right hand
|
||
|
//
|
||
|
Matrix3D world_to_hand_tm;
|
||
|
r_hand_tm.Get_Orthogonal_Inverse (world_to_hand_tm);
|
||
|
|
||
|
const Matrix3D &obj_tm = ThrownObject->Get_Transform ();
|
||
|
RelObjTM = world_to_hand_tm * obj_tm;
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(THROWN_OBJECT_STATE_PICKUP)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(THROWN_OBJECT_STATE_PICKUP) (void)
|
||
|
{
|
||
|
//
|
||
|
// Move the object with Raveshaw
|
||
|
//
|
||
|
Link_Thrown_Object_To_Hands ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(THROWN_OBJECT_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(THROWN_OBJECT_STATE_FLYING) (void)
|
||
|
{
|
||
|
Vector3 object_pos;
|
||
|
ThrownObject->Get_Position (&object_pos);
|
||
|
|
||
|
//
|
||
|
// Calculate the direction that the object will fly through the air
|
||
|
//
|
||
|
FlyingObjectDest = StarPos;
|
||
|
FlyingObjectVector = (StarPos - object_pos);
|
||
|
FlyingDist = FlyingObjectVector.Length ();
|
||
|
FlyingObjectVector.Normalize ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(THROWN_OBJECT_STATE_FLYING)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(THROWN_OBJECT_STATE_FLYING) (void)
|
||
|
{
|
||
|
const float RATE = 15.0F;
|
||
|
|
||
|
Vector3 object_pos;
|
||
|
ThrownObject->Get_Position (&object_pos);
|
||
|
|
||
|
float dist = (object_pos - FlyingObjectDest).Length ();
|
||
|
float dist_percent = (dist / FlyingDist);
|
||
|
|
||
|
float percent = RATE * TimeManager::Get_Frame_Seconds ();
|
||
|
Vector3 move_vector = FlyingObjectVector * percent;
|
||
|
|
||
|
move_vector.Z += (dist_percent - 0.5F) * (4.0F * TimeManager::Get_Frame_Seconds ());
|
||
|
|
||
|
//
|
||
|
// Do the move and check to see if we hit anything
|
||
|
//
|
||
|
if (Fly_Move (ThrownObject, move_vector)) {
|
||
|
|
||
|
//
|
||
|
// Fake-destroy the object
|
||
|
//
|
||
|
OffenseObjectClass offense_obj (10000.0F, 1);
|
||
|
ThrownObject->Completely_Damaged (offense_obj);
|
||
|
ThrownObject->Set_Delete_Pending ();
|
||
|
ThrownObject = NULL;
|
||
|
|
||
|
//
|
||
|
// Now, revert back to the nothing state
|
||
|
//
|
||
|
ThrownObjectState.Set_State (THROWN_OBJECT_STATE_NONE);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_BEGIN(LIGHTNING_ROD_STATE_ACTIVE)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_BEGIN(LIGHTNING_ROD_STATE_ACTIVE) (void)
|
||
|
{
|
||
|
LightningRodStateTimer = 0;
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_END(LIGHTNING_ROD_STATE_ACTIVE)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_END(LIGHTNING_ROD_STATE_ACTIVE) (void)
|
||
|
{
|
||
|
//
|
||
|
// Hide all the arc effects
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
PhysClass *phys_obj = ArcObjects[index]->Peek_Physical_Object ();
|
||
|
phys_obj->Peek_Model ()->Set_Hidden (true);
|
||
|
ArcLifeRemaining[index] = 0;
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// STATE_IMPL_THINK(LIGHTNING_ROD_STATE_ACTIVE)
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::STATE_IMPL_THINK(LIGHTNING_ROD_STATE_ACTIVE) (void)
|
||
|
{
|
||
|
LightningRodStateTimer -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (LightningRodStateTimer <= 0) {
|
||
|
LightningRodStateTimer = 0.125F;
|
||
|
|
||
|
int count = LightningRodList.Count ();
|
||
|
int index0 = FreeRandom.Get_Int (count - 1);
|
||
|
int index1 = index0 + 1;
|
||
|
|
||
|
const Matrix3D &start_tm = LightningRodList[index0]->Peek_Model ()->Get_Bone_Transform ("BBZZZT");
|
||
|
const Matrix3D &end_tm = LightningRodList[index1]->Peek_Model ()->Get_Bone_Transform ("BBZZZT");
|
||
|
|
||
|
Add_Lightning_Arc (start_tm.Get_Translation (), end_tm.Get_Translation ());
|
||
|
|
||
|
//
|
||
|
// Randomly strike the mutant
|
||
|
//
|
||
|
if (FreeRandom.Get_Int (6) == 1) {
|
||
|
Add_Lightning_Arc (start_tm.Get_Translation (), RaveshawPos + Vector3 (0, 0, 1.0F));
|
||
|
|
||
|
//
|
||
|
// Play an electric sound.
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Elec_Twiddler", Get_Transform ());
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Randomly strike the player
|
||
|
//
|
||
|
int star_dist = (StarPos - TIBERIUM_POS).Length ();
|
||
|
if (FreeRandom.Get_Int (star_dist) == 1) {
|
||
|
|
||
|
//
|
||
|
// Apply 5 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));
|
||
|
Add_Lightning_Arc (end_tm.Get_Translation (), StarPos + Vector3 (0, 0, 1.0F));
|
||
|
|
||
|
//
|
||
|
// Play an electric sound.
|
||
|
//
|
||
|
WWAudioClass::Get_Instance ()->Create_Instant_Sound ("Rav_Elec_Twiddler", Matrix3D (StarPos));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Hide any arc-effects that have finished
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
if (ArcLifeRemaining[index] > 0) {
|
||
|
ArcLifeRemaining[index] -= TimeManager::Get_Frame_Seconds ();
|
||
|
if (ArcLifeRemaining[index] <= 0) {
|
||
|
PhysClass *phys_obj = ArcObjects[index]->Peek_Physical_Object ();
|
||
|
phys_obj->Peek_Model ()->Set_Hidden (true);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Apply_Bone_Collision_Damage
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
RaveshawBossGameObjClass::Apply_Bone_Collision_Damage (float damage_scale, 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 (damage_scale, 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.25F);
|
||
|
|
||
|
if (delta_vector.Z > 0.0F) {
|
||
|
delta_vector.Z = 0.5F;
|
||
|
delta_vector.Normalize ();
|
||
|
COMBAT_STAR->Peek_Physical_Object ()->As_Phys3Class ()->Apply_Impulse (delta_vector * 2.0F);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Play the hit sound...
|
||
|
//
|
||
|
Attach_Sound ("Fight Impact Sound Twiddler", "ROOTTRANSFORM");
|
||
|
}
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Get_Distance_From_Ground
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
float
|
||
|
RaveshawBossGameObjClass::Get_Distance_From_Ground (void)
|
||
|
{
|
||
|
const float MAX_DISTANCE = 100.0F;
|
||
|
float distance = 0.0F;
|
||
|
|
||
|
//
|
||
|
// Determine the start and end positions of the ray
|
||
|
//
|
||
|
Vector3 start;
|
||
|
Get_Position (&start);
|
||
|
|
||
|
Vector3 end = start - Vector3 (0, 0, MAX_DISTANCE);
|
||
|
LineSegClass ray (start, end);
|
||
|
|
||
|
//
|
||
|
// Cast the ray into the world
|
||
|
//
|
||
|
CastResultStruct res;
|
||
|
PhysRayCollisionTestClass raytest (ray, &res, DEFAULT_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL);
|
||
|
|
||
|
Peek_Physical_Object ()->Inc_Ignore_Counter ();
|
||
|
COMBAT_SCENE->Cast_Ray (raytest);
|
||
|
Peek_Physical_Object ()->Dec_Ignore_Counter ();
|
||
|
|
||
|
//
|
||
|
// Calculate where in the world this would hit
|
||
|
//
|
||
|
if (res.StartBad == false) {
|
||
|
distance = (res.Fraction * MAX_DISTANCE);
|
||
|
}
|
||
|
|
||
|
return distance;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Create_Stealth_Soldier
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Create_Stealth_Soldier (const Matrix3D &tm)
|
||
|
{
|
||
|
//
|
||
|
// Create the stealth soldier
|
||
|
//
|
||
|
PhysicalGameObj *phys_game_obj = ObjectLibraryManager::Create_Object ("Raveshaw Boss Fodder");
|
||
|
WWASSERT (phys_game_obj != NULL);
|
||
|
StealthSoldier = phys_game_obj;
|
||
|
|
||
|
//
|
||
|
// Position the stealth soldier accordingly
|
||
|
//
|
||
|
SoldierGameObj *soldier = phys_game_obj->As_SoldierGameObj ();
|
||
|
soldier->Set_Transform (tm);
|
||
|
|
||
|
//
|
||
|
// Configure the stealth effect to be "on" (stealthed)
|
||
|
//
|
||
|
StealthEffect->Set_Current_State (1.0F);
|
||
|
StealthEffect->Set_Target_State (0.0F);
|
||
|
|
||
|
//
|
||
|
// Add the effect to the object
|
||
|
//
|
||
|
soldier->Peek_Physical_Object ()->Add_Effect_To_Me (StealthEffect);
|
||
|
|
||
|
//
|
||
|
// Disable physics for this soldier
|
||
|
//
|
||
|
soldier->Peek_Physical_Object ()->Enable_Objects_Simulation (false);
|
||
|
soldier->Start_Observers ();
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Link_Thrown_Object_To_Hands
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Link_Thrown_Object_To_Hands (void)
|
||
|
{
|
||
|
if (ThrownObject == NULL) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the transforms of Raveshaw's hands
|
||
|
//
|
||
|
const Matrix3D &r_hand_tm = Peek_Model ()->Get_Bone_Transform ("C R HAND");
|
||
|
const Matrix3D &l_hand_tm = Peek_Model ()->Get_Bone_Transform ("C L HAND");
|
||
|
|
||
|
//Vector3 z_axis = (l_hand_tm.Get_Translation () - r_hand_tm.Get_Translation ());
|
||
|
//z_axis.Normalize ();
|
||
|
|
||
|
Vector3 r_hand_pos = r_hand_tm.Get_Translation ();
|
||
|
Vector3 l_hand_pos = l_hand_tm.Get_Translation ();
|
||
|
Vector3 delta_vector = l_hand_pos - r_hand_pos;
|
||
|
|
||
|
Matrix3D obj_tm;
|
||
|
//obj_tm.Look_At (r_hand_pos, r_hand_pos - delta_vector, 0);
|
||
|
Matrix3D::Multiply (r_hand_tm, RelObjTM, &obj_tm);
|
||
|
|
||
|
ThrownObject->Set_Transform (obj_tm);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Link_Player_To_Hands
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Link_Player_To_Hands (void)
|
||
|
{
|
||
|
if (COMBAT_STAR == NULL) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the transform of Raveshaw's hand
|
||
|
//
|
||
|
const Matrix3D &hand_tm = Peek_Model ()->Get_Bone_Transform ("C L HAND");
|
||
|
|
||
|
const Matrix3D &neck_tm = COMBAT_STAR->Peek_Model ()->Get_Bone_Transform ("C NECK");
|
||
|
const Matrix3D &soldier_tm = COMBAT_STAR->Get_Transform ();
|
||
|
|
||
|
//
|
||
|
// Determine where to position the stealth soldier so he's embedded in Raveshaw's hand
|
||
|
//
|
||
|
Vector3 hand_pos = hand_tm.Get_Translation ();
|
||
|
Vector3 delta_pos = neck_tm.Get_Translation () - soldier_tm.Get_Translation ();
|
||
|
Vector3 new_pos = hand_pos - delta_pos;
|
||
|
|
||
|
//
|
||
|
// Disable collision on Raveshaw
|
||
|
//
|
||
|
Peek_Physical_Object ()->Inc_Ignore_Counter ();
|
||
|
COMBAT_STAR->Peek_Physical_Object ()->Inc_Ignore_Counter ();
|
||
|
|
||
|
//
|
||
|
// Get the player's collision box
|
||
|
//
|
||
|
AABoxClass collision_box;
|
||
|
collision_box = COMBAT_STAR->Peek_Physical_Object ()->As_HumanPhysClass ()->Get_Collision_Box ();
|
||
|
collision_box.Center += StarPos;
|
||
|
|
||
|
//
|
||
|
// Calculate what vector we'll be teleporting the player through
|
||
|
//
|
||
|
Vector3 vector = (new_pos - StarPos);
|
||
|
|
||
|
//
|
||
|
// Check to see if we would hit something if we do this
|
||
|
//
|
||
|
CastResultStruct result;
|
||
|
PhysAABoxCollisionTestClass col_test (collision_box, vector, &result, DEFAULT_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL);
|
||
|
bool retval = COMBAT_SCENE->Cast_AABox (col_test);
|
||
|
if (retval == false && result.StartBad == false && result.Fraction == 1.0F) {
|
||
|
|
||
|
//
|
||
|
// New position should be fine, so allow the position change
|
||
|
//
|
||
|
Matrix3D new_soldier_tm (new_pos);
|
||
|
COMBAT_STAR->Set_Transform (new_soldier_tm);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Restore collision on Raveshaw
|
||
|
//
|
||
|
Peek_Physical_Object ()->Dec_Ignore_Counter ();
|
||
|
COMBAT_STAR->Peek_Physical_Object ()->Dec_Ignore_Counter ();
|
||
|
|
||
|
|
||
|
//
|
||
|
// Get the target relative to the head
|
||
|
//
|
||
|
//Vector3 rav_head_pos = Peek_Model ()->Get_Bone_Transform ("C HEAD").Get_Translation ();
|
||
|
|
||
|
//COMBAT_STAR->Set_Targeting (rav_head_pos);
|
||
|
|
||
|
/*Vector3 rav_head_rel;
|
||
|
Matrix3D::Inverse_Transform_Vector (new_soldier_tm, rav_head_pos, &rav_head_rel);
|
||
|
|
||
|
float angle = ::atan2 (rav_head_rel.Y, rav_head_rel.X);
|
||
|
new_soldier_tm.Rotate_Z (angle - DEG_TO_RADF (90.0F));*/
|
||
|
|
||
|
//
|
||
|
// Choose a random orientation for the soldier
|
||
|
//
|
||
|
//new_soldier_tm.Rotate_Z (WWMath::Random_Float (0, DEG_TO_RADF (319.0F)));
|
||
|
|
||
|
|
||
|
/*Matrix3D world_to_soldier_tm;
|
||
|
soldier_tm.Get_Orthogonal_Inverse (world_to_soldier_tm);
|
||
|
|
||
|
Matrix3D neck_rel_to_sol_tm = neck_tm * world_to_soldier_tm;
|
||
|
|
||
|
Matrix3D sol_rel_to_neck_tm;
|
||
|
neck_rel_to_sol_tm.Get_Orthogonal_Inverse (sol_rel_to_neck_tm);
|
||
|
|
||
|
Matrix3D new_soldier_tm (hand_tm * sol_rel_to_neck_tm);*/
|
||
|
|
||
|
//Matrix3D test_tm = hand_tm * sol_rel_to_neck_tm;
|
||
|
//Matrix3D new_soldier_tm (test_tm.Get_Translation ());
|
||
|
//new_soldier_tm = hand_tm * sol_rel_to_neck_tm;
|
||
|
|
||
|
|
||
|
/*Matrix3D soldier_to_neck_tm;
|
||
|
neck_to_soldier_tm.Get_Orthogonal_Inverse (soldier_to_neck_tm);
|
||
|
|
||
|
|
||
|
Matrix3D world_to_neck_tm;
|
||
|
neck_tm.Get_Orthogonal_Inverse (world_to_neck_tm);
|
||
|
|
||
|
Matrix3D neck_to_soldier_tm = soldier_tm * world_to_neck_tm;
|
||
|
|
||
|
Matrix3D
|
||
|
Matrix3D new_soldier_tm = (hand_tm * neck_to_soldier_tm);*/
|
||
|
|
||
|
//COMBAT_STAR->Set_Transform (new_soldier_tm);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Link_Stealth_Soldier_To_Hand
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Link_Stealth_Soldier_To_Hand (void)
|
||
|
{
|
||
|
//
|
||
|
// Check to see if the stealth soldier has been destroyed...
|
||
|
//
|
||
|
SoldierGameObj *stealth_soldier = Peek_Stealth_Soldier ();
|
||
|
if (stealth_soldier == NULL) {
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the transform of Raveshaw's hand
|
||
|
//
|
||
|
const Matrix3D &hand_tm = Peek_Model ()->Get_Bone_Transform ("C L HAND");
|
||
|
|
||
|
const Matrix3D &neck_tm = stealth_soldier->Peek_Model ()->Get_Bone_Transform ("C NECK");
|
||
|
const Matrix3D &soldier_tm = stealth_soldier->Get_Transform ();
|
||
|
|
||
|
//
|
||
|
// Determine where to position the stealth soldier so he's embedded in Raveshaw's hand
|
||
|
//
|
||
|
Vector3 hand_pos = hand_tm.Get_Translation ();
|
||
|
Vector3 delta_pos = neck_tm.Get_Translation () - soldier_tm.Get_Translation ();
|
||
|
Vector3 new_pos = hand_pos - delta_pos;
|
||
|
|
||
|
Matrix3D new_soldier_tm (new_pos);
|
||
|
|
||
|
//
|
||
|
// Choose a random orientation for the soldier
|
||
|
//
|
||
|
//new_soldier_tm.Rotate_Z (WWMath::Random_Float (0, DEG_TO_RADF (319.0F)));
|
||
|
|
||
|
|
||
|
/*Matrix3D world_to_soldier_tm;
|
||
|
soldier_tm.Get_Orthogonal_Inverse (world_to_soldier_tm);
|
||
|
|
||
|
Matrix3D neck_rel_to_sol_tm = neck_tm * world_to_soldier_tm;
|
||
|
|
||
|
Matrix3D sol_rel_to_neck_tm;
|
||
|
neck_rel_to_sol_tm.Get_Orthogonal_Inverse (sol_rel_to_neck_tm);
|
||
|
|
||
|
Matrix3D new_soldier_tm (hand_tm * sol_rel_to_neck_tm);*/
|
||
|
|
||
|
//Matrix3D test_tm = hand_tm * sol_rel_to_neck_tm;
|
||
|
//Matrix3D new_soldier_tm (test_tm.Get_Translation ());
|
||
|
//new_soldier_tm = hand_tm * sol_rel_to_neck_tm;
|
||
|
|
||
|
|
||
|
/*Matrix3D soldier_to_neck_tm;
|
||
|
neck_to_soldier_tm.Get_Orthogonal_Inverse (soldier_to_neck_tm);
|
||
|
|
||
|
|
||
|
Matrix3D world_to_neck_tm;
|
||
|
neck_tm.Get_Orthogonal_Inverse (world_to_neck_tm);
|
||
|
|
||
|
Matrix3D neck_to_soldier_tm = soldier_tm * world_to_neck_tm;
|
||
|
|
||
|
Matrix3D
|
||
|
Matrix3D new_soldier_tm = (hand_tm * neck_to_soldier_tm);*/
|
||
|
|
||
|
stealth_soldier->Set_Transform (new_soldier_tm);
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Fly_Move
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
bool
|
||
|
RaveshawBossGameObjClass::Fly_Move (PhysicalGameObj *game_obj, const Vector3 &vector)
|
||
|
{
|
||
|
Vector3 curr_pos;
|
||
|
game_obj->Get_Position (&curr_pos);
|
||
|
|
||
|
//
|
||
|
// Get the object's collision box
|
||
|
//
|
||
|
AABoxClass collision_box;
|
||
|
|
||
|
if (game_obj->As_SoldierGameObj () != NULL) {
|
||
|
collision_box = game_obj->Peek_Physical_Object ()->As_HumanPhysClass ()->Get_Collision_Box ();
|
||
|
collision_box.Center += curr_pos;
|
||
|
} else {
|
||
|
collision_box = game_obj->Peek_Model ()->Get_Bounding_Box ();
|
||
|
}
|
||
|
|
||
|
if (game_obj != COMBAT_STAR) {
|
||
|
collision_box.Extent.Z -= 0.25F;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Disable collision on Raveshaw
|
||
|
//
|
||
|
Peek_Physical_Object ()->Inc_Ignore_Counter ();
|
||
|
game_obj->Peek_Physical_Object ()->Inc_Ignore_Counter ();
|
||
|
|
||
|
//
|
||
|
// Check to see if we've hit something
|
||
|
//
|
||
|
CastResultStruct result;
|
||
|
PhysAABoxCollisionTestClass col_test (collision_box, vector, &result, DEFAULT_COLLISION_GROUP, COLLISION_TYPE_PHYSICAL);
|
||
|
|
||
|
//
|
||
|
// Find where we hit
|
||
|
//
|
||
|
bool retval = COMBAT_SCENE->Cast_AABox (col_test);
|
||
|
if (result.StartBad == false) {
|
||
|
|
||
|
//
|
||
|
// Calculate where to move to...
|
||
|
//
|
||
|
Vector3 new_pos = curr_pos + (vector * (result.Fraction * 0.99F));
|
||
|
|
||
|
//
|
||
|
// Move the object
|
||
|
//
|
||
|
game_obj->Set_Position (new_pos);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Restore collision to Raveshaw
|
||
|
//
|
||
|
Peek_Physical_Object ()->Dec_Ignore_Counter ();
|
||
|
game_obj->Peek_Physical_Object ()->Dec_Ignore_Counter ();
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Find_Object_To_Throw
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
SimpleGameObj *
|
||
|
RaveshawBossGameObjClass::Find_Object_To_Throw (void)
|
||
|
{
|
||
|
if (COMBAT_STAR == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
SimpleGameObj *best_object = NULL;
|
||
|
float best_object_rating = 100.0F;
|
||
|
|
||
|
//
|
||
|
// Loop over all the game objects in the world (looking for simple game objects)
|
||
|
//
|
||
|
SLNode<BaseGameObj> *obj_node = NULL;
|
||
|
for (obj_node = GameObjManager::Get_Game_Obj_List ()->Head (); obj_node; obj_node = obj_node->Next ()) {
|
||
|
|
||
|
//
|
||
|
// Is this a simple game object?
|
||
|
//
|
||
|
PhysicalGameObj *phys_game_obj = obj_node->Data ()->As_PhysicalGameObj ();
|
||
|
if (phys_game_obj != NULL && phys_game_obj->As_SimpleGameObj () != NULL) {
|
||
|
SimpleGameObj *object = phys_game_obj->As_SimpleGameObj ();
|
||
|
if (object != NULL) {
|
||
|
|
||
|
//
|
||
|
// Is this one of Raveshaw's throwable objects?
|
||
|
//
|
||
|
const StringClass &name = object->Get_Definition ().Get_Name ();
|
||
|
if (::strstr (name, "(Raveshaw Ammo)") != NULL) {
|
||
|
|
||
|
//
|
||
|
// Get the position of the object
|
||
|
//
|
||
|
Vector3 object_pos;
|
||
|
object->Get_Position (&object_pos);
|
||
|
|
||
|
//
|
||
|
// Is this object in the boss area?
|
||
|
//
|
||
|
object_pos.Z = 0;
|
||
|
|
||
|
//
|
||
|
// Calculate how far this object is from Raveshaw and the player
|
||
|
//
|
||
|
float dist_to_me = (object_pos - RaveshawPos).Length () / 10.0F;
|
||
|
float dist_to_star = (object_pos - StarPos).Length () / 10.0F;
|
||
|
dist_to_star = WWMath::Clamp (1.0F - dist_to_star, 0.0F, 1.0F);
|
||
|
|
||
|
//
|
||
|
// Is this the object that's closest to Raveshaw and farthest from the player?
|
||
|
//
|
||
|
float rating = (dist_to_me * 0.5F) + (dist_to_star * 0.5F);
|
||
|
if (rating < best_object_rating) {
|
||
|
best_object = object;
|
||
|
best_object_rating = rating;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return best_object;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Determine_New_Overall_State
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Determine_New_Overall_State (void)
|
||
|
{
|
||
|
float health = DefenseObject.Get_Health ();
|
||
|
float health_percent = health / DefenseObject.Get_Health_Max ();
|
||
|
|
||
|
if (health_percent <= 0.05F) {
|
||
|
|
||
|
//
|
||
|
// Retreat to the catwalk if we're mostly damaged
|
||
|
//
|
||
|
if ( OverallState.Get_State () != OVERALL_STATE_JUMP_TO_CATWALK ||
|
||
|
OverallState.Get_State () != OVERALL_STATE_ON_CATWALK ||
|
||
|
OverallState.Get_State () != OVERALL_STATE_DEATH_SEQUENCE)
|
||
|
{
|
||
|
OverallState.Set_State (OVERALL_STATE_JUMP_TO_CATWALK);
|
||
|
}
|
||
|
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// Should he heal himself?
|
||
|
//
|
||
|
int possibility = (10.0F * health_percent) + 0.5F;
|
||
|
bool go_heal = (health_percent <= 0.75F && possibility > 0) && (FreeRandom.Get_Int (possibility) == 0);
|
||
|
if (go_heal) {
|
||
|
OverallState.Set_State (OVERALL_STATE_HEALING);
|
||
|
} else {
|
||
|
|
||
|
//
|
||
|
// How far away is the player?
|
||
|
//
|
||
|
float dist2 = (RaveshawPos - StarPos).Length2 ();
|
||
|
|
||
|
//
|
||
|
// Roll a random die to determine which action to take
|
||
|
//
|
||
|
int choice = FreeRandom.Get_Int (100);
|
||
|
if (choice < 35 && dist2 > 16.0F) {
|
||
|
OverallState.Set_State (OVERALL_STATE_THROWING_SOLDIER);
|
||
|
} else if (choice < 60 && (ThrownObject == NULL)) {
|
||
|
OverallState.Set_State (OVERALL_STATE_THROWING_OBJECT);
|
||
|
} else if (choice < 80) {
|
||
|
OverallState.Set_State (OVERALL_STATE_CHASE_STAR);
|
||
|
} else {
|
||
|
OverallState.Set_State (OVERALL_STATE_JUMP_TO_CATWALK);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Jump_To_Point
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Jump_To_Point (const Vector3 &pos)
|
||
|
{
|
||
|
//
|
||
|
// Begin the jump state (if necessary)
|
||
|
//
|
||
|
if (JumpState.Get_State () == JUMP_STATE_NONE) {
|
||
|
CurrentJumpToPos = pos;
|
||
|
JumpState.Set_State (JUMP_STATE_CROUCHING);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Collect_Lightning_Rods
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Collect_Lightning_Rods (void)
|
||
|
{
|
||
|
LightningRodList.Delete_All ();
|
||
|
|
||
|
//
|
||
|
// Compute the box where the lightning rods in question should live
|
||
|
//
|
||
|
AABoxClass box;
|
||
|
box.Center = TIBERIUM_POS;
|
||
|
box.Extent.Set (40.0F, 40.0F, 20.0F);
|
||
|
|
||
|
//
|
||
|
// Collect all the static objects in this box
|
||
|
//
|
||
|
NonRefPhysListClass obj_list;
|
||
|
COMBAT_SCENE->Collect_Objects (box, true, false, &obj_list);
|
||
|
|
||
|
//
|
||
|
// Loop over all the objects
|
||
|
//
|
||
|
NonRefPhysListIterator it (&obj_list);
|
||
|
for (it.First (); !it.Is_Done (); it.Next ()) {
|
||
|
DamageableStaticPhysClass *phys_obj = it.Peek_Obj ()->As_DamageableStaticPhysClass ();
|
||
|
|
||
|
//
|
||
|
// Add this object to our list
|
||
|
//
|
||
|
if (phys_obj != NULL) {
|
||
|
if (phys_obj->Peek_Model ()->Get_Bone_Index ("BBZZZT") > 0) {
|
||
|
LightningRodList.Add (phys_obj);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Sort the lightning rods based on the angle they make with the tiberium
|
||
|
//
|
||
|
int rod_count = LightningRodList.Count ();
|
||
|
if (rod_count > 0) {
|
||
|
::qsort (&LightningRodList[0], rod_count, sizeof (DamageableStaticPhysClass *), fnSortLightningRodsCallback);
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Create_Arc_Effects
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Create_Arc_Effects (void)
|
||
|
{
|
||
|
//
|
||
|
// Create the simple game object's that we'll use to display the lightning effect
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
ArcObjects[index] = (SimpleGameObj *)ObjectLibraryManager::Create_Object ("Arc Effect");
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Prepare_Arc_Effect_Data
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Prepare_Arc_Effect_Data (void)
|
||
|
{
|
||
|
//
|
||
|
// Create the simple game object's that we'll use to display the lightning effect
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
if ( ArcObjects[index]->Peek_Physical_Object () != NULL &&
|
||
|
ArcObjects[index]->Peek_Physical_Object ()->Peek_Model () != NULL)
|
||
|
{
|
||
|
ArcObjects[index]->Peek_Physical_Object ()->Peek_Model ()->Set_Hidden (true);
|
||
|
}
|
||
|
|
||
|
ArcLifeRemaining[index] = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get information about the model
|
||
|
//
|
||
|
SimpleGameObj *temp_obj = (SimpleGameObj *)ObjectLibraryManager::Create_Object ("Arc Effect");
|
||
|
if (temp_obj != NULL && temp_obj->Peek_Model () != NULL) {
|
||
|
RenderObjClass *model = temp_obj->Peek_Model ();
|
||
|
|
||
|
//
|
||
|
// Store the original transforms of each bone
|
||
|
//
|
||
|
for (int index = 0; index < BONE_COUNT; index ++) {
|
||
|
Bones[index] = model->Get_Bone_Transform (ARC_BONE_NAMES[index]);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Lookup the original transform of the end-bone
|
||
|
//
|
||
|
int end_index = model->Get_Bone_Index ("bone_end");
|
||
|
EndTM = model->Get_Bone_Transform (end_index);
|
||
|
|
||
|
//
|
||
|
// Get rid of the temporary object
|
||
|
//
|
||
|
temp_obj->Peek_Model ()->Set_Hidden (true);
|
||
|
temp_obj->Set_Delete_Pending ();
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
//BBZZZT
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Add_Lightning_Arc
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Add_Lightning_Arc (const Vector3 &start_point, const Vector3 &end_point)
|
||
|
{
|
||
|
//
|
||
|
// Try to find an available welding-arc
|
||
|
//
|
||
|
for (int index = 0; index < ARC_OBJ_COUNT; index ++) {
|
||
|
if ((ArcLifeRemaining[index] <= 0)) {
|
||
|
|
||
|
//
|
||
|
// Get the model of the object we'll be displaying
|
||
|
//
|
||
|
RenderObjClass *model = ArcObjects[index]->Peek_Physical_Object ()->Peek_Model ();
|
||
|
|
||
|
//
|
||
|
// Make the object "look" at its endpoint
|
||
|
//
|
||
|
Matrix3D start_tm;
|
||
|
start_tm.Obj_Look_At (start_point, end_point, 0);
|
||
|
ArcObjects[index]->Peek_Physical_Object ()->Set_Transform (start_tm);
|
||
|
|
||
|
//
|
||
|
// Now scale the bone's that control the length of the arc so it
|
||
|
// will fit perfectly between the start and endpoints.
|
||
|
//
|
||
|
for (int bone_index = 0; bone_index < BONE_COUNT; bone_index ++) {
|
||
|
|
||
|
float percent = WWMath::Fabs (Bones[bone_index].Get_Translation ().X / EndTM.Get_Translation ().X);
|
||
|
Vector3 new_pos = start_point + (end_point - start_point) * percent;
|
||
|
|
||
|
//
|
||
|
// Calculate the world space position of the bone
|
||
|
//
|
||
|
Vector3 world_space_pos = start_tm * Bones[bone_index].Get_Translation ();
|
||
|
Vector3 world_space_offset = new_pos - world_space_pos;
|
||
|
Matrix3D bone_tm (world_space_offset);
|
||
|
|
||
|
//
|
||
|
// Control the bone
|
||
|
//
|
||
|
int bone_id = model->Get_Bone_Index (ARC_BONE_NAMES[bone_index]);
|
||
|
model->Capture_Bone (bone_id);
|
||
|
model->Control_Bone (bone_id, bone_tm, true);
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Calculate the world space position of the endpoint
|
||
|
//
|
||
|
Vector3 world_space_end_pos = start_tm * EndTM.Get_Translation ();
|
||
|
Vector3 world_space_offset = end_point - world_space_end_pos;
|
||
|
Matrix3D end_tm (world_space_offset);
|
||
|
|
||
|
//
|
||
|
// Control the ending bone
|
||
|
//
|
||
|
int end_index = model->Get_Bone_Index ("bone_end");
|
||
|
model->Capture_Bone (end_index);
|
||
|
model->Control_Bone (end_index, end_tm, true);
|
||
|
|
||
|
//
|
||
|
// Start the animation
|
||
|
//
|
||
|
ArcLifeRemaining[index] = 3.0F;
|
||
|
HAnimClass *anim = model->Peek_Animation ();
|
||
|
if (anim != NULL) {
|
||
|
model->Set_Animation (anim, 0, RenderObjClass::ANIM_MODE_ONCE);
|
||
|
ArcLifeRemaining[index] = anim->Get_Total_Time ();
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Show the model
|
||
|
//
|
||
|
model->Set_Hidden (false);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|
||
|
|
||
|
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// fnSortLightningRodsCallback
|
||
|
//
|
||
|
////////////////////////////////////////////////////////////////
|
||
|
int __cdecl
|
||
|
RaveshawBossGameObjClass::fnSortLightningRodsCallback
|
||
|
(
|
||
|
const void *elem1,
|
||
|
const void *elem2
|
||
|
)
|
||
|
{
|
||
|
WWASSERT (elem1 != NULL);
|
||
|
WWASSERT (elem2 != NULL);
|
||
|
DamageableStaticPhysClass *rod1 = *((DamageableStaticPhysClass **)elem1);
|
||
|
DamageableStaticPhysClass *rod2 = *((DamageableStaticPhysClass **)elem2);
|
||
|
|
||
|
//
|
||
|
// Sort the rods based on the angle they make around the tiberium
|
||
|
//
|
||
|
int result = 0;
|
||
|
if (rod1 != rod2) {
|
||
|
|
||
|
Vector3 rod1_pos;
|
||
|
Vector3 rod2_pos;
|
||
|
rod1->Get_Position (&rod1_pos);
|
||
|
rod2->Get_Position (&rod2_pos);
|
||
|
|
||
|
rod1_pos -= TIBERIUM_POS;
|
||
|
rod2_pos -= TIBERIUM_POS;
|
||
|
|
||
|
//
|
||
|
// Compute the angle assuming the tiberium to be the center of a circle
|
||
|
//
|
||
|
float angle1 = WWMath::Atan2 (rod1_pos.Y, rod1_pos.X);
|
||
|
float angle2 = WWMath::Atan2 (rod2_pos.Y, rod2_pos.X);
|
||
|
angle1 = WWMath::Wrap (angle1 + DEG_TO_RADF (90.0F), 0.0F, DEG_TO_RADF (360.0F));
|
||
|
angle2 = WWMath::Wrap (angle2 + DEG_TO_RADF (90.0F), 0.0F, DEG_TO_RADF (360.0F));
|
||
|
|
||
|
//
|
||
|
// Sort based on this angle
|
||
|
//
|
||
|
if (angle1 < angle2) {
|
||
|
result = -1;
|
||
|
} else if (angle1 > angle2) {
|
||
|
result = 1;
|
||
|
} else {
|
||
|
result = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
//
|
||
|
// Find_Death_Facing_Pos
|
||
|
//
|
||
|
///////////////////////////////////////////////////////////////////////////
|
||
|
void
|
||
|
RaveshawBossGameObjClass::Find_Death_Facing_Pos (Vector3 *facing_pos)
|
||
|
{
|
||
|
float best_dist2 = 99999.0F;
|
||
|
|
||
|
//
|
||
|
// Get the catwalk waypath
|
||
|
//
|
||
|
WaypathClass *waypath = PathfindClass::Get_Instance ()->Find_Waypath (CATWALK_WAYPATH_ID);
|
||
|
WWASSERT (waypath != NULL);
|
||
|
|
||
|
//
|
||
|
// Now find the closest point which is in-between the waypath points
|
||
|
//
|
||
|
for (int index = 0; index < waypath->Get_Point_Count (); index ++) {
|
||
|
|
||
|
//
|
||
|
// Determine what the current and next waypath points are
|
||
|
//
|
||
|
int curr_index = index;
|
||
|
int next_index = index + 1;
|
||
|
if (index + 1 >= waypath->Get_Point_Count ()) {
|
||
|
next_index = 0;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Get the position of the current and next waypoint
|
||
|
//
|
||
|
Vector3 curr_waypath_pos = waypath->Get_Point (curr_index)->Get_Position ();
|
||
|
Vector3 next_waypath_pos = waypath->Get_Point (next_index)->Get_Position ();
|
||
|
|
||
|
//
|
||
|
// Evaluate this jump to position (is it the closest?)
|
||
|
//
|
||
|
Vector3 jump_to_pos = curr_waypath_pos + ((next_waypath_pos - curr_waypath_pos) * 0.5F);
|
||
|
Vector3 dir_vector = (RaveshawPos - jump_to_pos);
|
||
|
dir_vector.Z = 0;
|
||
|
float dist2 = dir_vector.Length2 ();
|
||
|
if (dist2 < best_dist2) {
|
||
|
best_dist2 = dist2;
|
||
|
(*facing_pos) = curr_waypath_pos;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return ;
|
||
|
}
|