The-Simpsons-Hit-and-Run/game/code/interiors/interiormanager.cpp

2410 lines
70 KiB
C++

//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: interiormanager.cpp
//
// Description: Implementation for the InteriorManager class.
//
// History: + Created -- Darwin Chau
//
//=============================================================================
//========================================
// System Includes
//========================================
// System
#include <stdlib.h> // for rand()
// Ftech
#include <raddebug.hpp>
#include <choreo/utility.hpp>
#include <p3d/light.hpp>
#include <p3d/matrixstack.hpp>
#include <p3d/view.hpp>
#include <simcommon/simstatearticulated.hpp>
//========================================
// Project Includes
//========================================
#include <interiors/interiormanager.h>
#include <ai/sequencer/actioncontroller.h>
#include <ai/sequencer/action.h>
#include <ai/actionbuttonhandler.h>
#include <camera/supercammanager.h>
#include <console/console.h>
#include <events/eventdata.h>
#include <events/eventmanager.h>
#include <main/game.h>
#include <memory/srrmemory.h>
#include <meta/directionallocator.h>
#include <meta/interiorentrancelocator.h>
#include <meta/triggervolumetracker.h>
#include <presentation/nisplayer.h>
#include <presentation/fmvplayer/fmvplayer.h>
#include <presentation/gui/guisystem.h>
#include <presentation/gui/ingame/guimanageringame.h>
#include <presentation/gui/ingame/guiscreenhud.h>
#include <presentation/gui/ingame/guiscreenletterbox.h>
#include <presentation/presentation.h>
#include <render/rendermanager/renderlayer.h>
#include <render/rendermanager/rendermanager.h>
#include <render/RenderManager/WorldRenderLayer.h>
#include <sound/soundmanager.h>
#include <worldsim/avatar.h>
#include <worldsim/avatarmanager.h>
#include <worldsim/character/character.h>
#include <worldsim/character/charactermanager.h>
#include <worldsim/coins/coinmanager.h>
#include <worldsim/worldphysicsmanager.h>
#include <worldsim/traffic/trafficmanager.h>
#include <meta/locatorevents.h>
#include <meta/eventlocator.h>
#include <meta/spheretriggervolume.h>
#include <meta/triggervolumetracker.h>
#include <cards/cardgallery.h>
#include <mission/charactersheet/charactersheetmanager.h>
#include <mission/missionmanager.h>
#include <mission/gameplaymanager.h>
#include <mission/animatedicon.h>
#include <worldsim/coins/sparkle.h>
//******************************************************************************
//
// Global Data, Local Data, Local Classes
//
//******************************************************************************
// Static pointer to instance of singleton.
InteriorManager* InteriorManager::spInstance = NULL;
rmt::Randomizer InteriorManager::sRandom(0);
bool InteriorManager::sRandomSeeded = false;
unsigned InteriorManager::sPersistGagIndex = 0;
extern bool cGuiManagerInGameActive;
const int PLAYER_ONE = 0;
// wow, what a hack
struct InteriorCentre
{
tName name;
rmt::Vector centre;
int level;
};
static InteriorCentre s_InteriorCentres[8];
// another hack
static const int NUM_OPAQUES = 1;
static const char sOpaques[NUM_OPAQUES][16] = {
"gag_buly.p3d"
};
InteriorManager::GagBinding::GagBinding()
{
Clear();
}
void InteriorManager::GagBinding::Clear(void)
{
interiorUID = 0;
weight = 1;
random = true;
gagFileName[0] = 0;
cycleMode = DEFAULT_CYCLE_MODE;
triggered = false;
action = false;
retrigger = false;
useGagLocator = false;
gagLoc = 0;
gagPos.Set(0.0f,0.0f,0.0f);
useTriggerLocator = false;
triggerLoc = 0;
triggerPos.Set(0.0f,0.0f,0.0f);
soundID = 0;
gagFMVFileName[ 0 ] = 0;
loopIntro = 0;
loopOutro = 0;
cameraShake = false;
shakeDelay = 0.0f;
shakeDuration = 0.0f;
shake.playerID = 0;
shake.direction.Set(0.0f,1.0f,0.0f);
shake.looping = false;
coinDelay = 0.0f;
coins = 0;
sparkle = false;
animBV = false;
loadDist = 100;
unloadDist = 150;
soundLoadDist = 10;
soundUnloadDist = 20;
i_S_Movie = 0;
persistIndex = -1;
dialogChar1[0] = '\0';
dialogChar2[0] = '\0';
acceptDialogID = 0;
rejectDialogID = 0;
instructDialogID = 0;
}
class Gag;
class GagDrawable : public DynaPhysDSG
{
public:
GagDrawable(Gag* g);
virtual ~GagDrawable() { mpDrawstuff->Release(); };
// void DisplayBoundingBox(tColour colour = tColour(0,255,0));
// void DisplayBoundingSphere(tColour colour = tColour(0,255,0));
void GetBoundingBox(rmt::Box3D* box)
{
mpDrawstuff->GetBoundingBox(box);
if(useTranslate)
{
box->high += mPosn;
box->low += mPosn;
}
}
void GetBoundingSphere(rmt::Sphere* sphere)
{
mpDrawstuff->GetBoundingSphere(sphere);
if(useTranslate)
{
sphere->centre += mPosn;
}
// sphere->radius += 10.0f;
}
virtual void Display();
void SetPosition(bool u, const rmt::Vector& v)
{
mPosn = v;
useTranslate = u;
if(useTranslate && mpSimStateObj)
{
rmt::Matrix matrix;
matrix.Identity();
matrix.FillTranslate(mPosn);
mpSimStateObj->SetTransform(matrix);
if(mPose)
{
mPose->Assign(((tCompositeDrawable*)mpDrawstuff)->GetPose());
mPose->GetJoint(0)->SetWorldTranslation(mPose->GetJoint(0)->GetWorldTranslation() + mPosn);
}
mpSimStateObj->GetCollisionObject()->SetHasRelocated( true );
mpSimStateObj->GetCollisionObject()->SetHasMoved( true );
mpSimStateObj->GetCollisionObject()->Update();
}
}
float sparkleStrength;
void SimUpdate(float timeins)
{
if(mPose)
{
mPose->Assign(((tCompositeDrawable*)mpDrawstuff)->GetPose());
mPose->GetJoint(0)->SetObjectTranslation(mPose->GetJoint(0)->GetObjectTranslation() + mPosn);
mpSimStateObj->GetCollisionObject()->SetHasMoved(true);
mpSimStateObj->GetCollisionObject()->Update();
}
}
void ApplyForce( const rmt::Vector& direction, float force )
{
// no force
}
private:
tDrawable* mpDrawstuff;
Gag* gag;
bool useTranslate;
poser::Pose* mPose;
private:
//Prevent wasteful constructor creation.
GagDrawable( const GagDrawable& pGagDrawable );
GagDrawable& operator=( const GagDrawable& pGagDrawable );
};
class Gag : public ActionButton::ButtonHandler, public AnimationPlayer::LoadDataCallBack, public EventListener, public NISSoundPlaybackCompleteCallback
{
public:
void Render(void)
{
gagPlayer->Render();
}
void Load(void)
{
char buffy[256];
sprintf( buffy, "art\\nis\\gags\\%s", binding->gagFileName );
gagPlayer->LoadData( buffy, this, false, 0 );
mLoading = true;
}
void SoundLoad(void)
{
if( binding->soundID != 0 )
{
GetSoundManager()->LoadNISSound( binding->soundID );
mSoundLoaded = true;
}
}
void Unload(void)
{
if(draw)
{
((WorldRenderLayer*)GetRenderManager()->mpLayer(RenderEnums::LevelSlot))->pWorldScene()->Remove(draw);
}
gagPlayer->Stop();
gagPlayer->ClearData();
if(trigger)
{
GetTriggerVolumeTracker()->RemoveTrigger(trigger);
trigger->Release();
trigger = NULL;
}
if(locator)
{
locator->Release();
locator = NULL;
}
if(draw)
{
draw->Release();
draw = NULL;
}
if(collObj)
{
collObj->Release();
collObj = NULL;
}
mLoaded = false;
}
void SoundUnload(void)
{
if( binding->soundID != 0 )
{
GetSoundManager()->StopAndDumpNISSound( binding->soundID );
mSoundLoaded = false;
}
}
// Used when the dialog finishes.
void HandleEvent(EventEnum id, void* pEventData)
{
//Wait for the dialogue system to announce that the dialogue is finished
//playing. Right now we only listen to one type of event so we don't need
//to check the id.
GetInteriorManager()->SetISMovieDialogPlaying( false );
CGuiScreenLetterBox::ForceOpen();
gagPlayer->Play();
GetEventManager()->RemoveListener(this, EVENT_CONVERSATION_DONE);
TrafficManager::GetInstance()->RemoveCharacterToStopFor(mDialogEventData.char1);
TrafficManager::GetInstance()->RemoveCharacterToStopFor(mDialogEventData.char2);
// Display message for the player that they should go to the Aztec theature.
if(GetCharacterSheetManager()->IsState(1))
{
GetGuiSystem()->HandleMessage( GUI_MSG_INGAME_DISPLAY_PROMPT, 10 );
}
}
void NISSoundPlaybackComplete()
{
m_isNISSoundComplete = true;
}
void Update( unsigned int elapsedTime )
{
if(mLoading)
{
return;
}
rmt::Vector charPos;
rmt::Vector gagPos = binding->gagPos;
GetCharacterManager()->GetCharacter(0)->GetPosition(charPos);
charPos.Sub(gagPos);
float dist = rmt::Abs(charPos.Magnitude());
if(mSoundLoaded && (dist > binding->soundUnloadDist))
{
SoundUnload();
}
if(!mSoundLoaded && (dist < binding->soundLoadDist))
{
SoundLoad();
}
// only do distance based loading for non interior gags, interior ones are always loaded
if( binding->interiorUID == static_cast< tUID >( 0 ) )
{
if(mLoaded && (dist > binding->unloadDist))
{
Unload();
}
if(!mLoaded && (dist < binding->loadDist))
{
Load();
}
}
if(draw)
{
if(binding->sparkle)
{
draw->sparkleStrength = 1.0f - rmt::Clamp((dist - 10.0f) * 0.1f, 0.0f, 1.0f);
}
else
{
draw->sparkleStrength = 0.0f;
}
}
if(!mLoaded)
{
return;
}
bool finished = (binding->gagFMVFileName[ 0 ] == 0) ? gagPlayer->IsFinished() : !GetPresentationManager()->GetFMVPlayer()->IsPlaying();
finished = finished && m_isNISSoundComplete;
if(finished && playing)
{
playing = false;
GetEventManager()->TriggerEvent(EVENT_GAG_END, (void*)binding);
if(binding->coinDelay < 0.0f)
{
rmt::Vector pos;
draw->GetPosition(&pos);
GetCoinManager()->SpawnInstantCoins(binding->coins, pos);
}
}
if(binding->retrigger)
{
if(!((binding->i_S_Movie == 1) && (!GetMissionManager()->IsSundayDrive())))
{
if(gagPlayer->IsFinished() && m_isNISSoundComplete)
{
gagPlayer->Rewind();
SoundUnload(); // Just to be sure
SoundLoad();
GetTriggerVolumeTracker()->AddTrigger(trigger);
//sparkles remain off once triggered
//sparkle = true;
}
}
}
if((mTimeToCameraShake > 0) && ((mTimeToCameraShake - (int)elapsedTime) <= 0))
{
mTimeToCameraShake = 0;
GetSuperCamManager()->GetSCC(0)->GetActiveSuperCam()->AllowShake();
GetEventManager()->TriggerEvent(EVENT_CAMERA_SHAKE, &binding->shake);
}
if((mTimeToCameraShakeEnd > 0) && ((mTimeToCameraShakeEnd - (int)elapsedTime) <= 0))
{
mTimeToCameraShakeEnd = 0;
GetSuperCamManager()->GetSCC(0)->GetActiveSuperCam()->DisableShake();
}
if((mTimeToCoinSpawn > 0) && ((mTimeToCoinSpawn - (int)elapsedTime) <= 0))
{
mTimeToCoinSpawn = 0;
rmt::Vector pos;
draw->GetPosition(&pos);
GetCoinManager()->SpawnInstantCoins(binding->coins, pos);
}
if(mTimeToCameraShake > 0)
{
mTimeToCameraShake -= elapsedTime;
}
if(mTimeToCameraShakeEnd > 0)
{
mTimeToCameraShakeEnd -= elapsedTime;
}
if(mTimeToCoinSpawn > 0)
{
mTimeToCoinSpawn -= elapsedTime;
}
gagPlayer->Update( elapsedTime );
draw->SimUpdate( static_cast< float >( elapsedTime) );
}
InteriorManager::GagBinding* GetBinding(void) { return binding; }
protected:
void StartIntro(void)
{
if(binding->loopIntro != 0)
{
gagPlayer->Play();
}
}
DialogEventData mDialogEventData;
void PlayDialog(radKey32 DialogID)
{
rAssert(strlen(binding->dialogChar1) != 0 && strlen(binding->dialogChar1) < DialogueObjective::MAX_CHAR_NAME_LEN);
rAssert(strlen(binding->dialogChar2) != 0 && strlen(binding->dialogChar2) < DialogueObjective::MAX_CHAR_NAME_LEN);
//Register with the event system that you are listening for the dialogue end
//event.
GetEventManager()->AddListener( this, EVENT_CONVERSATION_DONE );
//Send the alert to the dialogue system to start playing this bad-ass
Character* c1 = GetCharacterManager()->GetCharacterByName(binding->dialogChar1);
tRefCounted::Assign(mDialogEventData.char1, c1);
TrafficManager::GetInstance()->AddCharacterToStopFor(c1);
Character* c2 = GetCharacterManager()->GetMissionCharacter(binding->dialogChar2);
tRefCounted::Assign(mDialogEventData.char2, c2);
TrafficManager::GetInstance()->AddCharacterToStopFor(c2);
mDialogEventData.dialogName = DialogID;
GetEventManager()->TriggerEvent(EVENT_CONVERSATION_INIT, (void*)(&mDialogEventData));
GetEventManager()->TriggerEvent(EVENT_CONVERSATION_INIT_DIALOG, (void*)(&mDialogEventData));
GetEventManager()->TriggerEvent( EVENT_CONVERSATION_START, 0);
}
void Play(void)
{
rmt::Box3D box;
rmt::Vector pos;
playing = true;
bool alreadyPlayed = false;
if(binding->persistIndex != -1)
{
alreadyPlayed = GetCharacterSheetManager()->QueryGagViewed(GetGameplayManager()->GetCurrentLevelIndex(), binding->persistIndex);
if(!alreadyPlayed)
{
GetCharacterSheetManager()->AddGagViewed(GetGameplayManager()->GetCurrentLevelIndex(), binding->persistIndex);
GetEventManager()->TriggerEvent( EVENT_GAG_FOUND );
}
else
{
// We've already played this gag. Don't spawn any more coins. We can safely change this in the
//binding because we're dealing with a state that is persistent over the entire game. If this
//functionality changes we'll need to set some sort of flag in the the playing gag which the
//coin spawning coin can check later on.
binding->coins = 0;
}
}
//
// Not getting good position info here. Play from avatar position
//
Avatar* avatar = GetAvatarManager()->GetAvatarForPlayer( 0 );
rAssert( avatar != NULL ); //NIGEL - I put this assert in for you! love Ian.
if( avatar != NULL )
{
avatar->GetPosition( pos );
box.Set( pos, pos );
}
else
{
box.Set( rmt::Vector( 0.0f, 0.0f, 0.0f ), rmt::Vector( 0.0f, 0.0f, 0.0f ) );
}
// special case logic for the I&S movie. *sigh*
if((binding->i_S_Movie == 1) && (!GetCharacterSheetManager()->IsState(1)))
{
//The player is trying to pick up the I&S ticket!
bool haveAllCards = true;
for(int level = RenderEnums::L1; level < RenderEnums::numLevels; ++level)
{
if(GetCardGallery()->IsCardDeckComplete(level) == false)
{
haveAllCards = false;
break;
}
}
if(haveAllCards)
{
// They have all the cards, give them the ticket.
GetCharacterSheetManager()->SetState(1, true);
GetCharacterSheetManager()->SetFMVUnlocked(RenderEnums::L3);
GetInteriorManager()->SetISMovieDialogPlaying( true );
PlayDialog(binding->acceptDialogID);
binding->retrigger = false;
binding->triggered = false;
// Do the collection effect.
GetInteriorManager()->CollectionEffect("card_collect", binding->triggerPos);
}
else
{
if(GetCharacterSheetManager()->IsState(0))
{
// Not enough cards.
GetInteriorManager()->SetISMovieDialogPlaying( true );
PlayDialog(binding->rejectDialogID);
// GetSoundManager()->PlayNISSound( binding->rejectSoundID, &box );
}
else
{
// Give instructions.
GetCharacterSheetManager()->SetState(0, true);
GetInteriorManager()->SetISMovieDialogPlaying( true );
PlayDialog(binding->instructDialogID);
// GetSoundManager()->PlayNISSound( binding->instructSoundID, &box );
}
}
}
else if(binding->i_S_Movie == 2)
{
// The player is trying to watch the I&S movie.
if(GetCharacterSheetManager()->QueryFMVUnlocked(RenderEnums::L3))
{
// They have a ticket, play the movie.
GetPresentationManager()->PlayFMV( binding->gagFMVFileName );
}
else
{
// They don't have a ticket.
GetInteriorManager()->SetISMovieDialogPlaying( true );
PlayDialog(binding->rejectDialogID);
}
gagPlayer->Play();
}
else
{
if( !mSoundLoaded )
{
SoundLoad();
}
GetSoundManager()->PlayNISSound( binding->soundID, &box, this );
m_isNISSoundComplete = false;
if(binding->loopIntro != 0)
{
gagPlayer->DoneIntro();
}
else
{
gagPlayer->Play();
}
if( binding->gagFMVFileName[ 0 ] != 0 )
{
GetPresentationManager()->PlayFMV( binding->gagFMVFileName, NULL, true, false, false );
}
}
if(trigger)
{
GetTriggerVolumeTracker()->RemoveTrigger(trigger);
}
if(binding->cameraShake)
{
mTimeToCameraShake = (binding->shakeDelay == 0.0f) ? 1 : int(binding->shakeDelay * 1000.0f);
mTimeToCameraShakeEnd = (binding->shakeDuration == 0.0f) ? 0 : int((binding->shakeDelay + binding->shakeDuration) * 1000.0f);
}
if(binding->coins && (binding->coinDelay >= 0.0f) && !alreadyPlayed)
{
mTimeToCoinSpawn = (binding->coinDelay == 0.0f) ? 1 : int(binding->coinDelay * 1000.0f);
}
GetEventManager()->TriggerEvent(EVENT_GAG_START, (void*)binding);
sparkle = false;
}
public:
Gag(InteriorManager::GagBinding* b)
: binding(NULL),
locator(NULL),
trigger(NULL),
draw(NULL),
gagPlayer(NULL),
collObj(NULL),
mLoaded(false),
mLoading(false),
mTimeToCameraShake(0),
mTimeToCameraShakeEnd(0),
mTimeToCoinSpawn(0),
sparkle(false),
mSoundLoaded(false),
playing(false),
m_isNISSoundComplete(true)
{
binding = b;
gagPlayer = new NISPlayer;
gagPlayer->SetNameData( "GagController", NULL, "GagScene" );
gagPlayer->SetPlayAfterLoad( false );
gagPlayer->SetCycleMode( binding->cycleMode );
gagPlayer->SetShowAlways( true );
gagPlayer->SetIntroLoop(binding->loopIntro);
gagPlayer->SetOutroLoop(binding->loopOutro);
if(binding->interiorUID != static_cast< tUID >( 0 ) )
{
Load();
}
}
~Gag()
{
Unload();
SoundUnload();
delete gagPlayer;
}
bool IsLoaded(void)
{
return mLoaded;
}
void OnLoadDataComplete(void)
{
bool oldOnly = p3d::inventory->GetCurrentSectionOnly();
p3d::inventory->PushSection();
char buffy[256];
sprintf( buffy, "art\\nis\\gags\\%s", binding->gagFileName );
p3d::inventory->SelectSection(buffy);
p3d::inventory->SetCurrentSectionOnly(true);
mLoaded = true;
mLoading = false;
collObj = p3d::find<sim::CollisionObject>("GagScene");
if(collObj)
{
collObj->AddRef();
}
p3d::inventory->SetCurrentSectionOnly(false);
// Add gag animation to renderer
//
HeapMgr()->PushHeap(GMA_LEVEL_OTHER);
draw = new GagDrawable(this);
draw->AddRef();
if(binding->triggered)
{
if(!((binding->i_S_Movie == 1) &&
((!GetMissionManager()->IsSundayDrive()) ||
(GetCharacterSheetManager()->QueryFMVUnlocked(RenderEnums::L3)))))
{
if(binding->useTriggerLocator)
{
Locator* l = p3d::find<Locator>(binding->triggerLoc);
//rAssert(l); //get's fixed up later
if(l)
{
l->GetLocation(&binding->triggerPos);
}
}
locator = new EventLocator;
locator->SetEventType( LocatorEvent::GAG );
locator->SetData((unsigned int)this);
trigger = new SphereTriggerVolume(binding->triggerPos, binding->triggerRadius);
trigger->SetLocator(locator);
locator->SetNumTriggers( 1, HeapMgr()->GetCurrentHeap() );
locator->AddTriggerVolume( trigger );
GetTriggerVolumeTracker()->AddTrigger(trigger);
locator->AddRef();
trigger->AddRef();
StartIntro();
}
}
else
{
SoundLoad();
Play();
}
rmt::Vector gagPos = binding->gagPos;
if(binding->useGagLocator)
{
Locator* l = p3d::find<Locator>(binding->gagLoc);
//rAssert(l); //apparently *something* else positions this properly later
if(l)
{
l->GetLocation(&gagPos);
binding->gagPos = gagPos;
}
}
if(gagPos == rmt::Vector(0.0f,0.0f,0.0f))
{
rmt::Box3D box;
draw->GetBoundingBox(&box);
rmt::Vector c = box.high + box.low;
c /= 2;
draw->SetPosition(false, c);
}
else
{
draw->SetPosition(true, gagPos);
}
((WorldRenderLayer*)GetRenderManager()->mpLayer(RenderEnums::LevelSlot))->pWorldScene()->Add(draw);
p3d::inventory->PopSection();
p3d::inventory->SetCurrentSectionOnly(oldOnly);
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
bool alreadyPlayed = false;
if(binding->persistIndex != -1)
{
alreadyPlayed = GetCharacterSheetManager()->QueryGagViewed(GetGameplayManager()->GetCurrentLevelIndex(), binding->persistIndex);
}
if(alreadyPlayed)
{
sparkle = false;
}
else
{
sparkle = true;
}
}
void Trigger(EventLocator* loc)
{
if(((binding->gagFMVFileName[0] != 0) || (binding->i_S_Movie != 0)))
{
if(!GetGameplayManager()->GetCurrentMission()->IsSundayDrive())
{
return;
}
}
if(binding->action)
{
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
if(loc->GetPlayerEntered())
{
//
// Send a message about an active interactive gag
//
if(binding->triggered)
{
GetEventManager()->TriggerEvent( EVENT_INTERACTIVE_GAG );
}
Enter(pCharacter);
pCharacter->AddActionButtonHandler(this);
}
else
{
Exit(pCharacter);
pCharacter->RemoveActionButtonHandler(this);
}
}
else
{
if(loc->GetPlayerEntered())
{
Play();
}
}
}
protected:
friend class GagDrawable;
InteriorManager::GagBinding* binding;
EventLocator* locator;
SphereTriggerVolume* trigger;
GagDrawable* draw;
NISPlayer* gagPlayer;
sim::CollisionObject* collObj;
bool mLoaded;
bool mLoading;
int mTimeToCameraShake;
int mTimeToCameraShakeEnd;
int mTimeToCoinSpawn;
bool sparkle;
bool mSoundLoaded;
bool playing;
bool m_isNISSoundComplete;
virtual bool OnButtonPressed( Character* pCharacter, Sequencer* pSeq )
{
Play();
return true;
}
};
GagDrawable::GagDrawable(Gag* g) : gag(g), mPose(NULL)
{
mPosn.Set(0.0f, 0.0f, 0.0f);
mpDrawstuff = gag->gagPlayer->GetDrawable();
mpDrawstuff->AddRef();
mTranslucent = true;
// I need to go take a shower after this
for(int i = 0; i < NUM_OPAQUES; i++)
{
if(strcmp(sOpaques[i], gag->binding->gagFileName) == 0)
{
mTranslucent = false;
}
}
useTranslate = false;
sparkleStrength = 0.0f;
if(g->collObj)
{
tCompositeDrawable* cd = dynamic_cast<tCompositeDrawable*>(mpDrawstuff);
if(cd && gag->binding->animBV)
{
mPose = new poser::Pose(cd->GetPose());
SetSimState(sim::SimStateArticulated::CreateSimStateArticulated(mPose, g->collObj, NULL));
mpSimStateObj->SetControl(sim::simAICtrl);
mpSimStateObj->GetCollisionObject()->SetIsStatic(false);
}
else
{
SetSimState(sim::SimState::CreateStaticSimState(g->collObj));
mpSimStateObj->GetCollisionObject()->SetIsStatic(false);
}
}
}
void GagDrawable::Display()
{
if((gag->binding->i_S_Movie == 1) && (GetCharacterSheetManager()->QueryFMVUnlocked(RenderEnums::L3)))
{
return;
}
if(useTranslate)
{
p3d::stack->Push();
p3d::stack->Translate(mPosn);
}
gag->Render();
if(useTranslate)
{
p3d::stack->Pop();
}
if((sparkleStrength > 0.0f) && gag->sparkle)
{
float size = gag->binding->interiorUID == static_cast< tUID >( 0 ) ? 1.0f : 0.5f;
GetSparkleManager()->AddGagSparkle(gag->binding->triggerPos, size, sparkleStrength, (unsigned int)this);
}
}
class InteriorExit : public ActionButton::ButtonHandler
{
public:
virtual bool OnButtonPressed( Character* pCharacter, Sequencer* pSeq )
{
if( cGuiManagerInGameActive && !GetGuiSystem()->GetInGameManager()->IsEnteringPauseMenu() )
{
GetEventManager()->TriggerEvent( EVENT_EXIT_INTERIOR_START );
}
return true;
}
};
//******************************************************************************
//
// Public Member Functions
//
//******************************************************************************
//==============================================================================
// InteriorManager::CreateInstance
//==============================================================================
//
// Description: Creates the InteriorManager.
//
// Parameters: None.
//
// Return: Pointer to the InteriorManager.
//
// Constraints: This is a singleton so only one instance is allowed.
//
//==============================================================================
InteriorManager* InteriorManager::CreateInstance()
{
s_InteriorCentres[0].name.SetText("SpringfieldElementary");
s_InteriorCentres[0].centre.Set(500, -20, -350);
s_InteriorCentres[0].level = RenderEnums::L1;
s_InteriorCentres[1].name.SetText("KwikEMart");
s_InteriorCentres[1].centre.Set(500, -20, -300);
s_InteriorCentres[1].level = RenderEnums::L1;
s_InteriorCentres[2].name.SetText("SimpsonsHouse");
s_InteriorCentres[2].centre.Set(500, -20, -400);
s_InteriorCentres[2].level = RenderEnums::L1;
s_InteriorCentres[3].name.SetText("dmv");
s_InteriorCentres[3].centre.Set(0, -20, -200);
s_InteriorCentres[3].level = RenderEnums::L2;
s_InteriorCentres[4].name.SetText("moe1");
s_InteriorCentres[4].centre.Set(50, -20, -200);
s_InteriorCentres[4].level = RenderEnums::L2;
s_InteriorCentres[5].name.SetText("Android");
s_InteriorCentres[5].centre.Set(0, -20, -350);
s_InteriorCentres[5].level = RenderEnums::L3;
s_InteriorCentres[6].name.SetText("Observatory");
s_InteriorCentres[6].centre.Set(150, -20, -350);
s_InteriorCentres[6].level = RenderEnums::L3;
s_InteriorCentres[7].name.SetText("bartroom");
s_InteriorCentres[7].centre.Set(500, -20, -450);
s_InteriorCentres[7].level = RenderEnums::L1;
MEMTRACK_PUSH_GROUP( "InteriorManager" );
rAssert( spInstance == NULL );
spInstance = new InteriorManager;
rAssert( spInstance );
MEMTRACK_POP_GROUP("InteriorManager");
return spInstance;
}
const tName& InteriorManager::ClassifyPoint(const rmt::Vector& point)
{
static tName none((tUID)0);
for(int i = 0; i < 8; i++)
{
if((GetGameplayManager()->GetCurrentLevelIndex() % 3) == s_InteriorCentres[i].level)
{
rmt::Vector dist = point - s_InteriorCentres[i].centre;
if(dist.Magnitude() < 24.0f)
{
return s_InteriorCentres[i].name;
}
}
}
return none;
}
//==============================================================================
// InteriorManager::GetInstance
//==============================================================================
//
// Description: - Access point for the InteriorManager singleton.
//
// Parameters: None.
//
// Return: Pointer to the InteriorManager.
//
// Constraints: This is a singleton so only one instance is allowed.
//
//==============================================================================
InteriorManager* InteriorManager::GetInstance()
{
rAssert( spInstance != NULL );
return spInstance;
}
//==============================================================================
// InteriorManager::DestroyInstance
//==============================================================================
//
// Description: Destroy the InteriorManager.
//
// Parameters: None.
//
// Return: None.
//
//==============================================================================
void InteriorManager::DestroyInstance()
{
rAssert( spInstance != NULL );
delete( GMA_PERSISTENT, spInstance );
spInstance = NULL;
}
//==============================================================================
// InteriorManager::OnBootupStart
//==============================================================================
//
// Description:
//
// Parameters: None.
//
// Return: None.
//
//==============================================================================
void InteriorManager::OnBootupStart()
{
GetEventManager()->AddListener( this, EVENT_INTERIOR_LOAD_START );
GetEventManager()->AddListener( this, EVENT_INTERIOR_LOADED );
GetEventManager()->AddListener( this, EVENT_INTERIOR_DUMPED );
GetEventManager()->AddListener( this, EVENT_ENTER_INTERIOR_START );
GetEventManager()->AddListener( this, EVENT_EXIT_INTERIOR_START );
GetEventManager()->AddListener( this, EVENT_ENTER_INTERIOR_TRANSITION_START );
GetEventManager()->AddListener( this, EVENT_ENTER_INTERIOR_TRANSITION_END );
GetEventManager()->AddListener( this, static_cast<EventEnum>(EVENT_LOCATOR + LocatorEvent::INTERIOR_EXIT) );
GetEventManager()->AddListener( this, static_cast<EventEnum>(EVENT_LOCATOR + LocatorEvent::GAG) );
GetEventManager()->AddListener( this, EVENT_GUI_IRIS_WIPE_CLOSED );
GetEventManager()->AddListener( this, EVENT_GUI_IRIS_WIPE_OPEN );
GetEventManager()->AddListener( this, EVENT_CHARACTER_POS_RESET );
GetConsole()->AddFunction( "ClearGagBindings",
InteriorManager::ConsoleClearGagBindings,
"ClearGagBindings();",
0, 0 );
GetConsole()->AddFunction( "AddGagBinding",
InteriorManager::ConsoleAddGagBinding,
"AddGagBinding(InteriorName, GagFileName, CycleMode, Weight, SoundResourceName);",
5, 5 );
GetConsole()->AddFunction( "GagBegin",
InteriorManager::ConsoleGagBegin,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetInterior",
InteriorManager::ConsoleGagSetInterior,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetCycle",
InteriorManager::ConsoleGagSetCycle,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetWeight",
InteriorManager::ConsoleGagSetWeight,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetSound",
InteriorManager::ConsoleGagSetSound,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetTrigger",
InteriorManager::ConsoleGagSetTrigger,
",",
3, 5 );
GetConsole()->AddFunction( "GagPlayFMV", InteriorManager::ConsoleGagPlayFMV,
"Play FMV specified by file name", 1, 1 );
GetConsole()->AddFunction( "GagSetPosition",
InteriorManager::ConsoleGagSetPosition,
",",
1, 3 );
GetConsole()->AddFunction( "GagSetRandom",
InteriorManager::ConsoleGagSetRandom,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetIntro",
InteriorManager::ConsoleGagSetIntro,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetOutro",
InteriorManager::ConsoleGagSetOutro,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetCameraShake",
InteriorManager::ConsoleGagSetCameraShake,
",",
2, 3 );
GetConsole()->AddFunction( "GagSetCoins",
InteriorManager::ConsoleGagSetCoins,
",",
1, 2 );
GetConsole()->AddFunction( "GagSetSparkle",
InteriorManager::ConsoleGagSetSparkle,
",",
1, 1 );
GetConsole()->AddFunction( "GagSetAnimCollision",
InteriorManager::ConsoleGagSetAnimCollision,
",",
1, 1 );
GetConsole()->AddFunction( "GagEnd",
InteriorManager::ConsoleGagEnd,
",",
0, 0 );
GetConsole()->AddFunction( "GagSetLoadDistances",
InteriorManager::ConsoleGagSetLoadDistances,
",",
2, 2 );
GetConsole()->AddFunction( "GagSetSoundLoadDistances",
InteriorManager::ConsoleGagSetSoundLoadDistances,
",",
2, 2 );
GetConsole()->AddFunction( "GagSetPersist",
InteriorManager::ConsoleGagSetPersist,
",",
1, 1 );
GetConsole()->AddFunction( "GagCheckCollCards",
InteriorManager::ConsoleGagCheckCollCards,
",",
5, 5);
GetConsole()->AddFunction( "GagCheckMovie",
InteriorManager::ConsoleGagCheckMovie,
",",
4, 4);
}
//==============================================================================
// InteriorManager::OnMissionRestart
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::OnMissionRestart()
{
}
//==============================================================================
// InteriorManager::OnGameplayStart
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::OnGameplayStart()
{
if(!mLoadedGags)
{
mEntryRequested = false;
LoadGagNIS(0);
}
mCollectionEffect = new AnimatedIcon();
rAssert(mCollectionEffect);
}
//==============================================================================
// InteriorManager::OnGameplayEnd
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::OnGameplayEnd()
{
ClearGags();
this->ClearGagBindings();
SwitchToExterior();
delete mCollectionEffect;
mCollectionEffect = 0;
}
//=============================================================================
// InteriorManager::UnloadGagSounds
//=============================================================================
// Description: We need to do this before movies get played (i.e. Larry the
// Looter)
//
// Parameters: None
//
// Return: void
//
//=============================================================================
void InteriorManager::UnloadGagSounds()
{
int i;
for( i = 0; i < mGagCount; i++ )
{
gags[i]->SoundUnload();
}
}
void InteriorManager::Enter(InteriorEntranceLocator* entry, Character* pCharacter, Sequencer* pSeq)
{
//
// Once this sequence starts, we're on autopilot until the character
// appears and hits his cue in the interior so disable controller input.
//
pCharacter->GetController()->SetActive( false );
rmt::Matrix transform = entry->GetTransform();
rmt::Vector standPosition;
entry->GetLocation( &standPosition ) ;
Action* pAction = 0;
// trigger the event.
//
pSeq->BeginSequence();
pAction = new TriggerEventAction( EVENT_ENTER_INTERIOR_START, (void*)&mLoadedInteriorUID );
pSeq->AddAction( pAction );
pAction = new TriggerEventAction( EVENT_ENTER_INTERIOR_TRANSITION_START, (void*)&mLoadedInteriorUID );
pSeq->AddAction( pAction );
pSeq->EndSequence( );
// Walk to entry point
/*
pSeq->BeginSequence();
pAction = new Arrive( pCharacter, standPosition );
pSeq->AddAction( pAction );
pAction = pCharacter->GetWalkerLocomotionAction();
pSeq->AddAction( pAction );
pSeq->EndSequence();
*/
// Orient
rmt::Vector direction = transform.Row( 2 );
direction.y = 0.0f;
// If direction != 0, 0, 0, then rotate us to align with direction.
//
if ( direction.NormalizeSafe( ) )
{
pSeq->BeginSequence();
pAction = new Orient( pCharacter, direction );
pSeq->AddAction( pAction );
// SlaveLoco
//
pAction = 0;
pAction = pCharacter->GetWalkerLocomotionAction();
pSeq->AddAction( pAction );
pSeq->EndSequence( );
}
/*
// Move character.
//
pSeq->BeginSequence();
pAction = new Position( pCharacter, standPosition, 0.1f );
pSeq->AddAction( pAction );
pSeq->EndSequence( );
*/
}
//==============================================================================
// InteriorManager::Update
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::Update( unsigned int elapsedTime )
{
for(int i = 0; i < mGagCount; i++)
{
if(gags[i])
{
gags[i]->Update(elapsedTime);
}
}
if(mInteriorAnimations)
{
mInteriorAnimations->Advance((float)elapsedTime);
}
AttemptEntry();
mCollectionEffect->Update(elapsedTime);
}
//==============================================================================
// InteriorManager::HandleEvent
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::HandleEvent( EventEnum id, void* pEventData )
{
switch( id )
{
case EVENT_INTERIOR_LOAD_START:
{
rAssert( pEventData != 0 );
InteriorLoadedEventData* pData = reinterpret_cast<InteriorLoadedEventData*>( pEventData );
mSection = pData->sectionName.GetUID();
mLoadedInteriorUID = pData->interiorName.GetUID();
}
break;
case EVENT_ENTER_INTERIOR_TRANSITION_START:
{
mState = ENTER;
GetExitPos();
}
break;
case EVENT_INTERIOR_LOADED:
{
rAssert( pEventData != 0 );
InteriorLoadedEventData* pData = reinterpret_cast<InteriorLoadedEventData*>( pEventData );
mSection = pData->sectionName.GetUID();
mLoadedInteriorUID = pData->interiorName.GetUID();
mInteriorLoaded = true;
if(mIn)
{
SetupLightsAndAnims();
}
}
break;
case EVENT_INTERIOR_DUMPED:
{
mInteriorLoaded = false;
mLoadedInteriorUID = 0;
}
break;
case EVENT_CHARACTER_POS_RESET :
{
rmt::Vector pos;
GetCharacterManager()->GetCharacter(0)->GetPosition(pos);
LoadLevelGags(pos);
}
break;
case EVENT_GUI_IRIS_WIPE_OPEN:
{
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
pCharacter->GetController()->SetActive( true );
if(mState == ENTER)
{
mState = INSIDE;
}
if(mState == EXIT)
{
mState = NONE;
}
}
break;
case EVENT_GUI_IRIS_WIPE_CLOSED:
{
switch( mState )
{
case ENTER:
{
GetRenderManager()->mpLayer(RenderEnums::LevelSlot)->Freeze();
mEntryRequested = true;
mLoadedGags = false;
}
break;
case EXIT:
{
this->ExitInterior();
}
break;
default:
{
//rAssert( 0 );
}
}
}
break;
case EVENT_EXIT_INTERIOR_START:
{
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
pCharacter->GetController()->SetIntention( CharacterController::NONE );
pCharacter->GetController()->SetActive( false );
mState = EXIT;
}
break;
case EVENT_LOCATOR + LocatorEvent::INTERIOR_EXIT:
{
if((mState == INSIDE) || (mState == ENTER))
{
if(1)
{
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
EventLocator* loc = (EventLocator*)pEventData;
if(loc->GetPlayerEntered())
{
mExit->Enter(pCharacter);
pCharacter->AddActionButtonHandler(mExit);
}
else
{
mExit->Exit(pCharacter);
pCharacter->RemoveActionButtonHandler(mExit);
}
}
else
{
EventLocator* loc = (EventLocator*)pEventData;
if(loc->GetPlayerEntered())
{
mExit->OnButtonPressed(NULL, NULL);
}
}
}
}
break;
case EVENT_LOCATOR + LocatorEvent::GAG:
{
EventLocator* loc = (EventLocator*)pEventData;
for(int i = 0; i < mGagCount; i++)
{
if(loc->GetData() == (unsigned int)gags[i])
{
gags[i]->Trigger(loc);
}
}
}
break;
default:
{
}
}
}
//==============================================================================
// InteriorManager::ConsoleClearGagBindings
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::ConsoleClearGagBindings( int argc, char** argv )
{
GetInteriorManager()->ClearGagBindings();
}
void InteriorManager::ClearGagBindings()
{
for(int i = 0; i < mBindingCount; i++)
{
mGagBindings[i].Clear();
}
mBindingCount = 0;
sPersistGagIndex = 0;
}
//==============================================================================
// InteriorManager::ConsoleAddGagBinding
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::ConsoleAddGagBinding( int argc, char** argv )
{
// Convert interior name to UID
//
tUID interiorUID = tName::MakeUID( argv[1] );
char* gagFileName = argv[2];
// Select cycle mode.
//
p3dCycleMode cycleMode;
if( !strcmp( "default", argv[3] ) )
{
cycleMode = DEFAULT_CYCLE_MODE;
}
else if( !strcmp( "cycle", argv[3] ) )
{
cycleMode = FORCE_CYCLIC;
}
else if( !strcmp( "single", argv[3] ) )
{
cycleMode = FORCE_NON_CYCLIC;
}
else
{
rAssertMsg( 0, "Invalid cycle mode" );
cycleMode = DEFAULT_CYCLE_MODE;
}
// Assign weighted probability of selecting gag.
//
int weight = atoi( argv[4] );
//
// Get the name of the sound resource to play with this gag
//
char* gagSound = argv[5];
// Send it on down...
//
GetInteriorManager()->AddGagBinding( interiorUID, gagFileName, cycleMode, weight, gagSound );
}
//==============================================================================
// InteriorManager::AddGagBinding
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::AddGagBinding
(
tUID interiorUID,
char* gagFileName,
p3dCycleMode cycleMode,
int weight,
char* gagSound
)
{
// Can raise the max if necessary.
//
rAssert( mBindingCount < MAX_BINDINGS );
// Convert interior name to UID
//
mGagBindings[mBindingCount].interiorUID = interiorUID;
// Save the gag filename.
//
rAssert( strlen( gagFileName ) < 13 );
strcpy( mGagBindings[mBindingCount].gagFileName, gagFileName );
// Select cycle mode.
//
mGagBindings[mBindingCount].cycleMode = cycleMode;
// Assign weighted probability of selecting gag.
//
mGagBindings[mBindingCount].weight = weight;
//
// Make a radKey out of the gag sound name
//
mGagBindings[mBindingCount].soundID = ::radMakeKey32( gagSound );
mGagBindings[ mBindingCount ].gagFMVFileName[ 0 ] = 0;
if(mGagBindings[mBindingCount].interiorUID)
{
if(!mGagBindings[ mBindingCount ].useGagLocator)
{
mGagBindings[ mBindingCount ].useGagLocator = true;
mGagBindings[ mBindingCount ].gagLoc = tEntity::MakeUID("InteriorOrigin");
}
}
++mBindingCount;
}
void InteriorManager::GagBegin(char* gagFileName)
{
rAssert(!mBuildingGag);
mBuildingGag = true;
// Can raise the max if necessary.
rAssert( mBindingCount < MAX_BINDINGS );
// Save the gag filename.
rAssert( strlen( gagFileName ) < 13 );
strcpy( mGagBindings[mBindingCount].gagFileName, gagFileName );
}
InteriorManager::GagBinding* InteriorManager::GetBuildBinding(void)
{
rAssert(mBuildingGag);
return &mGagBindings[mBindingCount];
}
void InteriorManager::GagEnd(void)
{
rAssert(mBuildingGag);
mBuildingGag = false;
if((mGagBindings[mBindingCount].i_S_Movie == 1) && (GetCharacterSheetManager()->IsState(1)))
{
// Oops we've already got the ticket! Don't put it in again.
mGagBindings[mBindingCount].Clear();
return;
}
++mBindingCount;
}
void InteriorManager::ConsoleGagBegin(int argc, char** argv )
{
GetInteriorManager()->GagBegin(argv[1]);
}
void InteriorManager::ConsoleGagSetInterior(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->interiorUID = tEntity::MakeUID(argv[1]);
if(GetInteriorManager()->GetBuildBinding()->interiorUID)
{
if(!GetInteriorManager()->GetBuildBinding()->useGagLocator)
{
GetInteriorManager()->GetBuildBinding()->useGagLocator = true;
GetInteriorManager()->GetBuildBinding()->gagLoc = tEntity::MakeUID("InteriorOrigin");
}
}
}
void InteriorManager::ConsoleGagSetCycle(int argc, char** argv )
{
// Select cycle mode.
//
p3dCycleMode cycleMode;
if( !strcmp( "default", argv[1] ) )
{
cycleMode = DEFAULT_CYCLE_MODE;
}
else if( !strcmp( "cycle", argv[1] ) )
{
cycleMode = FORCE_CYCLIC;
}
else if( !strcmp( "single", argv[1] ) )
{
cycleMode = FORCE_NON_CYCLIC;
}
else if( !strcmp( "reset", argv[1] ) )
{
cycleMode = FORCE_NON_CYCLIC;
GetInteriorManager()->GetBuildBinding()->retrigger = true;
}
else
{
rAssertMsg( 0, "Invalid cycle mode" );
cycleMode = DEFAULT_CYCLE_MODE;
}
GetInteriorManager()->GetBuildBinding()->cycleMode = cycleMode;
}
void InteriorManager::ConsoleGagSetWeight(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->weight = atoi(argv[1]);
}
void InteriorManager::ConsoleGagSetSound(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->soundID = ::radMakeKey32(argv[1]);
}
void InteriorManager::ConsoleGagSetIntro( int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->loopIntro = atoi(argv[1]);
}
void InteriorManager::ConsoleGagSetOutro( int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->loopOutro = atoi(argv[1]);
}
/*=============================================================================
Description: Play the FMV specified by file name. Note that PlayFMV causes
the HUD to be un/reloaded.
=============================================================================*/
void InteriorManager::ConsoleGagPlayFMV( int argc, char** argv )
{
rAssert( argc > 1 );
rAssert( strlen( argv[ 1 ] ) < 13 ); // Enforce 8.3 file naming.
strcpy( GetInteriorManager()->GetBuildBinding()->gagFMVFileName, argv[ 1 ] );
}
void InteriorManager::ConsoleGagSetTrigger(int argc, char** argv )
{
rAssert((argc == 4) || (argc == 6));
GetInteriorManager()->GetBuildBinding()->triggered = true;
if( strcmp( "touch", argv[1] ) == 0 )
{
GetInteriorManager()->GetBuildBinding()->action = false;
}
else if( strcmp( "action", argv[1]) == 0 )
{
GetInteriorManager()->GetBuildBinding()->action = true;
}
if(argc == 4)
{
GetInteriorManager()->GetBuildBinding()->useTriggerLocator = true;
GetInteriorManager()->GetBuildBinding()->triggerLoc = tEntity::MakeUID(argv[2]);
}
else
{
GetInteriorManager()->GetBuildBinding()->useTriggerLocator = false;
GetInteriorManager()->GetBuildBinding()->triggerPos.Set((float)atof(argv[2]), (float)atof(argv[3]), (float)atof(argv[4]));
}
GetInteriorManager()->GetBuildBinding()->triggerRadius = (float)atof(argv[argc-1]);
}
void InteriorManager::ConsoleGagSetPosition(int argc, char** argv )
{
rAssert((argc == 2) || (argc == 4));
if(argc == 2)
{
GetInteriorManager()->GetBuildBinding()->useGagLocator = true;
GetInteriorManager()->GetBuildBinding()->gagLoc = tEntity::MakeUID(argv[1]);
}
else
{
GetInteriorManager()->GetBuildBinding()->useGagLocator = false;
GetInteriorManager()->GetBuildBinding()->gagPos.Set((float)atof(argv[1]), (float)atof(argv[2]), (float)atof(argv[3]));
}
}
void InteriorManager::ConsoleGagSetRandom(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->random = atoi(argv[1]) != 0;
}
void InteriorManager::ConsoleGagSetCameraShake(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->cameraShake = true;
GetInteriorManager()->GetBuildBinding()->shakeDelay = (float)atof(argv[1]);
GetInteriorManager()->GetBuildBinding()->shake.force = (float)atof(argv[2]);
if(argc == 4)
{
GetInteriorManager()->GetBuildBinding()->shakeDuration = (float)atof(argv[3]);
GetInteriorManager()->GetBuildBinding()->shake.looping = GetInteriorManager()->GetBuildBinding()->shakeDuration != 0.0f;
}
}
void InteriorManager::ConsoleGagSetCoins(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->coins = atoi(argv[1]);
if(argc == 3)
{
GetInteriorManager()->GetBuildBinding()->coinDelay = (float)atof(argv[2]);
}
}
void InteriorManager::ConsoleGagSetSparkle(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->sparkle = atoi(argv[1]) != 0;
}
void InteriorManager::ConsoleGagSetAnimCollision(int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->animBV = atoi(argv[1]) != 0;
}
void InteriorManager::ConsoleGagSetLoadDistances( int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->loadDist = atoi(argv[1]);
GetInteriorManager()->GetBuildBinding()->unloadDist = atoi(argv[2]);
}
void InteriorManager::ConsoleGagSetSoundLoadDistances( int argc, char** argv )
{
GetInteriorManager()->GetBuildBinding()->soundLoadDist = atoi(argv[1]);
GetInteriorManager()->GetBuildBinding()->soundUnloadDist = atoi(argv[2]);
}
void InteriorManager::ConsoleGagSetPersist( int argc, char** argv )
{
if(atoi(argv[1]))
{
GetInteriorManager()->GetBuildBinding()->persistIndex = sPersistGagIndex++;
}
else
{
GetInteriorManager()->GetBuildBinding()->persistIndex = -1;
}
}
void InteriorManager::ConsoleGagCheckCollCards(int argc, char** argv)
{
GetInteriorManager()->GetBuildBinding()->i_S_Movie = 1;
unsigned int len = strlen(argv[1]) < DialogueObjective::MAX_CHAR_NAME_LEN - 1 ? strlen(argv[1]) : DialogueObjective::MAX_CHAR_NAME_LEN - 2;
strncpy( GetInteriorManager()->GetBuildBinding()->dialogChar1, argv[1], len );
GetInteriorManager()->GetBuildBinding()->dialogChar1[len] = '\0';
len = strlen(argv[2]) < DialogueObjective::MAX_CHAR_NAME_LEN - 1 ? strlen(argv[2]) : DialogueObjective::MAX_CHAR_NAME_LEN - 2;
strncpy( GetInteriorManager()->GetBuildBinding()->dialogChar2, argv[2], len );
GetInteriorManager()->GetBuildBinding()->dialogChar2[len] = '\0';
GetInteriorManager()->GetBuildBinding()->acceptDialogID = ::radMakeKey32(argv[3]);
GetInteriorManager()->GetBuildBinding()->instructDialogID = ::radMakeKey32(argv[4]);
GetInteriorManager()->GetBuildBinding()->rejectDialogID = ::radMakeKey32(argv[5]);
}
void InteriorManager::ConsoleGagCheckMovie(int argc, char** argv)
{
GetInteriorManager()->GetBuildBinding()->i_S_Movie = 2;
unsigned int len = strlen(argv[1]) < DialogueObjective::MAX_CHAR_NAME_LEN - 1 ? strlen(argv[1]) : DialogueObjective::MAX_CHAR_NAME_LEN - 2;
strncpy( GetInteriorManager()->GetBuildBinding()->dialogChar1, argv[1], len );
GetInteriorManager()->GetBuildBinding()->dialogChar1[len] = '\0';
len = strlen(argv[2]) < DialogueObjective::MAX_CHAR_NAME_LEN - 1 ? strlen(argv[2]) : DialogueObjective::MAX_CHAR_NAME_LEN - 2;
strncpy( GetInteriorManager()->GetBuildBinding()->dialogChar2, argv[2], len );
GetInteriorManager()->GetBuildBinding()->dialogChar2[len] = '\0';
rAssert( strlen( argv[ 3 ] ) < 13 ); // Enforce 8.3 file naming.
strcpy( GetInteriorManager()->GetBuildBinding()->gagFMVFileName, argv[ 3 ] );
GetInteriorManager()->GetBuildBinding()->rejectDialogID = ::radMakeKey32(argv[4]);
}
void InteriorManager::ConsoleGagEnd(int argc, char** argv )
{
GetInteriorManager()->GagEnd();
}
void InteriorManager::LoadLevelGags(const rmt::Vector& startPos, bool initial)
{
tUID interior = ClassifyPoint(startPos).GetUID();
bool needTo = true;
if(!initial)
{
// this will happen if we are trying to reset from one interior into another
// the mission system sends too many events, so we'll ignore the bogus ones
if(!((interior == static_cast< tUID >( 0 )) || (interior == mLoadedInteriorUID)))
{
return;
}
needTo = mCurrentInteriorUID != interior;
}
if(needTo)
{
mCurrentInteriorUID = interior;
if(mCurrentInteriorUID)
{
LoadGagNIS(mCurrentInteriorUID);
mState = INSIDE;
mIn = true;
mEntryRequested = false;
GetExitPos();
SwitchToInterior();
}
else
{
mState = NONE;
mEntryRequested = false;
SwitchToExterior();
LoadGagNIS(0);
}
GetCharacterManager()->GetCharacter(0)->SetPosition(startPos);
for(int i = 0; i < mGagCount; i++)
{
if(gags[i])
{
gags[i]->Update(0);
}
}
}
}
//******************************************************************************
//
// Private Member Functions
//
//******************************************************************************
//==============================================================================
// InteriorManager::InteriorManager
//==============================================================================
//
// Description: Constructor.
//
// Parameters: None.
//
// Return: N/A.
//
//==============================================================================
InteriorManager::InteriorManager()
:
mEntryRequested( false ),
mInteriorLoaded( false ),
mLoadedInteriorUID( 0 ),
mCurrentInteriorUID( 0 ),
mCollectionEffect(0),
mIn (false),
mBindingCount( 0 ),
mGagCount(0),
mBuildingGag(false),
mExit(new InteriorExit),
mInteriorAnimations(NULL),
m_isPlayingISDialog( false )
{
mExit->AddRef();
for(int i = 0; i < MAX_GAGS; i++)
{
gags[i] = NULL;
}
if (!sRandomSeeded)
{
sRandom.Seed (Game::GetRandomSeed ());
sRandomSeeded = true;
}
}
//==============================================================================
// InteriorManager::~InteriorManager
//==============================================================================
//
// Description: Destructor.
//
// Parameters: None.
//
// Return: N/A.
//
//==============================================================================
InteriorManager::~InteriorManager()
{
mExit->Release();
GetEventManager()->RemoveAll(this);
ClearGags();
}
//==============================================================================
void InteriorManager::SwitchToInterior()
{
if(mLoadedInteriorUID != tUID(0))
{
mCurrentInteriorUID = mLoadedInteriorUID;
}
if(mCurrentInteriorUID == tEntity::MakeUID("moe1"))
{
static rmt::Matrix mirrorMatrix(-1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, 1.0f, 0.0f,
109.5f, 0.0f, 0.0f, 1.0f);
WorldRenderLayer* pWorldRenderLayer = static_cast< WorldRenderLayer* > (GetRenderManager()->mpLayer( RenderEnums::LevelSlot ));
pWorldRenderLayer->SetMirror(true, &mirrorMatrix);
Character* moe = GetCharacterManager()->GetCharacterByName("moe");
if(moe && moe->IsAmbient())
{
moe->ResetAmbientPosition();
}
} else if(mCurrentInteriorUID == tEntity::MakeUID("bartroom"))
{
static rmt::Matrix mirrorMatrix(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f,
0.0f, 0.0f, -894.0f, 1.0f);
WorldRenderLayer* pWorldRenderLayer = static_cast< WorldRenderLayer* > (GetRenderManager()->mpLayer( RenderEnums::LevelSlot ));
pWorldRenderLayer->SetMirror(true, &mirrorMatrix);
}
SetupLightsAndAnims();
mIn = true;
GetEventManager()->TriggerEvent(EVENT_INTERIOR_SWITCH, (void*)1);
}
void InteriorManager::SetupLightsAndAnims()
{
// Setup the lights.
//
p3d::inventory->PushSection();
p3d::inventory->SelectSection(mSection);
p3d::inventory->SetCurrentSectionOnly(true);
tLightGroup* pLightGroup = p3d::find<tLightGroup>("InteriorLightGroup");
if( !pLightGroup )
{
pLightGroup = p3d::find<tLightGroup>("LightGroup");
}
if( pLightGroup )
{
RenderLayer* rl = GetRenderManager()->mpLayer(RenderEnums::LevelSlot);
rAssert(rl);
tView* view = rl->pView( PLAYER_ONE );
if(view == 0)
{
// We've come in here before the view has been set up by the render manager.
rl->SetUpViewCam();
view = rl->pView(PLAYER_ONE);
}
rAssert(view);
view->RemoveAllLights();
for( int i = 0; i < pLightGroup->GetNumLights(); ++i )
{
tLight* light = pLightGroup->GetLight( i );
rAssert( light != NULL );
if( light != NULL )
{
GetRenderManager()->mpLayer(RenderEnums::LevelSlot)->pView( PLAYER_ONE )->AddLight( light );
}
}
}
tRefCounted::Assign(mInteriorAnimations, p3d::find<tFrameController>("MasterController"));
p3d::inventory->SetCurrentSectionOnly(false);
if(mInteriorAnimations)
{
mInteriorAnimations->SetCycleMode(FORCE_CYCLIC);
}
p3d::inventory->PopSection();
}
//==============================================================================
void InteriorManager::AttemptEntry()
{
if( mEntryRequested && mInteriorLoaded && !mIn)
{
SwitchToInterior();
//----------------------------------------------------------------------
// Teleport the character to the interior.
//----------------------------------------------------------------------
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
rAssert( pCharacter != 0 );
p3d::inventory->PushSection();
p3d::inventory->SelectSection(mSection);
p3d::inventory->SetCurrentSectionOnly(true);
// Find the end locator.
//
DirectionalLocator* pEndLoc = p3d::find<DirectionalLocator>( "InteriorEntryEnd" );
rAssert( pEndLoc != 0 );
p3d::inventory->SetCurrentSectionOnly(false);
p3d::inventory->PopSection();
rmt::Matrix endTransform = pEndLoc->GetTransform();
rmt::Vector standPosition;
pEndLoc->GetLocation( &standPosition ) ;
// Put the character in position.
//
rmt::Matrix transform = pEndLoc->GetTransform();
float facingDir = choreo::GetWorldAngle( transform.Row(2).x, transform.Row(2).z );
pCharacter->RelocateAndReset(standPosition, facingDir);
}
if( !mLoadedGags && mEntryRequested && !GetLoadingManager()->IsLoading())
{
mLoadedGags = true;
LoadGagNIS(mLoadedInteriorUID);
}
else if( mEntryRequested && mInteriorLoaded && mLoadedGags && !GetLoadingManager()->IsLoading())
{
GetRenderManager()->mpLayer(RenderEnums::LevelSlot)->Thaw();
mEntryRequested = false;
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
pCharacter->GetActionController()->Clear();
Sequencer* pSeq = pCharacter->GetActionController()->GetNextSequencer();
Action* pAction = 0;
// Wait a while for camera to reorient itself
pSeq->BeginSequence();
pSeq->AddAction( new DelayAction(0.5f));
pSeq->EndSequence();
// Open Iris
//
pSeq->BeginSequence();
pAction = new TriggerEventAction( EVENT_ENTER_INTERIOR_TRANSITION_END, (void*)pCharacter );
pSeq->AddAction( pAction );
pSeq->EndSequence();
// Finish
//
pSeq->BeginSequence();
pAction = new TriggerEventAction( EVENT_ENTER_INTERIOR_END, (void*)pCharacter );
pSeq->AddAction( pAction );
pSeq->EndSequence();
GetSuperCamManager()->GetSCC( 0 )->SetIsInitialCamera(true);
}
}
void InteriorManager::SwitchToExterior()
{
if(!mIn)
return;
mCurrentInteriorUID = 0;
mIn = false;
// reset the exterior lights
//
tView* view = GetRenderManager()->mpLayer(RenderEnums::LevelSlot)->pView( PLAYER_ONE );
view->RemoveAllLights();
p3d::inventory->PushSection();
p3d::inventory->SelectSection("Default");
tLightGroup* sun = p3d::find<tLightGroup>("sun");
rAssert( sun );
p3d::inventory->PopSection();
for(int j=0;j<sun->GetNumLights();j++)
{
view->AddLight( sun->GetLight(j) );
}
tRefCounted::Release(mInteriorAnimations);
ClearGags();
// Show the HUD Map.
//
// GetGuiSystem()->HandleMessage( GUI_MSG_SHOW_HUD_OVERLAY, HUD_MAP );
WorldRenderLayer* pWorldRenderLayer = static_cast< WorldRenderLayer* > (GetRenderManager()->mpLayer( RenderEnums::LevelSlot ));
pWorldRenderLayer->SetMirror(false, NULL);
GetSuperCamManager()->GetSCC( 0 )->SetIsInitialCamera(true);
GetEventManager()->TriggerEvent(EVENT_INTERIOR_SWITCH, 0);
}
void InteriorManager::ExitInterior()
{
if(mState != EXIT)
return;
SwitchToExterior();
this->LoadGagNIS(0);
Character* pCharacter = GetCharacterManager()->GetCharacter( PLAYER_ONE );
rAssert( pCharacter != 0 );
// position the character outside
pCharacter->RelocateAndReset(mExitPos, mExitFacing);
pCharacter->GetActionController()->Clear();
Sequencer* pSeq = pCharacter->GetActionController()->GetNextSequencer();
// Wait a while for camera to reorient itself
pSeq->BeginSequence();
pSeq->AddAction( new DelayAction(1.0f));
pSeq->EndSequence();
// Open iris, and notify anyone else that might be interested
// (ambient sound, etc) that we are outside again
pSeq->BeginSequence();
pSeq->AddAction( new TriggerEventAction( EVENT_EXIT_INTERIOR_END, (void*)pCharacter ) );
pSeq->EndSequence();
}
//==============================================================================
// InteriorManager::LoadGagNIS
//==============================================================================
//
// Description:
//
// Parameters:
//
// Return:
//
//==============================================================================
void InteriorManager::LoadGagNIS(tUID interiorUID)
{
ClearGags();
int totalWeight = 0;
// Which gags are available for this interior?
//
int i;
for( i = 0; i < mBindingCount; ++i )
{
if( (mGagBindings[i].interiorUID == interiorUID) && mGagBindings[i].random)
{
totalWeight += mGagBindings[i].weight;
}
}
int pick = 0;
if(totalWeight)
{
pick = sRandom.IntRanged(0,totalWeight-1);
}
totalWeight = 0;
for( i = 0; i < mBindingCount; ++i )
{
if( (mGagBindings[i].interiorUID == interiorUID) && mGagBindings[i].random)
{
if((pick >= totalWeight) && (pick < (totalWeight + mGagBindings[i].weight)))
{
HeapMgr()->PushHeap(GMA_LEVEL_OTHER);
rAssert(mGagCount < MAX_GAGS);
gags[mGagCount] = new Gag(&mGagBindings[i]);
gags[mGagCount]->AddRef();
mGagCount++;
HeapMgr()->PopHeap(GMA_LEVEL_OTHER);
}
totalWeight += mGagBindings[i].weight;
}
else if( (mGagBindings[i].interiorUID == interiorUID) && !mGagBindings[i].random)
{
HeapMgr()->PushHeap(GMA_LEVEL_OTHER);
rAssert(mGagCount < MAX_GAGS);
gags[mGagCount] = new Gag(&mGagBindings[i]);
gags[mGagCount]->AddRef();
mGagCount++;
HeapMgr()->PopHeap(GMA_LEVEL_OTHER);
}
}
}
void InteriorManager::ClearGags()
{
for(int i = 0; i < mGagCount; i++)
{
tRefCounted::Release(gags[i]);
}
mGagCount = 0;
}
void InteriorManager::GetExitPos(void)
{
// get the position and facing of the exit locator
rmt::Vector heading;
Locator* loc = p3d::find<Locator>(mLoadedInteriorUID);
if(!loc)
{
loc = p3d::find<Locator>(mCurrentInteriorUID);
}
rAssert(loc);
loc->GetPosition(&mExitPos);
loc->GetHeading(&heading);
mExitFacing = choreo::GetWorldAngle( heading.x, heading.z ) + rmt::PI;
}
void InteriorManager::CollectionEffect(const char* Name, const rmt::Vector& Pos)
{
mCollectionEffect->Init(Name, Pos, true, true);
}