The-Simpsons-Hit-and-Run/game/code/worldsim/character/charactermanager.cpp

2488 lines
76 KiB
C++

#include <worldsim/character/charactermanager.h>
#include <worldsim/character/character.h>
#include <worldsim/character/characterrenderable.h>
#include <worldsim/worldphysicsmanager.h>
#include <worldsim/vehiclecentral.h>
#include <worldsim/redbrick/vehicle.h>
#include <ai/actionbuttonmanager.h>
#include <ai/actionbuttonhandler.h>
#include <events/eventenum.h>
#include <events/eventmanager.h>
#include <meta/locatorevents.h>
#include <meta/eventlocator.h>
#include <meta/triggervolume.h>
#include <meta/carstartlocator.h>
#include <camera/supercamcentral.h>
#include <camera/supercammanager.h>
#include <memory/srrmemory.h>
#include <raddebug.hpp>
#include <raddebugwatch.hpp>
#include <p3d/anim/drawablepose.hpp>
#include <p3d/shader.hpp>
#include <p3d/shadow.hpp>
// Choreo includes.
//
#include <p3d/anim/pose.hpp>
#include <choreo/bank.hpp>
#include <choreo/load.hpp>
#include <choreo/puppet.hpp>
#include <choreo/utility.hpp>
#include <simcommon/simstate.hpp>
#include <simcommon/simulatedobject.hpp>
#include <simcollision/collisionobject.hpp>
#include <console/console.h>
#include <render/RenderManager/RenderManager.h>
#include <render/RenderManager/RenderLayer.h>
// Temp hack to get NPCs in.
// TBJ [9/3/2002]
//
#include <mission/gameplaymanager.h>
#include <constants/maxplayers.h>
#include <stdlib.h>
#include <debug/profiler.h>
#include <worldsim/avatarmanager.h>
#include <radtime.hpp>
#include <p3d/anim/skeleton.hpp>
#include <ai/sequencer/actioncontroller.h>
#include <ai/sequencer/action.h>
#include <ai/sequencer/sequencer.h>
#include <presentation/blinker.h>
#include <presentation/gui/ingame/guimanageringame.h>
#include <presentation/gui/ingame/guiscreenhud.h>
#include <mission/charactersheet/charactersheetmanager.h>
CharacterManager* CharacterManager::spCharacterManager = 0;
/************ OUTPUT_TIMES FOR DLOP **********/
//#define OUTPUT_TIMES
/**********************************************/
// Init the character tunables.
//
// Statics.
//
float CharacterTune::sfLocoRotateRate;
float CharacterTune::sfLocoAcceleration;
float CharacterTune::sfLocoDecceleration;
bool CharacterTune::bLocoTest;
float CharacterTune::sfAirRotateRate;
float CharacterTune::sfAirAccelScale;
float CharacterTune::sfAirGravity;
float CharacterTune::sfStompGravityScale;
float CharacterTune::sfDashBurstMax;
float CharacterTune::sfDashAcceleration;
float CharacterTune::sfDashDeceleration;
float CharacterTune::sfJumpHeight;
float CharacterTune::sfDoubleJumpHeight;
float CharacterTune::sfDoubleJumpAllowUp;
float CharacterTune::sfDoubleJumpAllowDown;
float CharacterTune::sfHighJumpHeight;
float CharacterTune::sfMaxSpeed;
float CharacterTune::sfTurboRotateRate;
float CharacterTune::sfGetInOutOfCarAnimSpeed;
rmt::Vector CharacterTune::sGetInPosition;
float CharacterTune::sGetInHeightThreshold;
float CharacterTune::sGetInOpenDelay;
float CharacterTune::sGetInOpenSpeed;
float CharacterTune::sGetInCloseDelay;
float CharacterTune::sGetInCloseSpeed;
float CharacterTune::sGetOutOpenDelay;
float CharacterTune::sGetOutOpenSpeed;
float CharacterTune::sGetOutCloseDelay;
float CharacterTune::sGetOutCloseSpeed;
float CharacterTune::sfKickingForce;
float CharacterTune::sfSlamForce;
// How long in seconds that the character will get shocked for
float CharacterTune::sfShockTime;
bool CharacterManager::sbFixedSimRate;
static const unsigned INVALID_LOAD = 0xffffffff;
Blinker g_Blinkers[ 64 ]; //should match max_characters
/*
==============================================================================
CharacterManager::CreateInstance
==============================================================================
Description: Comment
Parameters: ( void )
Return: CharacterManager
=============================================================================
*/
CharacterManager* CharacterManager::CreateInstance( void )
{
rAssertMsg( spCharacterManager == 0, "CharacterManager already created.\n" );
#ifdef RAD_GAMECUBE
spCharacterManager = new ( GMA_GC_VMM ) CharacterManager;
#else
spCharacterManager = new ( GMA_PERSISTENT ) CharacterManager;
#endif
return( spCharacterManager );
}
/*
==============================================================================
CharacterManager::GetInstance
==============================================================================
Description: Comment
Parameters: ( void )
Return: CharacterManager
=============================================================================
*/
CharacterManager* CharacterManager::GetInstance( void )
{
rAssertMsg( spCharacterManager != 0, "CharacterManager has not been created yet.\n" );
return spCharacterManager;
}
/*
==============================================================================
CharacterManager::DestroyInstance
==============================================================================
Description: Comment
Parameters: ( void )
Return: void
=============================================================================
*/
void CharacterManager::DestroyInstance( void )
{
rAssertMsg( spCharacterManager != 0, "CharacterManager has not been created.\n" );
delete ( GMA_PERSISTENT, spCharacterManager );
}
/*
==============================================================================
CharacterManager::CharacterManager
==============================================================================
Description: Comment
Parameters: ( void )
Return: CharacterManager
=============================================================================
*/
CharacterManager::CharacterManager( void )
{
int i;
for ( i = 0; i < MAX_CHARACTERS; i++ )
{
mpCharacter[ i ] = 0;
mGarbage[i] = false;
}
GetEventManager()->AddListener( this, (EventEnum)( EVENT_LOCATOR + LocatorEvent::CAR_DOOR ) );
GetEventManager()->AddListener( this, (EventEnum)( EVENT_LOCATOR + LocatorEvent::BOUNCEPAD ) );
GetEventManager()->AddListener( this, (EventEnum)( EVENT_LOCATOR + LocatorEvent::GENERIC_BUTTON_HANDLER_EVENT ) );
GetEventManager()->AddListener( this, EVENT_DEATH_VOLUME_SCREEN_BLANK );
GetEventManager()->AddListener( this, EVENT_STAGE_COMPLETE );
GetEventManager()->AddListener( this, EVENT_MISSION_SUCCESS );
GetEventManager()->AddListener( this, EVENT_CARD_COLLECTED );
GetEventManager()->AddListener( this, EVENT_MISSION_CHARACTER_RESET );
GetEventManager()->AddListener( this, EVENT_GETINTOVEHICLE_START );
GetEventManager()->AddListener( this, EVENT_GETOUTOFVEHICLE_END );
GetEventManager()->AddListener( this, EVENT_TOGGLE_FIRSTPERSON );
CharacterTune::sfLocoRotateRate = 10.0f;
CharacterTune::sfLocoAcceleration = 20.0f;
CharacterTune::sfLocoDecceleration = -10.0f;
CharacterTune::bLocoTest = false;
CharacterTune::sfAirRotateRate = 4.0f;
CharacterTune::sfAirAccelScale = 0.078f; //was .1
CharacterTune::sfAirGravity = -25.0f; //was -30
CharacterTune::sfStompGravityScale = 3.22f;
CharacterTune::sfJumpHeight = 1.9f; //was 1.65
CharacterTune::sfDoubleJumpHeight = 1.0f;
CharacterTune::sfDoubleJumpAllowUp = 2.0f;
CharacterTune::sfDoubleJumpAllowDown = 12.0f; //was 6
CharacterTune::sfHighJumpHeight = 1.9f;
CharacterTune::sfDashBurstMax = 4.0f; // 7.0
CharacterTune::sfDashAcceleration = 200.0f;
CharacterTune::sfDashDeceleration = 200.0f;
CharacterTune::sfMaxSpeed = 4.0f;
CharacterTune::sGetInPosition.Set( 1.05f, 0.0f, -0.86f );
CharacterTune::sGetInHeightThreshold = 0.1f;
CharacterTune::sGetInOpenDelay = 0.0f;
CharacterTune::sGetInOpenSpeed = 0.2f;
CharacterTune::sGetInCloseDelay = 0.0f;
CharacterTune::sGetInCloseSpeed = 0.2f;
CharacterTune::sGetOutOpenDelay = 0.0f;
CharacterTune::sGetOutOpenSpeed = 0.2f;
CharacterTune::sGetOutCloseDelay = 0.0f;
CharacterTune::sGetOutCloseSpeed = 0.2f;
CharacterTune::sfTurboRotateRate = 2.0f; // 1.2
CharacterTune::sfGetInOutOfCarAnimSpeed = 30.0f;
CharacterTune::sfKickingForce = 400.0f;
CharacterTune::sfSlamForce = 800.0f;
CharacterManager::sbFixedSimRate = false;
Console* pConsole = GetConsole( );
rAssert( pConsole );
if ( pConsole )
{
pConsole->AddFunction( "SetCharacterPosition", CharacterManager::SetCharacterPosition, "Sets the character position", 3, 3 );
pConsole->AddFunction( "ResetCharacter", CharacterManager::ResetCharacter, "Sets the character to the named locator", 2, 2 );
pConsole->AddFunction( "AddTeleportDest", AddTeleportDest, "Set a valid location for a teleport", 3, 5 );
pConsole->AddFunction( "SetInitialWalk", SetInitialWalk, "Set locator to walk to on startup", 1, 1 );
}
#ifdef DEBUGWATCH
const int MAX_LEN = 64;
char debugName[ MAX_LEN ];
int len = sprintf( debugName, "Character" );
rAssert( len < MAX_LEN );
radDbgWatchAddBoolean(&CharacterTune::bLocoTest, "Steer Facing", debugName, NULL, 0 );
radDbgWatchAddFloat(&CharacterTune::sfLocoRotateRate, "Loco Turning Rate", debugName, NULL, 0, 0.1f, 50.0f);
radDbgWatchAddFloat(&CharacterTune::sfLocoAcceleration, "Loco Acceleration", debugName, NULL, 0, 0.1f, 50.0f);
radDbgWatchAddFloat(&CharacterTune::sfLocoDecceleration, "Loco Deceleration", debugName, NULL, 0, -50.0f, -0.1f);
radDbgWatchAddFloat(&CharacterTune::sfAirRotateRate, "Air Turning Rate", debugName, NULL, 0, 0.0f, 20.0f);
radDbgWatchAddFloat(&CharacterTune::sfAirAccelScale, "Air Acceleration", debugName, NULL, 0, 0.0f, 1.0f );
radDbgWatchAddFloat(&CharacterTune::sfAirGravity, "Air Gravity", debugName, NULL, 0, -100.0f, 0.1f );
radDbgWatchAddFloat(&CharacterTune::sfStompGravityScale, "Stomp Gravity Scale", debugName, NULL, 0, 0.1f, 4.0f);
radDbgWatchAddFloat(&CharacterTune::sfJumpHeight, "Jump Height (Tap)", debugName, NULL, 0, 0.0f, 100.0f );
radDbgWatchAddFloat(&CharacterTune::sfDoubleJumpHeight, "Jump Height (Double Jump)", debugName, NULL, 0, 0.0f, 100.0f );
radDbgWatchAddFloat(&CharacterTune::sfDoubleJumpAllowUp, "Double Jump Sweet Spot (Up)", debugName, NULL, 0, 0.0f, 30.0f );
radDbgWatchAddFloat(&CharacterTune::sfDoubleJumpAllowDown, "Double Jump Sweet Spot (Down)", debugName, NULL, 0, 0.0f, 30.0f );
radDbgWatchAddFloat(&CharacterTune::sfHighJumpHeight, "Jump Height (Full Press)", debugName, NULL, 0, 0.0f, 100.0f );
radDbgWatchAddFloat(&CharacterTune::sfDashAcceleration, "Dash Accel", debugName, NULL, 0, 0.0f, 200.0f );
radDbgWatchAddFloat(&CharacterTune::sfDashDeceleration, "Dash Decel", debugName, NULL, 0, 0.0f, 200.0f );
radDbgWatchAddFloat(&CharacterTune::sfMaxSpeed, "Max Speed", debugName, NULL, 0, 0.0f, 8.0f );
radDbgWatchAddFloat((float*)&CharacterTune::sGetInPosition.x, "Get In Offset X", "Get In/Get Out", NULL, 0, 0.0f, 3.0f );
radDbgWatchAddFloat((float*)&CharacterTune::sGetInPosition.z, "Get In Offset Z", "Get In/Get Out", NULL, 0, -1.5f, 1.5f );
radDbgWatchAddFloat(&CharacterTune::sGetInHeightThreshold, "Height Threshold", "Get In/Get Out", NULL, 0, -2.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sfGetInOutOfCarAnimSpeed, "Speed", "Get In/Get Out", NULL, 0, 15.0f, 240.0f );
radDbgWatchAddFloat(&CharacterTune::sGetInOpenDelay, "Get In Open Delay", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetInOpenSpeed, "Get In Open Speed", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetInCloseDelay, "Get In Close Delay", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetInCloseSpeed, "Get In Close Speed", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetOutOpenDelay, "Get Out Open Delay", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetOutOpenSpeed, "Get Out Open Speed", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetOutCloseDelay, "Get Out Close Delay", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddFloat(&CharacterTune::sGetOutCloseSpeed, "Get Out Close Speed", "Get In/Get Out", NULL, 0, 0.0f, 2.0f );
radDbgWatchAddBoolean( &CharacterManager::sbFixedSimRate, "Fixed sim rate", debugName, NULL, 0 );
radDbgWatchAddFloat(&CharacterTune::sfDashBurstMax, "Turbo Speed", debugName, NULL, 0, 0.0f, 100.0f );
radDbgWatchAddFloat(&CharacterTune::sfTurboRotateRate, "Turbo Rotate Rate", debugName, NULL, 0, 0.0f, 10.0f );
radDbgWatchAddString(sCharacterToSpawn, 64, "NPC to Spawn", "CharacterManager");
radDbgWatchAddFunction( "Spawn NPC", &Spawn, NULL, "CharacterManager");
radDbgWatchAddFunction( "Next Skin", &NextSkin, NULL, "CharacterManager");
radDbgWatchAddFloat(&CharacterTune::sfKickingForce, "Kicking Force", debugName, NULL, 0, 0.0f, 2000.0f );
radDbgWatchAddFloat(&CharacterTune::sfSlamForce, "Stomping Force", debugName, NULL, 0, 0.0f, 4000.0f );
radDbgWatchAddFloat(&CharacterTune::sfShockTime, "Time(sec) to be shocked",debugName , NULL, NULL ,0 , 10.0f);
#ifdef RAD_XBOX
extern float g_XBoxMipmapBias;
radDbgWatchAddFloat(&g_XBoxMipmapBias, "Mipmap Bias", "XBox", NULL, NULL , -10.0f , 10.0f);
#endif
#endif //DEBUGWATCH
strcpy(mDummyLoadData.modelName, "npd");
strcpy(mDummyLoadData.animName, "npd");
FillLoadData( mDummyLoadData, "npd", "npd");
mGarbageCollect = false;
mUniversalPose = new tPose(64);
mUniversalPose->AddRef();
mNumCharactersAdded = 0;
}
CharacterManager::~CharacterManager( void )
{
Destroy(true);
tRefCounted::Release(mUniversalPose);
GetEventManager()->RemoveAll( this );
}
void CharacterManager::PreLoad( void )
{
// Load the global textures
char fname[128];
sprintf(fname, "art\\chars\\global.p3d");
char section[128];
sprintf(section, "Eakkachaichanvet");
p3d::inventory->AddSection(section);
GetLoadingManager()->AddRequest( FILEHANDLER_PURE3D, fname, GMA_LEVEL_OTHER, section );
// Load in a dummy, lightweight model
LoadModel("nps");
LoadModel("ndr");
LoadModel("npd");
// these animation banks are loaded all the time
LoadAnimation("nps");
LoadAnimation("ndr");
LoadAnimation("npd");
}
void CharacterManager::Destroy(bool permenant)
{
mUniversalPose->SetSkeleton(NULL);
ClearTeleportDests();
if(permenant)
{
p3d::inventory->RemoveSectionElements( "Eakkachaichanvet" );
p3d::inventory->DeleteSection( "Eakkachaichanvet" );
}
int i;
for ( i = 0; i < MAX_CHARACTERS; i++ )
{
g_Blinkers[ i ].SetCharacter( NULL );
if ( mpCharacter[ i ] != 0 )
{
GetWorldPhysicsManager()->RemoveFromAnyOtherCurrentDynamicsListAndCollisionArea(mpCharacter[i]);
mpCharacter[ i ]->RemoveFromWorldScene( );
mpCharacter[ i ]->ClearAllActionButtonHandlers();
mpCharacter[ i ]->SetManaged(false);
mpCharacter[ i ]->Release();
mpCharacter[ i ] = 0;
}
// Clean out the load data names, to make sure we clean up all memory in use
//
mCharacterLoadData[ i ].modelSection.SetText (0);
mCharacterLoadData[ i ].animSection.SetText (0);
mCharacterLoadData[ i ].animModelSection.SetText (0);
mCharacterLoadData[ i ].mModelHigh.SetText (0);
mCharacterLoadData[ i ].mModelMedium.SetText (0);
mCharacterLoadData[ i ].mModelLow.SetText (0);
mCharacterLoadData[ i ].mChoreoName.SetText (0);
}
for ( i = permenant ? 0 : 3; i < MAX_LOADS; i++ )
{
rAssert(mModelData[i].state != LOADING);
rAssert(mAnimData[i].state != LOADING);
if(mModelData[i].state == LOADED || mModelData[i].state == GARBAGE )
{
p3d::inventory->RemoveSectionElements(mModelData[i].section);
p3d::inventory->DeleteSection(mModelData[i].section);
}
if(mAnimData[i].state == LOADED || mAnimData[i].state == GARBAGE )
{
p3d::inventory->RemoveSectionElements(mAnimData[i].section);
p3d::inventory->DeleteSection(mAnimData[i].section);
}
mModelData[i].state = NOT_LOADED;
mAnimData[i].state = NOT_LOADED;
}
mNumCharactersAdded = 0;
}
void CharacterManager::RemoveCharacter( Character* c)
{
rAssert(c);
if(c)
{
for ( int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] == c )
{
if(mpCharacter[ i ]->GetRole() == Character::ROLE_COMPLETED_BONUS)
{
GetVehicleCentral()->RemoveSuppressedDriver(this->mRealModelNames[i]);
}
// if you get this assert, please leave it running and go get Nigel or Dusit
rAssert(mpCharacter[ i ]->GetRole() != Character::ROLE_PEDESTRIAN);
g_Blinkers[ i ].SetCharacter( NULL );
GetWorldPhysicsManager()->RemoveFromAnyOtherCurrentDynamicsListAndCollisionArea(mpCharacter[i]);
mpCharacter[ i ]->RemoveFromWorldScene( );
GetRenderManager()->mEntityDeletionList.Add((tRefCounted*&)mpCharacter[ i ]);
mpCharacter[ i ]->SetManaged(false);
mpCharacter[ i ] = 0;
GarbageCollectModel(mCharacterModelData[i]);
GarbageCollectAnim(mCharacterAnimData[i]);
return;
}
}
}
}
void CharacterManager::SetGarbage(Character* c, bool garbage)
{
for( int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] == c)
{
mGarbage[i] = garbage;
}
}
}
void CharacterManager::GarbageCollectModel(unsigned modelIndex)
{
bool modelUsed = (modelIndex < 3); // first three animation are npd, ndr, nps, don't garbage colelct
for ( int j = 0; (j < MAX_CHARACTERS) && !modelUsed; j++ )
{
if(mpCharacter[j])
{
modelUsed |= modelIndex == mCharacterModelData[j];
}
}
if(!modelUsed)
{
if(mModelData[modelIndex].state == LOADING)
{
mModelData[modelIndex].state = LOADING_GARBAGE;
mModelData[modelIndex].gracePeriod = 3.0f;
}
else
{
mModelData[modelIndex].state = GARBAGE;
mModelData[modelIndex].gracePeriod = 3.0f;
}
}
}
void CharacterManager::GarbageCollectAnim(unsigned animIndex)
{
bool animUsed = (animIndex < 3); // first three animation are npd, ndr, nps, don't garbage colelct
for ( int j = 0; (j < MAX_CHARACTERS) && !animUsed; j++ )
{
if(mpCharacter[j])
{
animUsed |= animIndex == mCharacterAnimData[j];
}
}
if(!animUsed)
{
if(mAnimData[animIndex].state == LOADING)
{
mAnimData[animIndex].state = LOADING_GARBAGE;
}
else
{
mAnimData[animIndex].state = GARBAGE;
}
}
}
bool CharacterManager::IsModelLoaded(const char* name)
{
unsigned index = FindLoad(mModelData, tEntity::MakeUID(name));
if( index != INVALID_LOAD && mModelData[index].state == LOADED )
{
return true;
}
return false;
//return FindLoad(mModelData, tEntity::MakeUID(name)) != INVALID_LOAD;
}
bool CharacterManager::IsAnimLoaded(const char* name)
{
unsigned index = FindLoad(mAnimData, tEntity::MakeUID(name));
if( index != INVALID_LOAD && mAnimData[index].state == LOADED )
{
return true;
}
return false;
//return FindLoad(mAnimData, tEntity::MakeUID(name)) != INVALID_LOAD;
}
unsigned CharacterManager::LoadModel(const char* model, LoadingManager::ProcessRequestsCallback* callback, void* userData)
{
tUID uid = tEntity::MakeUID(model);
unsigned loadIndex = AllocLoad(mModelData, uid);
if(mModelData[loadIndex].state == GARBAGE)
{
mModelData[loadIndex].state = LOADED;
}
if(mModelData[loadIndex].state == LOADING_GARBAGE)
{
mModelData[loadIndex].state = LOADING;
}
if((mModelData[loadIndex].state == LOADED) && callback)
{
callback->OnProcessRequestsComplete(userData);
}
else
{
mModelData[loadIndex].callback = callback;
mModelData[loadIndex].userData = userData;
}
if(mModelData[loadIndex].state == NOT_LOADED)
{
char truncModel[ 32 ];
// filenames are truncated at 6 characters
strcpy(truncModel, model);
truncModel[6] = 0;
char modelName[128];
sprintf(modelName, "art\\chars\\%s_m.p3d", truncModel);
char modelSection[128];
sprintf(modelSection, "%s_m", model);
mModelData[loadIndex].name = uid;
mModelData[loadIndex].section = tEntity::MakeUID(modelSection);
mModelData[loadIndex].state = LOADING;
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
p3d::inventory->AddSection(modelSection);
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
GetLoadingManager()->AddRequest( FILEHANDLER_PURE3D, modelName, GMA_CHARS_AND_GAGS, modelSection);
GetLoadingManager()->AddCallback(this, (void*)loadIndex);
}
return loadIndex;
}
unsigned CharacterManager::LoadAnimation(const char* anim)
{
tUID uid = tEntity::MakeUID(anim);
unsigned loadIndex = AllocLoad(mAnimData, uid);
if(mAnimData[loadIndex].state == GARBAGE)
{
mAnimData[loadIndex].state = LOADED;
}
if(mAnimData[loadIndex].state == LOADING_GARBAGE)
{
mAnimData[loadIndex].state = LOADING;
}
if(mAnimData[loadIndex].state == NOT_LOADED)
{
char truncAnim[ 32 ];
// filenames are truncated at 6 characters
strcpy(truncAnim, anim);
truncAnim[6] = 0;
char animName[128];
char choreoName[128];
sprintf(animName, "art\\chars\\%s_a.p3d", truncAnim);
sprintf(choreoName, "art\\chars\\%s.cho", anim);
char animSection[128];
sprintf(animSection, "%s_a", anim);
mAnimData[loadIndex].name = uid;
mAnimData[loadIndex].section = tEntity::MakeUID(animSection);
mAnimData[loadIndex].state = LOADING;
HeapMgr()->PushHeap( GMA_TEMP );
p3d::inventory->AddSection(animSection);
HeapMgr()->PopHeap( GMA_TEMP );
GetLoadingManager()->AddRequest( FILEHANDLER_PURE3D, animName, GMA_LEVEL_OTHER, animSection);
GetLoadingManager()->AddRequest( FILEHANDLER_CHOREO, choreoName, GMA_LEVEL_OTHER, animSection);
GetLoadingManager()->AddCallback(this, (void*)(0x10000000 | loadIndex));
}
return loadIndex;
}
unsigned CharacterManager::FindLoad(Load* loads, tUID name)
{
for(int i = 0; i < MAX_LOADS; i++)
{
if(loads[i].name == name)
{
return i;
}
}
return INVALID_LOAD;
}
unsigned CharacterManager::AllocLoad(Load* loads, tUID name)
{
unsigned index = FindLoad(loads, name);
if(index == INVALID_LOAD)
{
for(int i = 0; i < MAX_LOADS; i++)
{
if(loads[i].state == NOT_LOADED)
{
loads[i].name = name;
return i;
}
}
}
else
{
return index;
}
rAssertMsg(0, "Can't load any more character data");
return INVALID_LOAD;
}
CharacterManager::LoadState CharacterManager::GetState(Load* loads, tUID name)
{
unsigned index = FindLoad(loads, name);
if(index != INVALID_LOAD)
{
return loads[index].state;
}
return NOT_LOADED;
}
void CharacterManager::FillLoadData( CharacterLoadData& data, const char* useModel, const char* useAnim)
{
const int MAX_LEN = 32;
char modelName[ MAX_LEN ];
int len = sprintf( modelName, "%s_h", useModel);
rAssert( len < MAX_LEN );
data.mModelHigh.SetText( modelName );
len = sprintf( modelName, "%s_m", useModel );
rAssert( len < MAX_LEN );
data.mModelMedium.SetText( modelName );
len = sprintf( modelName, "%s_l", useModel );
rAssert( len < MAX_LEN );
data.mModelLow.SetText( modelName );
data.mChoreoName.SetText( useAnim );
char sec[256];
sprintf(sec, "%s_m", useModel);
data.modelSection.SetText(sec);
sprintf(sec, "%s_a", useAnim);
data.animSection.SetText(sec);
sprintf(sec, "%s_m", useAnim);
data.animModelSection.SetText(sec);
}
Character* CharacterManager::AddCharacter( CharacterType type, const char* characterName, const char* modelName, const char* choreoPuppet, const char* location)
{
unsigned int addCharTime = radTimeGetMicroseconds();
unsigned int MakeUIDTime = radTimeGetMicroseconds();
tUID modelUID = tEntity::MakeUID(modelName);
tUID animUID = tEntity::MakeUID(choreoPuppet);
MakeUIDTime = radTimeGetMicroseconds() - MakeUIDTime;
Character* character;
// #ifdef RAD_GAMECUBE
// HeapMgr()->PushHeap( GMA_GC_VMM );
// #else
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
// #endif
unsigned int NewTime = radTimeGetMicroseconds();
if(type == PC)
{
if( (int)mNumCharactersAdded >= GetGameplayManager()->GetNumPlayers() )
{
rReleasePrintf("Tried to add too many PCs, not supported right now. Check level scrips for multiple AddCharacter calls.\n");
// #ifdef RAD_GAMECUBE
// HeapMgr()->PopHeap( GMA_GC_VMM );
// #else
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
// #endif
return NULL;
}
MEMTRACK_PUSH_GROUP( "CharacterManager - Add PC" );
character = new Character;
character->mbAllowUnload = false;
//character->SetSimpleShadow( false );
}
else
{
rAssert( mNumCharactersAdded == (unsigned int)GetGameplayManager()->GetNumPlayers() );
MEMTRACK_PUSH_GROUP( "CharacterManager - Add NPC" );
character = new NPCharacter;
}
if((strcmp(modelName, "lisa") == 0) || (strncmp(modelName, "l_", 2) == 0))
{
character->SetIsLisa(true);
}
if((strcmp(modelName, "marge") == 0) || (strncmp(modelName, "m_", 2) == 0))
{
character->SetIsMarge(true);
}
rAssert( character );
NewTime = radTimeGetMicroseconds() - NewTime;
// #ifdef RAD_GAMECUBE
// HeapMgr()->PopHeap( GMA_GC_VMM );
// #else
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
// #endif
unsigned int SetNameTime = radTimeGetMicroseconds();
character->SetName( characterName );
SetNameTime = radTimeGetMicroseconds() - SetNameTime;
unsigned int AddCharacterTime = radTimeGetMicroseconds();
int characterIndex = AddCharacter( character, type );
strcpy(mRealModelNames[ characterIndex ], modelName);
strcpy(mRealAnimNames[ characterIndex ], choreoPuppet);
mLoaded[characterIndex] = true;
mGarbage[characterIndex] = false;
if ( type == PC )
{
rAssert( characterIndex == (int)mNumCharactersAdded );
++mNumCharactersAdded;
}
AddCharacterTime = radTimeGetMicroseconds() - AddCharacterTime;
unsigned int FillLoadTime = radTimeGetMicroseconds();
strcpy(mCharacterLoadData[characterIndex].modelName, modelName);
strcpy(mCharacterLoadData[characterIndex].animName, choreoPuppet);
FillLoadData( mCharacterLoadData[characterIndex], modelName, choreoPuppet);
FillLoadTime = radTimeGetMicroseconds() - FillLoadTime;
unsigned int LoadModelTime = 0;
unsigned int SetupCharacterTime;
LoadModelTime = radTimeGetMicroseconds();
mCharacterModelData[characterIndex] = LoadModel(modelName);
mCharacterAnimData[characterIndex] = LoadAnimation(choreoPuppet);
LoadModelTime = radTimeGetMicroseconds() - LoadModelTime;
if( (GetState(mAnimData, animUID) == LOADED) && (GetState(mModelData, modelUID) == LOADED) )
{
SetupCharacterTime = radTimeGetMicroseconds();
SetupCharacter( mCharacterLoadData[characterIndex], character );
SetupCharacterTime = radTimeGetMicroseconds() - SetupCharacterTime;
}
else
{
SetupCharacterTime = radTimeGetMicroseconds();
SetupCharacter( mDummyLoadData, character );
SetupCharacterTime = radTimeGetMicroseconds() - SetupCharacterTime;
}
unsigned int InitTime = radTimeGetMicroseconds();
character->Init();
InitTime = radTimeGetMicroseconds() - InitTime;
if(type == NPC)
{
// Dusit [Oct 22, 2002]:
// Don't solve collisions for NPCs.. They just sit there...
// We'll enable solve collisions as needed...
character->SetSolveCollisions( false );
}
else
{
// PCs get immediatly added to scene, NPCs might not be visible (i.e pedestrians)
character->AddToWorldScene();
}
if(location)
{
//Set the initial character position.
Locator* loc = p3d::find<Locator>( location );
CarStartLocator* cloc = dynamic_cast<CarStartLocator*>( loc );
rmt::Vector position;
if ( cloc )
{
cloc->GetLocation( &position );
character->RelocateAndReset( position, cloc->GetRotation() );
}
else if ( loc )
{
rmt::Vector position;
loc->GetLocation( &position );
character->RelocateAndReset( position, 0 );
}
else
{
rDebugPrintf( "Couldn't find locator \"%s\" for %s\n", location, characterName );
}
// if NPC, add the locator as the first waypoint of this character
if( loc && type == NPC )
{
// the controller should have been created in NPC constructor
NPCController* npcController = (NPCController*) character->GetController();
rAssert( npcController );
bool res = npcController->AddNPCWaypoint( position );
rAssert( res );
}
}
addCharTime = radTimeGetMicroseconds() - addCharTime;
#ifdef OUTPUT_TIMES
rReleasePrintf("AddCharacter %s Time %d\n",characterName, addCharTime);
rReleasePrintf(" AddCharacter MakeUIDTime %s Time %d\n",characterName, MakeUIDTime);
rReleasePrintf(" AddCharacter NewTime %s Time %d\n",characterName, NewTime);
rReleasePrintf(" AddCharacter SetNameTime %s Time %d\n",characterName, SetNameTime);
rReleasePrintf(" AddCharacter AddCharacterTime %s Time %d\n",characterName, AddCharacterTime);
rReleasePrintf(" AddCharacter FillLoadTime %s Time %d\n",characterName, FillLoadTime);
rReleasePrintf(" AddCharacter LoadModelTime %s Time %d\n",characterName, LoadModelTime);
rReleasePrintf(" AddCharacter SetupCharacterTime %s Time %d\n",characterName, SetupCharacterTime);
rReleasePrintf(" AddCharacter InitTime %s Time %d\n",characterName, InitTime);
#endif
if(type == PC)
{
MEMTRACK_POP_GROUP( "CharacterManager - Add PC" );
}
else
{
MEMTRACK_POP_GROUP( "CharacterManager - Add NPC" );
}
if(type == PC && GetGameplayManager()->IsSuperSprint() == false && GetGameplayManager()->mIsDemo == false)
{
//check to see if there is a valid skin that is not called NULL
if(strcmp(GetCharacterSheetManager()->QueryCurrentSkin(GetGameplayManager()->GetCurrentLevelIndex()),"NULL") != 0)
{
SwapData(character, GetCharacterSheetManager()->QueryCurrentSkin(GetGameplayManager()->GetCurrentLevelIndex()), GetAnimName(character));
}
}
return character;
}
Character* CharacterManager::AddCharacterDeferedLoad( CharacterType type, const char* characterName, const char* modelName, const char* choreoPuppet, const char* location)
{
Character* c = AddCharacter(type, characterName, "npd", "npd", location);
unsigned characterIndex = INVALID_LOAD;
for ( int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] == c )
{
characterIndex = i;
break;
}
}
rAssert(characterIndex != INVALID_LOAD);
strcpy(mRealModelNames[ characterIndex ], modelName);
strcpy(mRealAnimNames[ characterIndex ], choreoPuppet);
mLoaded[characterIndex] = false;
return c;
}
void CharacterManager::SwapData(Character* character, const char* modelName, const char* choreoPuppet)
{
unsigned index = InternalSwapData(character, modelName, choreoPuppet);
rAssert(index != INVALID_LOAD);
strcpy(mRealModelNames[ index ], modelName);
strcpy(mRealAnimNames[ index ], choreoPuppet);
}
unsigned CharacterManager::InternalSwapData(Character* character, const char* modelName, const char* choreoPuppet)
{
unsigned int SwapDataTime = radTimeGetMicroseconds();
unsigned characterIndex = INVALID_LOAD;
for ( int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] == character )
{
characterIndex = i;
break;
}
}
rAssert(characterIndex != INVALID_LOAD);
tUID modelUID;
tUID animUID;
unsigned modelIndex = mCharacterModelData[characterIndex];
unsigned animIndex = mCharacterAnimData[characterIndex];
if(modelName)
{
modelUID = tEntity::MakeUID(modelName);
strcpy(mCharacterLoadData[characterIndex].modelName, modelName);
}
else
{
modelUID = tEntity::MakeUID(mCharacterLoadData[characterIndex].modelName);
}
if(choreoPuppet)
{
animUID = tEntity::MakeUID(choreoPuppet);
strcpy(mCharacterLoadData[characterIndex].animName, choreoPuppet);
}
else
{
animUID = tEntity::MakeUID(mCharacterLoadData[characterIndex].animName);
}
unsigned int FillLoadTime = radTimeGetMicroseconds();
FillLoadData( mCharacterLoadData[characterIndex], mCharacterLoadData[characterIndex].modelName, mCharacterLoadData[characterIndex].animName);
FillLoadTime = radTimeGetMicroseconds() - FillLoadTime;
unsigned int LoadModelTime = 0;
unsigned int SetupCharacterTime = 0;
unsigned int CreatePuppetTime = 0;
LoadModelTime = radTimeGetMicroseconds();
mCharacterModelData[characterIndex] = LoadModel(mCharacterLoadData[characterIndex].modelName);
mCharacterAnimData[characterIndex] = LoadAnimation(mCharacterLoadData[characterIndex].animName);
LoadModelTime = radTimeGetMicroseconds() - LoadModelTime;
if((GetState(mAnimData, animUID) == LOADED) && (GetState(mModelData, modelUID) == LOADED))
{
SetupCharacterTime = radTimeGetMicroseconds();
CreatePuppetTime = SetupCharacter( mCharacterLoadData[characterIndex], character );
SetupCharacterTime = radTimeGetMicroseconds() - SetupCharacterTime;
}
else
{
SetupCharacterTime = radTimeGetMicroseconds();
CreatePuppetTime = SetupCharacter( mDummyLoadData, character );
SetupCharacterTime = radTimeGetMicroseconds() - SetupCharacterTime;
}
unsigned int GarbageCollectTime = radTimeGetMicroseconds();
GarbageCollectModel(modelIndex);
GarbageCollectAnim(animIndex);
GarbageCollectTime = radTimeGetMicroseconds() - GarbageCollectTime;
SwapDataTime = radTimeGetMicroseconds() - SwapDataTime;
#ifdef OUTPUT_TIMES
rReleasePrintf("SwapDataTime %s Time %d\n",modelName, SwapDataTime);
rReleasePrintf(" FillLoadTime %s Time %d\n",modelName, FillLoadTime);
if( LoadModelTime != 0 )
rReleasePrintf(" LoadModelTime %s Time %d\n",modelName, LoadModelTime);
rReleasePrintf(" GarbageCollectTime %s Time %d\n",modelName, GarbageCollectTime );
rReleasePrintf(" SetupCharacterTime %s Time %d\n",modelName, SetupCharacterTime );
rReleasePrintf(" CreatePuppetTime %s Time %d\n\n",modelName, CreatePuppetTime );
#endif
return characterIndex;
}
//=============================================================================
// CharacterManager::SetupCharacter
//=============================================================================
// Description: Comment
//
// Parameters: ( CharacterLoadData& data, Character* pCharacter, bool isNPC )
//
// Return: void
//
//=============================================================================
unsigned int CharacterManager::SetupCharacter( CharacterLoadData& data, Character* pCharacter)
{
p3d::inventory->PushSection();
bool currOnly = p3d::inventory->GetCurrentSectionOnly();
tName curr = p3d::inventory->GetCurrentSection()->GetName();
p3d::inventory->SetCurrentSectionOnly(true);
// #ifdef RAD_GAEMCUBE
// HeapMgr()->PushHeap( GMA_GC_VMM );
// #else
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
// #endif
MEMTRACK_PUSH_GROUP( "CharacterManager - CharacterRenderable" );
p3d::inventory->SelectSection(data.modelSection.GetUID());
CharacterRenderable* pCharacterRenderable;
if(data.modelSection.GetUID() != tEntity::MakeUID("npd_m"))
{
pCharacterRenderable = new CharacterRenderable(
p3d::find<tDrawablePose>( data.mModelHigh.GetUID() ),
p3d::find<tDrawablePose>( data.mModelMedium.GetUID() ),
p3d::find<tDrawablePose>( data.mModelLow.GetUID() ));
pCharacterRenderable->SetSwatchShader( p3d::find<tShader>( "char_swatches_lit_m" ) );
}
else
{
pCharacterRenderable = new CharacterRenderable(NULL, NULL, NULL);
pCharacterRenderable->SetSwatchShader( NULL );
}
pCharacterRenderable->SetShadowColour( pCharacter->GetShadowColour() );
// Lets find the electrocution effect
p3d::inventory->SelectSection( P3D_DEFAULT_INV_SECTION );
p3d::inventory->SetCurrentSectionOnly( false );
pCharacterRenderable->SetShockEffect( p3d::find< tDrawable >( "electrocuted" ) );
p3d::inventory->SetCurrentSectionOnly( true );
p3d::inventory->SelectSection( "Eakkachaichanvet" );
pCharacterRenderable->SetSwatchTexture( 0, p3d::find<tTexture>( "char_swatches_lit.bmp" ) );
pCharacterRenderable->SetSwatchTexture( 1, p3d::find<tTexture>( "char_swatches1.bmp" ) );
pCharacterRenderable->SetSwatchTexture( 2, p3d::find<tTexture>( "char_swatches2.bmp" ) );
pCharacterRenderable->SetSwatchTexture( 3, p3d::find<tTexture>( "char_swatches3.bmp" ) );
pCharacterRenderable->SetSwatchTexture( 4, p3d::find<tTexture>( "char_swatches4.bmp" ) );
pCharacterRenderable->SetSwatch( 0 );
p3d::inventory->SelectSection( data.modelSection.GetUID() );
pCharacter->SetDrawable( pCharacterRenderable );
MEMTRACK_POP_GROUP("CharacterManager - CharacterRenderable");
tDrawablePose* pDrawablePose = pCharacterRenderable->GetDrawable();
tSkeleton* pSkeleton = NULL;
if(pDrawablePose)
{
pSkeleton = pDrawablePose->GetSkeleton();
}
else
{
p3d::inventory->SelectSection(data.animModelSection.GetUID());
pSkeleton = p3d::find<tSkeleton>( data.mChoreoName.GetUID() );
}
if(!pSkeleton)
{
tUID uid = tEntity::MakeUID("npd");
p3d::inventory->SelectSection(uid);
pSkeleton = p3d::find<tSkeleton>(uid);
}
rAssert( pSkeleton);
p3d::inventory->SelectSection(data.animSection.GetUID());
choreo::Bank* bank = p3d::find<choreo::Bank>( data.mChoreoName.GetUID() );
rAssert( bank != 0 );
MEMTRACK_PUSH_GROUP( "CharacterManager - Puppet" );
unsigned int PuppetTime = radTimeGetMicroseconds();
// Make sure the skeleton to be remapped are equivalent.
//
choreo::Rig* rig = bank->GetRig();
rAssert( rig != 0 );
tSkeleton* rigSkeleton = rig->GetSkeleton( );
int i = 0;
if ( rigSkeleton->GetNumJoint() != pSkeleton->GetNumJoint() )
{
rDebugPrintf( "%s skeleton is not the same as choreo::Rig skeleton %s. Animations will be hooped.\n",
rigSkeleton->GetName( ), pSkeleton->GetName( ) );
}
mUniversalPose->SetSkeleton(pSkeleton);
mUniversalPose->ResetToRestPose();
pCharacter->SetInCar(false);
pCharacter->SetPuppet( new choreo::Puppet( mUniversalPose, bank, false, 0x20, 5 ) );
choreo::Puppet* pPuppet = pCharacter->GetPuppet();
PuppetTime = radTimeGetMicroseconds() - PuppetTime;
// #ifdef RAD_GAEMCUBE
// HeapMgr()->PopHeap( GMA_GC_VMM );
// #else
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
// #endif
MEMTRACK_POP_GROUP( "CharacterManager - Puppet" );
//
// Determine & store y offset needed for this character
//
float yAdjustDrawable = 0.0f, yAdjustPuppet = 0.0f;
if( pCharacterRenderable->GetDrawable() &&
pCharacterRenderable->GetDrawable()->GetSkeleton() )
{
yAdjustDrawable = pCharacterRenderable->GetDrawable()->GetSkeleton()->
FindJoint( tEntity::MakeUID("Balance_Root") )->worldMatrix.Row(3).y;
}
if( pPuppet && pPuppet->GetSkeleton() )
{
yAdjustPuppet = pPuppet->GetSkeleton()->
FindJoint( tEntity::MakeUID("Balance_Root") )->worldMatrix.Row(3).y;
}
pCharacter->SetYAdjust((yAdjustDrawable - yAdjustPuppet) * 0.30f);
//
// Setup the blinker for this character
//
unsigned int characterIndex = GetCharacterIndex( pCharacter );
g_Blinkers[ characterIndex ].SetCharacter( pCharacter );
p3d::inventory->SetCurrentSectionOnly(currOnly);
p3d::inventory->SelectSection( curr );
p3d::inventory->PopSection();
return PuppetTime;
}
void CharacterManager::GarbageCollect(bool ignoreDist)
{
int i;
const float GARBAGE_COLLECT_DISTANCE = 100.0f;
// garbage collect
if(mGarbageCollect)
{
for(i = MAX_PLAYERS; i < MAX_CHARACTERS; i++)
{
if(mpCharacter[i])
{
rmt::Vector charPos;
rmt::Vector camPos;
rmt::Vector distance;
mpCharacter[i]->GetPosition(charPos);
// camPos = GetSuperCamManager()->GetSCC(0)->GetCamera()->GetPosition();
GetCharacter(0)->GetPosition(camPos);
distance.Sub(camPos, charPos);
float fDist = rmt::Abs(distance.Magnitude());
if(fDist > 10000)
{
continue;
}
bool suppressLoad = false;
if(mpCharacter[i]->GetRole() == Character::ROLE_ACTIVE_BONUS)
{
if(!GetGameplayManager()->GetCurrentMission()->IsBonusMission() &&
!GetGameplayManager()->GetCurrentMission()->IsRaceMission() &&
!GetGameplayManager()->GetCurrentMission()->IsWagerMission() &&
!GetGameplayManager()->GetCurrentMission()->IsSundayDrive())
{
suppressLoad = true;
}
}
if(mGarbage[i])
{
if(fDist > GARBAGE_COLLECT_DISTANCE || GetGameplayManager()->IsIrisClosed() || ignoreDist )
{
if(mpCharacter[i]->GetRole() != Character::ROLE_ACTIVE_BONUS)
{
if(mpCharacter[i]->IsAmbient())
{
mGarbage[i] = false;
mpCharacter[i]->EnableAmbientDialogue(true);
mpCharacter[i]->ResetAmbientPosition();
}
else
{
RemoveCharacter(mpCharacter[i]);
}
}
else
{
mGarbage[i] = false;
}
}
}
else if (mLoaded[i] && (fDist > 150) && mpCharacter[i]->mbAllowUnload)
{
InternalSwapData(mpCharacter[i], "npd", "npd");
mLoaded[i] = false;
mpCharacter[i]->RemoveFromPhysics();
}
else if (!mLoaded[i] && (fDist < 150) && !suppressLoad)
{
if( !CommandLineOptions::Get( CLO_NO_PEDS ) )
InternalSwapData(mpCharacter[i], mRealModelNames[i], mRealAnimNames[i]);
mLoaded[i] = true;
if(!mpCharacter[i]->IsInCar())
{
mpCharacter[i]->AddToPhysics();
}
}
}
}
for(i = 1; i < MAX_LOADS; i++)
{
if(mModelData[i].state == GARBAGE)
{
if(mModelData[i].gracePeriod < 0.0f)
{
p3d::inventory->RemoveSectionElements(mModelData[i].section);
p3d::inventory->DeleteSection(mModelData[i].section);
mModelData[i].state = NOT_LOADED;
}
}
if(mAnimData[i].state == GARBAGE)
{
if(mAnimData[i].gracePeriod < 0.0f)
{
p3d::inventory->RemoveSectionElements(mAnimData[i].section);
p3d::inventory->DeleteSection(mAnimData[i].section);
mAnimData[i].state = NOT_LOADED;
}
}
}
}
}
/*
==============================================================================
CharacterManager::PreSimUpdate
==============================================================================
Description: Comment
Parameters: ( float timeins )
Return: void
=============================================================================
*/
void CharacterManager::PreSimUpdate( float timeins )
{
int i;
for ( i = 1; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] && (mpCharacter[ i ]->GetRenderLayer() == GetRenderManager()->rCurWorldRenderLayer()) )
{
BEGIN_PROFILE("Character::PreSimUpdate")
mpCharacter[ i ]->PreSimUpdate( timeins );
END_PROFILE("Character::PreSimUpdate")
}
}
for(i = 1; i < MAX_LOADS; i++)
{
if(mModelData[i].state == GARBAGE)
{
mModelData[i].gracePeriod -= timeins;
}
if(mAnimData[i].state == GARBAGE)
{
mAnimData[i].gracePeriod -= timeins;
}
}
}
/*
==============================================================================
CharacterManager::PostSimUpdate
==============================================================================
Description: Comment
Parameters: ( float timeins )
Return: void
=============================================================================
*/
void CharacterManager::PostSimUpdate( float timeins )
{
int i;
for ( i = 1; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] && (mpCharacter[ i ]->GetRenderLayer() == GetRenderManager()->rCurWorldRenderLayer()) )
{
BEGIN_PROFILE("Character::PostSimUpdate")
mpCharacter[ i ]->PostSimUpdate( timeins );
END_PROFILE("Character::PostSimUpdate")
}
}
}
/*
==============================================================================
CharacterManager::Update
==============================================================================
Description: Comment
Parameters: ( float timeins )
Return: void
=============================================================================
*/
void CharacterManager::Update( float timeins )
{
int i;
for( i = 0; i < MAX_CHARACTERS; i++ )
{
Character* character = mpCharacter[i];
if( character && (character->GetRenderLayer() == GetRenderManager()->rCurWorldRenderLayer()) )
{
g_Blinkers[ i ].Update( static_cast< int >( timeins * 1000 ) );
int collisionAreaIndex = character->GetCollisionAreaIndex();
if( collisionAreaIndex > WorldPhysicsManager::INVALID_COLLISION_AREA )
{
BEGIN_PROFILE("Character::UpdatePhObjects");
character->UpdatePhysicsObjects( timeins, collisionAreaIndex );
END_PROFILE("Character::UpdatePhObjects");
}
character->UpdateRoot( timeins );
sim::SimState* simState = character->GetSimState();
if( simState != NULL && simState->GetControl() == sim::simSimulationCtrl )
{
simState->GetSimulatedObject()->Update( timeins );
character->UpdateSimState( timeins );
sim::CollisionObject* collObj = simState->GetCollisionObject();
collObj->Update();
}
}
}
}
/*
==============================================================================
CharacterManager::PreSubstepUpdate
==============================================================================
Description: Comment
Parameters: ( float timeins )
Return: void
=============================================================================
*/
void CharacterManager::PreSubstepUpdate( float timeins )
{
for( int i=0; i<MAX_CHARACTERS; i++ )
{
if( mpCharacter[ i ] && mpCharacter[ i ]->IsInSubstep() )
{
BEGIN_PROFILE("Character::PreSimUpdate")
mpCharacter[ i ]->PreSimUpdate( timeins );
END_PROFILE("Character::PreSimUpdate")
}
}
}
/*
==============================================================================
CharacterManager::PostSubstepUpdate
==============================================================================
Description: Comment
Parameters: ( float timeins )
Return: void
=============================================================================
*/
void CharacterManager::PostSubstepUpdate( float timeins )
{
if ( mpCharacter[ 0 ] )
{
BEGIN_PROFILE("Character::PostSimUpdate")
mpCharacter[ 0 ]->PostSimUpdate( timeins );
END_PROFILE("Character::PostSimUpdate")
}
}
void CharacterManager::ClearTargetVehicle(Vehicle* v)
{
for (int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( NULL != mpCharacter[ i ] )
{
if(mpCharacter[ i ]->GetTargetVehicle() == v)
{
mpCharacter[ i ]->SetTargetVehicle(NULL);
}
}
}
}
void CharacterManager::ResetBonusCharacters(void)
{
for (int i = 0; i < MAX_CHARACTERS; i++ )
{
if ( NULL != mpCharacter[ i ] )
{
if(mpCharacter[ i ]->GetRole() == Character::ROLE_ACTIVE_BONUS)
{
((NPCController*)(mpCharacter[ i ]->GetController()))->TeleportToPath();
}
}
}
}
/*
==============================================================================
CharacterManager::AddCharacter
==============================================================================
Description: Add a character to the array. Returns true if succesfully added.
Parameters: ( Character* pCharacter, int& number, bool isNPC )
Return: bool
=============================================================================
*/
int CharacterManager::AddCharacter( Character* pCharacter, CharacterType type )
{
int i = 0;
// if it's an NPC, skip the first couple of entries (reserved for players)
if ( type == NPC )
{
i = MAX_PLAYERS;
}
// find an empty slot
for (; i < MAX_CHARACTERS; i++ )
{
if ( 0 == mpCharacter[ i ] )
{
break;
}
}
rAssertMsg(( i < MAX_CHARACTERS ), "Couldn't add character, no space in character array");
tRefCounted::Assign( mpCharacter[ i ], pCharacter );
mpCharacter[ i ]->SetManaged(true);
mGarbage[i] = false;
return i;
}
void CharacterManager::OnProcessRequestsComplete( void* pUserData )
{
unsigned index = (unsigned)pUserData;
if(index & 0x10000000)
{
index &= 0x0fffffff;
if(mAnimData[index].state == LOADING)
{
mAnimData[index].state = LOADED;
for(int i = 0; i < MAX_CHARACTERS; i++)
{
if(mpCharacter[i] && (mCharacterAnimData[i] == index))
{
if(mModelData[mCharacterModelData[i]].state == LOADED)
{
unsigned int PuppetTime = SetupCharacter(mCharacterLoadData[i], mpCharacter[i] );
#ifdef OUTPUT_TIMES
rReleasePrintf( "A) Calling SetupCharacter from OnProcessRequestsComplete for %s took %d\n",
mCharacterLoadData[i].modelName, PuppetTime );
#endif
}
}
}
} else if(mAnimData[index].state == LOADING_GARBAGE)
{
mAnimData[index].state = GARBAGE;
}
else
{
rAssert(0);
}
}
else
{
if(mModelData[index].state == LOADING)
{
mModelData[index].state = LOADED;
for(int i = 0; i < MAX_CHARACTERS; i++)
{
if(mpCharacter[i] && (mCharacterModelData[i] == index))
{
if(mAnimData[mCharacterAnimData[i]].state == LOADED)
{
unsigned int PuppetTime = SetupCharacter(mCharacterLoadData[i], mpCharacter[i] );
#ifdef OUTPUT_TIMES
rReleasePrintf( "B) Calling SetupCharacter from OnProcessRequestsComplete for %s took %d\n",
mCharacterLoadData[i].modelName, PuppetTime );
#endif
}
}
}
if(mModelData[index].callback)
{
mModelData[index].callback->OnProcessRequestsComplete(mModelData[index].userData);
mModelData[index].callback = NULL;
}
} else if(mModelData[index].state == LOADING_GARBAGE)
{
mModelData[index].state = GARBAGE;
}
else
{
rAssert(0);
}
}
}
//=============================================================================
Character* CharacterManager::GetCharacterByName( const char* name ) const
{
return GetCharacterByName( tEntity::MakeUID( name ) );
}
/*
==============================================================================
CharacterManager::GetCharacterByName
==============================================================================
Description: Comment
Parameters: ( const tUID uid )
Return: Character
=============================================================================
*/
Character* CharacterManager::GetCharacterByName( const tUID uid ) const
{
int i;
for( i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] != 0 && mpCharacter[ i ]->GetUID() == uid )
{
return mpCharacter[ i ];
}
}
return NULL;
}
//=============================================================================
Character* CharacterManager::GetMissionCharacter( const char* name ) const
{
Character* c = NULL;
// pick an appropriate name based on if we are a bonus mission or not
char n[64];
if(GetGameplayManager()->GetCurrentMission()->IsBonusMission())
{
sprintf(n, "b_%s", name);
c = GetCharacterManager()->GetCharacterByName( n );
}
if(!c)
{
sprintf(n, "reward_%s", name);
c = GetCharacterManager()->GetCharacterByName( n );
}
if(!c)
{
c = GetCharacterManager()->GetCharacterByName( name );
}
return c;
}
/*
==============================================================================
CharacterManager::GetCharacter
==============================================================================
Description: Return a pointer to the character.
Parameters: ( int i )
Return: Character
=============================================================================
*/
Character* CharacterManager::GetCharacter( int i ) const
{
if ( i < MAX_CHARACTERS )
{
return mpCharacter[ i ];
}
else
{
return NULL;
}
}
/*
==============================================================================
CharacterManager::HandleEvent
==============================================================================
Description: Comment
Parameters: ( EventEnum id, void* pEventData )
Return: void
=============================================================================
*/
void CharacterManager::HandleEvent( EventEnum id, void* pEventData )
{
switch ( id )
{
case EVENT_GETINTOVEHICLE_START :
{
Character* c = (Character*)pEventData;
if(c->GetTargetVehicle())
{
if(c->GetTargetVehicle()->mpDriver && (c->GetTargetVehicle()->mpDriver != c))
{
c->GetTargetVehicle()->mpDriver->GetController()->SetIntention(CharacterController::WaveHello);
}
}
}
break;
case EVENT_GETOUTOFVEHICLE_END :
{
Character* c = (Character*)pEventData;
if(c->GetTargetVehicle())
{
if(c->GetTargetVehicle()->mpDriver && (c->GetTargetVehicle()->mpDriver != c))
{
c->GetTargetVehicle()->mpDriver->GetController()->SetIntention(CharacterController::WaveGoodbye);
}
}
}
break;
case EVENT_TOGGLE_FIRSTPERSON :
{
CGuiScreenHud* currentHud = GetCurrentHud();
if(pEventData == 0)
{
if(GetCharacter(0)->GetActionButtonHandler())
{
if ( GetCharacter(0)->GetActionButtonHandler()->IsInstanceEnabled() )
{
if( currentHud != NULL )
{
currentHud->HandleMessage( GUI_MSG_SHOW_HUD_OVERLAY, HUD_ACTION_BUTTON );
}
}
}
}
else
{
if( currentHud != NULL )
{
currentHud->HandleMessage( GUI_MSG_HIDE_HUD_OVERLAY, HUD_ACTION_BUTTON );
}
}
}
break;
case EVENT_STAGE_COMPLETE :
{
if(pEventData)
{
Character* ch = GetCharacter(0);
ch->GetController()->SetIntention(CharacterController::CelebrateSmall);
}
}
break;
case EVENT_CARD_COLLECTED :
case EVENT_MISSION_SUCCESS :
{
Character* ch = GetCharacter(0);
ch->GetController()->SetIntention(CharacterController::CelebrateBig);
}
break;
case EVENT_MISSION_CHARACTER_RESET :
{
if(pEventData && (sInitialWalkLocator[0] != 0))
{
rmt::Vector dest;
Locator* l = p3d::find<Locator>(sInitialWalkLocator);
if(l)
{
l->GetLocation(&dest);
Character* c = GetCharacterManager()->GetCharacter(0);
if(c->GetWalkerLocomotionAction()->GetStatus() != RUNNING)
{
c->GetWalkerLocomotionAction()->SetStatus(SLEEPING);
}
Sequencer* pSeq = c->GetActionController()->GetNextSequencer();
pSeq->BeginSequence();
pSeq->AddAction( new Arrive( c, dest) );
pSeq->AddAction( c->GetWalkerLocomotionAction() );
pSeq->EndSequence( );
}
}
sInitialWalkLocator[0] = 0;
}
break;
case EVENT_LOCATOR + LocatorEvent::CAR_DOOR:
{
EventLocator* pLocator = static_cast<EventLocator*>( pEventData );
rAssert( pLocator );
unsigned int playerId = pLocator->GetPlayerID();
Character* pCharacter = GetCharacter( playerId );
unsigned int actionId = pLocator->GetData( );
rAssert( actionId >= 0 );
ActionButton::GetInCar* pGetInCarAction = static_cast<ActionButton::GetInCar* >( GetActionButtonManager()->GetActionByIndex( actionId ) );
rAssert( dynamic_cast<ActionButton::GetInCar*>( pGetInCarAction ) );
rAssert( pGetInCarAction );
if ( pLocator->GetPlayerEntered() )
{
// Entered a door volume.
//
#ifdef RAD_DEBUG
int vehicleId = pGetInCarAction->GetVehicleId();
Vehicle* pVehicle = GetVehicleCentral()->GetVehicle( vehicleId );
rAssert( pVehicle );
#endif
pCharacter->AddActionButtonHandler( pGetInCarAction );
pGetInCarAction->Enter( pCharacter );
// TODO: Think about what will happen when the character is in two vols.
// at the same time.
//
}
else if ( !pLocator->GetPlayerEntered() )
{
// Exited a door volume.
//
pGetInCarAction->Exit( pCharacter );
pCharacter->RemoveActionButtonHandler( pGetInCarAction );
}
break;
}
case EVENT_LOCATOR + LocatorEvent::BOUNCEPAD:
{
EventLocator* pLocator = static_cast<EventLocator*>( pEventData );
if ( pLocator->GetPlayerEntered() )
{
rAssert( pLocator );
unsigned int playerId = pLocator->GetPlayerID();
Character* pCharacter = GetCharacter( playerId );
ActionButton::Bounce::OnEnter( pCharacter, pLocator );
}
break;
}
case EVENT_LOCATOR + LocatorEvent::GENERIC_BUTTON_HANDLER_EVENT:
{
EventLocator* pLocator = static_cast<EventLocator*>( pEventData );
rAssert( pLocator );
if ( pLocator->GetPlayerEntered() )
{
unsigned int playerId = pLocator->GetPlayerID();
Character* pCharacter = GetCharacter( playerId );
unsigned int actionId = pLocator->GetData( );
rAssert( actionId >= 0 );
ActionButton::GenericEventButtonHandler* pTED = static_cast<ActionButton::GenericEventButtonHandler* >( GetActionButtonManager()->GetActionByIndex( actionId ) );
rAssert( dynamic_cast< ActionButton::GenericEventButtonHandler* > (pTED) );
rAssert( pTED );
if ( pCharacter != static_cast<Character*>(pTED->GetEventData()) )
{
pCharacter->AddActionButtonHandler( pTED );
pTED->Enter( pCharacter );
}
}
else
{
unsigned int playerId = pLocator->GetPlayerID();
Character* pCharacter = GetCharacter( playerId );
unsigned int actionId = pLocator->GetData( );
rAssert( actionId >= 0 );
ActionButton::GenericEventButtonHandler* pTED = static_cast<ActionButton::GenericEventButtonHandler* >( GetActionButtonManager()->GetActionByIndex( actionId ) );
if ( pTED && (pCharacter != static_cast<Character*>(pTED->GetEventData())) )
{
rAssert( dynamic_cast<ActionButton::GenericEventButtonHandler* >( pTED ) != NULL );
pTED->Exit( pCharacter );
pCharacter->RemoveActionButtonHandler( pTED );
}
}
break;
}
case EVENT_DEATH_VOLUME_SCREEN_BLANK:
{
//TODO: Make the blends go away.
//Also, cut the camera properly...
EventLocator* pLocator = static_cast<EventLocator*>( pEventData );
if( pLocator == NULL )
{
break;
}
if ( pLocator->GetPlayerID() >= static_cast<unsigned int>(MAX_PLAYERS) )
{
//Ignore this!
break;
}
//Ignore when player leaves.
if ( pLocator->GetPlayerEntered() )
{
unsigned int playerId = pLocator->GetPlayerID();
Character* pCharacter = GetCharacter( playerId );
//Only do this if he's on foot.
if ( pCharacter->GetStateManager()->GetState() == CharacterAi::GET_IN)
{
GetAvatarManager()->PutCharacterInCar(pCharacter, pCharacter->GetTargetVehicle());
GetEventManager()->TriggerEvent(EVENT_GETINTOVEHICLE_END, pCharacter);
}
else
{
if ( pCharacter->GetStateManager()->GetState() == CharacterAi::GET_OUT )
{
GetAvatarManager()->PutCharacterOnGround( pCharacter, pCharacter->GetTargetVehicle() );
}
else if ( pCharacter->IsInCar() )
{
return;
}
rmt::Matrix mat = pLocator->GetMatrix();
rmt::Vector facing = mat.Row(2);
rmt::Vector pos;
pLocator->GetLocation( &pos );
float fDesiredDir = choreo::GetWorldAngle( facing.x, facing.z );
pCharacter->RelocateAndReset( pos, fDesiredDir, true, false );
GetSuperCamManager()->GetSCC( 0 )->DoCameraCut();
}
}
break;
}
default:
{
break;
}
}
}
const char* CharacterManager::GetModelName(Character* c)
{
for(int i = 0; i < MAX_CHARACTERS; i++)
{
if(c == mpCharacter[i])
{
return mRealModelNames[i];
}
}
return NULL;
}
const char* CharacterManager::GetAnimName(Character* c)
{
for(int i = 0; i < MAX_CHARACTERS; i++)
{
if(c == mpCharacter[i])
{
return mRealAnimNames[i];
}
}
return NULL;
}
/*
==============================================================================
CharacterManager::SubmitStatics
==============================================================================
Description: Comment
Parameters: ( void )
Return: void
=============================================================================
*/
void CharacterManager::SubmitStatics( void )
{
int i;
for ( i = 0; i < MAX_CHARACTERS; i++ )
{
Character* character = mpCharacter[i];
if( character != NULL )
{
character->SubmitStatics();
}
}
}
/*
==============================================================================
CharacterManager::SubmitAnimCollisions
==============================================================================
Description: Comment
Parameters: ( void )
Return: void
=============================================================================
*/
void CharacterManager::SubmitAnimCollisions( void )
{
int i;
for ( i = 0; i < MAX_CHARACTERS; i++ )
{
if ( mpCharacter[ i ] )
{
mpCharacter[ i ]->SubmitAnimCollisions();
}
}
}
/*
==============================================================================
CharacterManager::SubmitDynamics
==============================================================================
Description: Comment
Parameters: ( void )
Return: void
=============================================================================
*/
void CharacterManager::SubmitDynamics( void )
{
int i;
for ( i = 0; i < MAX_CHARACTERS; i++ )
{
Character* character = mpCharacter[i];
if( character != NULL )
{
character->SubmitDynamics();
}
}
}
/*
==============================================================================
CharacterManager::SetCharacterPosition
==============================================================================
Description: Comment
Parameters: ( int argc, char** argv )
Return: void
=============================================================================
*/
void CharacterManager::SetCharacterPosition( int argc, char** argv )
{
int index = ::atoi( argv[ 1 ] );
Character* pCharacter = GetCharacterManager()->GetCharacter( index );
if ( pCharacter )
{
rmt::Vector pos;
pos.x = static_cast<float>( atoi( argv[ 2 ] ) );
pos.y = 0.0f;
pos.z = static_cast<float>( atoi( argv[ 3 ] ) );
pCharacter->SetPosition( pos );
}
}
/*
==============================================================================
CharacterManager::ResetCharacter
==============================================================================
Description: Comment
Parameters: ( int argc, char** argv )
Return: void
=============================================================================
*/
void CharacterManager::ResetCharacter( int argc, char** argv )
{
int index = ::atoi( argv[ 1 ] );
Character* pCharacter = GetCharacterManager()->GetCharacter( index );
Locator* loc = p3d::find<Locator>( argv[2] );
if ( pCharacter && loc )
{
rmt::Vector pos;
loc->GetLocation( &pos );
pCharacter->RelocateAndReset(pos, pCharacter->GetDesiredDir());
}
}
char CharacterManager::sInitialWalkLocator[64] = "";
void CharacterManager::SetInitialWalk(int argc, char** argv)
{
strcpy(sInitialWalkLocator, argv[1]);
}
char CharacterManager::sCharacterToSpawn[64] = "homer";
Character* CharacterManager::sSpawnedCharacter = NULL;
void CharacterManager::Spawn(void*)
{
if(sSpawnedCharacter)
{
GetCharacterManager()->RemoveCharacter(sSpawnedCharacter);
sSpawnedCharacter = NULL;
}
sSpawnedCharacter = GetCharacterManager()->AddCharacter(NPC, "dummy", sCharacterToSpawn, "npd", "next_to_pc");
rmt::Vector position;
rmt::Vector facing;
GetCharacterManager()->GetCharacter(0)->GetPosition( &position );
GetCharacterManager()->GetCharacter(0)->GetFacing( facing );
position += facing;
position += facing;
sSpawnedCharacter->RelocateAndReset( position, 0);
if(sSpawnedCharacter)
sSpawnedCharacter->AddToWorldScene();
}
static const int sNumBartSkins = 7;
static int sCurBartSkin = 1;
static char sBartSkins [sNumBartSkins][16] =
{
"bart",
"b_man",
"b_military",
"b_ninja",
"b_football",
"b_tall",
"b_hugo"
};
static const int sNumHomerSkins = 7;
static int sCurHomerSkin = 1;
static char sHomerSkins [sNumHomerSkins][16] =
{
"homer",
"h_fat",
"h_donut",
"h_stcrobe",
"h_undrwr",
"h_scuzzy",
"h_evil"
};
static const int sNumLisaSkins = 4;
static int sCurLisaSkin = 1;
static char sLisaSkins [sNumLisaSkins][16] =
{
"lisa",
"l_cool",
"l_florida",
"l_jersey"
};
static const int sNumMargeSkins = 4;
static int sCurMargeSkin = 1;
static char sMargeSkins [sNumMargeSkins][16] =
{
"marge",
"m_police",
"m_pink",
"m_prison"
};
static const int sNumApuSkins = 4;
static int sCurApuSkin = 1;
static char sApuSkins [sNumApuSkins][16] =
{
"apu",
"a_american",
"a_besharp",
"a_army"
};
void CharacterManager::NextSkin( void* )
{
tUID bart = tEntity::MakeUID("bart");
tUID homer = tEntity::MakeUID("homer");
tUID lisa = tEntity::MakeUID("lisa");
tUID marge = tEntity::MakeUID("marge");
tUID apu = tEntity::MakeUID("apu");
Character* pc = GetCharacterManager()->GetCharacter(0);
if(pc->GetUID() == bart)
{
GetCharacterManager()->SwapData(pc, sBartSkins[sCurBartSkin], "bart");
sCurBartSkin = (sCurBartSkin + 1) % sNumBartSkins;
}
if(pc->GetUID() == homer)
{
GetCharacterManager()->SwapData(pc, sHomerSkins[sCurHomerSkin], "homer");
sCurHomerSkin = (sCurHomerSkin + 1) % sNumHomerSkins;
}
if(pc->GetUID() == lisa)
{
GetCharacterManager()->SwapData(pc, sLisaSkins[sCurLisaSkin], "lisa");
sCurLisaSkin = (sCurLisaSkin + 1) % sNumLisaSkins;
}
if(pc->GetUID() == marge)
{
GetCharacterManager()->SwapData(pc, sMargeSkins[sCurMargeSkin], "marge");
sCurMargeSkin = (sCurMargeSkin + 1) % sNumMargeSkins;
}
if(pc->GetUID() == apu)
{
GetCharacterManager()->SwapData(pc, sApuSkins[sCurApuSkin], "apu");
sCurApuSkin = (sCurApuSkin + 1) % sNumApuSkins;
}
}
static const int s_numCheatModels = 107;
static char s_CheatModels[s_numCheatModels][107] =
{
"apu",
"askinner",
"a_american",
"a_army",
"a_besharp",
"barney",
"bart",
"beeman",
"brn_unf",
"burns",
"b_football",
"b_hugo",
"b_man",
"b_military",
"b_ninja",
"b_tall",
"captain",
"carl",
"cbg",
"cletus",
"dolph",
"eddie",
"frink",
"gil",
"grandpa",
"hibbert",
"homer",
"h_donut",
"h_evil",
"h_fat",
"h_scuzzy",
"h_stcrobe",
"h_undrwr",
"jasper",
"jimbo",
"kearney",
"krusty",
"lenny",
"lisa",
"lou",
"louie",
"l_cool",
"l_florida",
"l_jersey",
"marge",
"milhouse",
"moe",
"moleman",
"m_pink",
"m_police",
"m_prison",
"ned",
"nelson",
"nriviera",
"otto",
"patty",
"ralph",
"selma",
"skinner",
"smithers",
"snake",
"teen",
"wiggum",
"willie",
"boy1",
"boy2",
"boy3",
"bum",
"busm1",
"busm2",
"busw1",
"const1",
"const2",
"farmr1",
"fem1",
"fem2",
"fem3",
"fem4",
"girl1",
"girl2",
"hooker",
"joger1",
"joger2",
"male1",
"male2",
"male3",
"male4",
"male5",
"male6",
"mobstr",
"nuclear",
"olady1",
"olady2",
"olady3",
"rednk1",
"rednk2",
"sail1",
"sail2",
"sail3",
"sail4",
"zfem1",
"zfem5",
"zmale1",
"zmale3",
"zmale4",
"frankenstein",
"witch"
};
static int s_curCheatModel = 0;
void CharacterManager::NextCheatModel(void)
{
if( CommandLineOptions::Get( CLO_NO_PEDS ) )
return;
Character* pc = GetCharacterManager()->GetCharacter(0);
GetCharacterManager()->SwapData(pc, s_CheatModels[s_curCheatModel], GetCharacterManager()->GetAnimName(pc));
s_curCheatModel = (s_curCheatModel + 1) % s_numCheatModels;
}
#include <mission/gameplaymanager.h>
#include <meta/zoneeventlocator.h>
static const unsigned MAX_TELEPORT_DESTS = 64;
static ZoneEventLocator* s_dynaloadLoc = NULL;
static unsigned s_numTeleportDests = 0;
struct TeleportDest
{
char name[32];
bool useLoc;
char loc[32];
rmt::Vector pos;
char zone[64];
} s_teleportDests[MAX_TELEPORT_DESTS];
unsigned CharacterManager::GetNumTeleportDests(void)
{
return s_numTeleportDests;
}
const char* CharacterManager::GetTeleportDest(unsigned i)
{
static char dummy[] = "Invalid Teleport Destination";
if(i < s_numTeleportDests)
{
return s_teleportDests[i].name;
}
return dummy;
}
void CharacterManager::ClearTeleportDests(void)
{
for(unsigned i = 0; i < s_numTeleportDests; i++)
{
radDbgWatchDelete( &DoTeleport );
}
tRefCounted::Release(s_dynaloadLoc);
s_numTeleportDests = 0;
}
void CharacterManager::AddTeleportDest(int argc, char** argv)
{
rAssert(argc != 5);
strcpy(s_teleportDests[s_numTeleportDests].name, argv[1]);
if(argc == 4)
{
strcpy(s_teleportDests[s_numTeleportDests].loc, argv[2]);
strcpy(s_teleportDests[s_numTeleportDests].zone, argv[3]);
s_teleportDests[s_numTeleportDests].useLoc = true;
}
else
{
s_teleportDests[s_numTeleportDests].pos.Set((float)atof(argv[2]), (float)atof(argv[3]), (float)atof(argv[4]));
strcpy(s_teleportDests[s_numTeleportDests].zone, argv[5]);
s_teleportDests[s_numTeleportDests].useLoc = false;
}
radDbgWatchAddFunction( argv[1], &DoTeleport, (void*)s_numTeleportDests, "Teleport");
s_numTeleportDests++;
}
void CharacterManager::DoTeleport(void* data)
{
int which = (int)data;
GetRenderManager()->mpLayer( RenderEnums::LevelSlot )->DumpAllDynaLoads(1, GetRenderManager()->mEntityDeletionList );
tRefCounted::Assign(s_dynaloadLoc,new(GetGameplayManager()->GetCurrentMissionHeap()) ZoneEventLocator);
s_dynaloadLoc->SetZoneSize( strlen(s_teleportDests[which].zone) + 1 );
s_dynaloadLoc->SetZone( s_teleportDests[which].zone );
s_dynaloadLoc->SetPlayerEntered();
GetEventManager()->TriggerEvent( EVENT_FIRST_DYNAMIC_ZONE_START, s_dynaloadLoc );
rmt::Vector pos = s_teleportDests[which].pos;
if(s_teleportDests[which].useLoc)
{
Locator* l = p3d::find<Locator>(s_teleportDests[which].loc);
l->GetLocation(&pos);
}
if(GetCharacterManager()->GetCharacter(0)->IsInCar())
{
GetCharacterManager()->GetCharacter(0)->GetTargetVehicle()->SetPosition(&pos);
}
else
{
GetCharacterManager()->GetCharacter(0)->RelocateAndReset(pos, 0);
}
}
//=============================================================================
// CharacterManager::ResetCharacter
//=============================================================================
// Description: Comment
//
// Parameters: ( int argc, char** argv )
//
// Return: void
//
//=============================================================================
unsigned int CharacterManager::GetCharacterIndex( const Character* character ) const
{
unsigned int i;
unsigned int size = MAX_CHARACTERS;
for( i = 0; i < size; ++i )
{
if( mpCharacter[ i ] == character )
{
return i;
}
}
rAssertMsg( false, "Searched for a chraracter that does not exist" );
return 0;
}