//============================================================================= // 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 // for rand() // Ftech #include #include #include #include #include #include //======================================== // Project Includes //======================================== #include #include #include #include #include #include #include #include #include
#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include //****************************************************************************** // // 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("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(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(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(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(EVENT_LOCATOR + LocatorEvent::INTERIOR_EXIT) ); GetEventManager()->AddListener( this, static_cast(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( 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( 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("InteriorLightGroup"); if( !pLightGroup ) { pLightGroup = p3d::find("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("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( "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("sun"); rAssert( sun ); p3d::inventory->PopSection(); for(int j=0;jGetNumLights();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(mLoadedInteriorUID); if(!loc) { loc = p3d::find(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); }