The-Simpsons-Hit-and-Run/game/code/presentation/presentation.cpp

1467 lines
47 KiB
C++

//=============================================================================
// Copyright (C) 2002 Radical Entertainment Ltd. All rights reserved.
//
// File: presentation.cpp
//
// Description: Implement PresentationManager
//
// History: 16/04/2002 + Created -- NAME
//
//=============================================================================
//========================================
// System Includes
//========================================
// Foundation Tech
#include <raddebug.hpp>
#include <raddebugwatch.hpp>
#include <p3d/view.hpp>
//========================================
// Project Includes
//========================================
#include <events/eventmanager.h>
#include <events/eventenum.h>
#include <events/eventdata.h>
#include <memory/srrmemory.h>
#include <contexts/context.h>
#include <contexts/bootupcontext.h>
#include <contexts/gameplay/gameplaycontext.h>
#include <gameflow/gameflow.h>
#include <meta/eventlocator.h>
#include <meta/triggervolume.h>
#include <presentation/playerdrawable.h>
#include <presentation/presentation.h>
#include <presentation/presentationanimator.h>
#include <presentation/nisplayer.h>
#include <presentation/tutorialmanager.h>
#include <presentation/cameraplayer.h>
#include <presentation/transitionplayer.h>
#include <presentation/gui/guimanager.h>
#include <presentation/gui/guisystem.h>
#include <presentation/gui/guitextbible.h>
#include <presentation/gui/ingame/guimanageringame.h>
#include <presentation/gui/ingame/guiscreenhud.h>
#include <presentation/gui/ingame/guiscreenmissionload.h>
#include <presentation/mouthflapper.h>
#include <presentation/fmvplayer/fmvplayer.h>
#include <camera/supercammanager.h>
#include <camera/supercamcentral.h>
#include <camera/conversationcam.h>
#include <camera/isupercamtarget.h>
#include <worldsim/character/character.h>
#include <worldsim/character/charactermanager.h>
#include <worldsim/character/charactertarget.h>
#include <worldsim/avatarmanager.h>
#include <p3d/matrixstack.hpp>
#include <render/rendermanager/rendermanager.h>
#include <render/RenderManager/RenderLayer.h>
#include <render/enums/renderenums.h>
#include <mission/gameplaymanager.h>
#include <mission/objectives/missionobjective.h>
#include <screen.h>
//******************************************************************************
//
// Global Data, Local Data, Local Classes
//
//******************************************************************************
// Static pointer to instance of singleton.
PresentationManager* PresentationManager::spInstance = NULL;
const int PLAYER_ONE = 0;
const int MAX_DIALOG_LINES = 64;
#define MAX_CHARACTERS 64
//******************************************************************************
//
// Public Member Functions
//
//******************************************************************************
//=============================================================================
// PresentationManager::CreateInstance
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: PresentationManager
//
//=============================================================================
PresentationManager* PresentationManager::CreateInstance()
{
MEMTRACK_PUSH_GROUP( "PresentationManager" );
if( spInstance == NULL )
{
spInstance = new(GMA_PERSISTENT) PresentationManager;
rAssert( spInstance );
}
MEMTRACK_POP_GROUP( "PresentationManager" );
return spInstance;
}
//=============================================================================
// PresentationManager::GetInstance
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: PresentationManager
//
//=============================================================================
PresentationManager* PresentationManager::GetInstance()
{
return spInstance;
}
//=============================================================================
// PresentationManager::DestroyInstance
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void PresentationManager::DestroyInstance()
{
if( spInstance != NULL )
{
delete( GMA_PERSISTENT, spInstance );
spInstance = NULL;
}
}
//==============================================================================
// PresentationManager::PresentationManager
//==============================================================================
// Description: Constructor.
//
// Parameters: None.
//
// Return: N/A.
//
//==============================================================================
PresentationManager::PresentationManager() :
mTransitionPool( NULL ),
mNISPool( NULL ),
mFMVPool( NULL ),
mFIFOBegin( 0 ),
mFIFOEnd( 0 ),
mpCurrent( NULL ),
mpFMVPlayer( NULL ),
mpNISPlayer( NULL ),
mpCameraPlayer( NULL ),
mpTransitionPlayer( NULL ),
// mLanguage( Language::MAX_LANGUAGES ),
mp_PCAnimator( NULL ),
mp_NPCAnimator( NULL ),
mDialogLineNumber( -1 ),
mCameraForLineOfDialog(MAX_DIALOG_LINES),
mpPlayCallback( 0 ),
mWaitingOnFade( false ),
mOverlay( 0 )
{
mInConversation = false;
// mOldFOV= 0.0F;
unsigned int i;
for( i = 0; i < MAX_EVENT_SIZE; i++ )
{
mEventFIFO[ i ] = NULL;
}
// what is the current allocator
radMemoryAllocator current = HeapManager::GetInstance()->GetCurrentAllocator();
GameMemoryAllocator gmaCurrent = HeapManager::GetInstance()->GetCurrentHeap();
mFMVPool = new FMVEventPool( gmaCurrent, 10 );
mNISPool = new NISEventPool( gmaCurrent, 10 );
mTransitionPool = new TransitionEventPool( gmaCurrent, 10 );
mpNISPlayer = new NISPlayer();
mpCameraPlayer = new CameraPlayer();
mpTransitionPlayer = new TransitionPlayer();
mpFMVPlayer = new( current ) FMVPlayer();
mpPlayerDrawable = new PlayerDrawable();
mpPlayerDrawable->AddRef();
mOverlay = new PresentationOverlay();
mOverlay->AddRef();
mp_oldcam = NULL;
mOldCamIndexNum =0;
}
//==============================================================================
// PresentationManager::~PresentationManager
//==============================================================================
// Description: Destructor.
//
// Parameters: None.
//
// Return: N/A.
//
//==============================================================================
PresentationManager::~PresentationManager()
{
delete mFMVPool; mFMVPool = NULL;
delete mNISPool; mNISPool = NULL;
delete mTransitionPool; mTransitionPool = NULL;
delete mpNISPlayer; mpNISPlayer = NULL;
delete mpCameraPlayer; mpCameraPlayer = NULL;
delete mpTransitionPlayer; mpTransitionPlayer = NULL;
delete mpFMVPlayer; mpFMVPlayer = NULL;
this->FinalizePlayerDrawable();
mpPlayerDrawable->ReleaseVerified();
mOverlay->Release();
}
//=============================================================================
// PresentationManager::Initialize
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void PresentationManager::Initialize()
{
MEMTRACK_PUSH_GROUP( "PresentationManager" );
//Cary: I took this out since it was allocating to the levelslot when
//the level isn't even loaded. No one seems to know what it's for
//so Darryl probably did it and it's not used anymore. Feb 13th 2003
//pLayer = GetRenderManager()->mpLayer( RenderEnums::LevelSlot );
//pLayer->AddGuts( mpPlayerDrawable );
GetEventManager()->AddListener( this, EVENT_LOCATOR );
//Listen for Conversation
GetEventManager()->AddListener( this, EVENT_CONVERSATION_INIT );
GetEventManager()->AddListener( this, EVENT_CONVERSATION_SKIP );
GetEventManager()->AddListener( this, EVENT_CONVERSATION_DONE );
//Listen for MouthFlapping Cues
GetEventManager()->AddListener( this, EVENT_PC_TALK );
GetEventManager()->AddListener( this, EVENT_PC_SHUTUP );
GetEventManager()->AddListener( this, EVENT_NPC_TALK );
GetEventManager()->AddListener( this, EVENT_NPC_SHUTUP );
GetEventManager()->AddListener( this, EVENT_GUI_FADE_OUT_DONE );
rAssert( mp_PCAnimator == NULL );
rAssert( mp_NPCAnimator == NULL );
HeapMgr()->PushHeap( GMA_LEVEL_OTHER );
mp_PCAnimator = new PresentationAnimator();
mp_NPCAnimator = new PresentationAnimator();
HeapMgr()->PopHeap( GMA_LEVEL_OTHER );
MEMTRACK_POP_GROUP( "PresentationManager" );
}
//=============================================================================
// PresentationManager::Finalize
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void PresentationManager::Finalize()
{
mCameraForLineOfDialog.erase( mCameraForLineOfDialog.begin(), mCameraForLineOfDialog.end() );
mp_PCAnimator->SetCharacter( NULL );
mp_NPCAnimator->SetCharacter( NULL );
mp_PCAnimator->ClearAmbientAnimations();
mp_NPCAnimator->ClearAmbientAnimations();
//remove for Conversation
GetEventManager()->RemoveListener( this, EVENT_CONVERSATION_INIT );
GetEventManager()->RemoveListener( this, EVENT_CONVERSATION_SKIP );
GetEventManager()->RemoveListener( this, EVENT_CONVERSATION_DONE );
//remove for MouthFlapping Cues
GetEventManager()->RemoveListener( this, EVENT_PC_TALK );
GetEventManager()->RemoveListener( this, EVENT_PC_SHUTUP );
GetEventManager()->RemoveListener( this, EVENT_NPC_TALK );
GetEventManager()->RemoveListener( this, EVENT_NPC_SHUTUP );
delete mp_PCAnimator; mp_PCAnimator = NULL;
delete mp_NPCAnimator; mp_NPCAnimator = NULL;
}
//=============================================================================
// PresentationManager::InitializePlayerDrawable
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void
PresentationManager::InitializePlayerDrawable()
{
RenderLayer* pLayer = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( pLayer != NULL );
pLayer->pView( 0 )->SetClearColour( tColour( 0, 0, 0 ) );
pLayer->AddGuts( mpPlayerDrawable );
}
//=============================================================================
// PresentationManager::FinalizePlayerDrawable
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void
PresentationManager::FinalizePlayerDrawable()
{
RenderLayer* pLayer = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( pLayer != NULL );
pLayer->RemoveGuts( mpPlayerDrawable );
}
//=============================================================================
// PresentationManager::GetAnimatorNpc
//=============================================================================
// Description: returns the presentation animator for the NPC
//
// Parameters: NONE
//
// Return: pointer to the presentationanimator
//
//=============================================================================
PresentationAnimator* PresentationManager::GetAnimatorNpc()
{
return this->mp_NPCAnimator;
}
//=============================================================================
// PresentationManager::GetAnimatorPc
//=============================================================================
// Description: returns the presentation animator for the PC
//
// Parameters: NONE
//
// Return: pointer to the presentationanimator
//
//=============================================================================
PresentationAnimator* PresentationManager::GetAnimatorPc()
{
return this->mp_PCAnimator;
}
/*=============================================================================
Description: You're one stop method for playing an FMV during gameplay. It
unloads the HUD (for memory), plays the FMV, and then
reloads the HUD. Don't use this in the frontend as the
un/reloading of the frontend is a waste.
NOTE that the platform specific path for the movies is prepended
to the filename. So if you pass "fmv2.rmv" you'll get
"d:\movies\fmv2.rmv" on XBox, "movies\fmv2.rmv" on PS2,
"movies/fmv2.rmv" on GC.
=============================================================================*/
void PresentationManager::PlayFMV( const char* FileName,
PresentationEvent::PresentationEventCallBack* pCallback,
bool IsSkippable,
bool StopMusic,
bool IsLocalized )
{
// this puts the FMV player in the "loading" state
// this is needed so that the gag system can tell when a gag has ended
// (without this the state right before and right after the fmc playes is the same
mpFMVPlayer->PreLoad();
#ifdef RAD_E3
// no in-game FMV's for E3 build
//
if( pCallback != NULL )
{
pCallback->OnPresentationEventEnd( NULL );
}
return;
#endif
if( mOverlay )
{
//
// Hide the HUD
//
CGuiScreenHud* hud = dynamic_cast< CGuiScreenHud* >( GetGuiSystem()->GetInGameManager()->FindWindowByID( CGuiWindow::GUI_SCREEN_ID_HUD ) );
rAssert( hud != NULL );
Scrooby::Screen* screen = hud->GetScroobyScreen();
screen->SetAlpha( 0.0f );
mOverlay->SetStart( BLACK_TRANSPARENT );
mOverlay->SetEnd( BLACK );
mOverlay->SetDuration( 0.5f );
RenderLayer* pLayer = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( pLayer );
if( pLayer->IsDead() )
{
pLayer->Resurrect();
}
pLayer->Thaw();
pLayer->AddGuts( mOverlay );
}
mWaitingOnFade = true;
FMVEvent* pEvent = 0;
GetPresentationManager()->QueueFMV( &pEvent, this );
#ifdef RAD_XBOX
strcpy( pEvent->fileName, "D:\\movies\\" );
#elif RAD_PS2
strcpy( pEvent->fileName, "movies\\" );
#elif RAD_WIN32
strcpy( pEvent->fileName, "movies\\" );
#else
strcpy( pEvent->fileName, "movies/" );
#endif
strcat( pEvent->fileName, FileName );
pEvent->SetRenderLayer( RenderEnums::PresentationSlot );
pEvent->SetAutoPlay( true );
#ifdef PAL
if( IsLocalized )
{
switch( CGuiTextBible::GetCurrentLanguage() )
{
case Scrooby::XL_FRENCH:
{
pEvent->SetAudioIndex( FMVEvent::AUDIO_INDEX_FRENCH );
break;
}
case Scrooby::XL_GERMAN:
{
pEvent->SetAudioIndex( FMVEvent::AUDIO_INDEX_GERMAN );
break;
}
case Scrooby::XL_SPANISH:
{
pEvent->SetAudioIndex( FMVEvent::AUDIO_INDEX_SPANISH );
break;
}
default:
{
rAssert( CGuiTextBible::GetCurrentLanguage() == Scrooby::XL_ENGLISH );
pEvent->SetAudioIndex( FMVEvent::AUDIO_INDEX_ENGLISH );
break;
}
}
}
else
#endif // PAL
{
pEvent->SetAudioIndex( FMVEvent::AUDIO_INDEX_ENGLISH );
}
#ifdef RAD_GAMECUBE
pEvent->SetAllocator( GMA_ANYWHERE_IN_LEVEL );
#else
pEvent->SetAllocator( GMA_LEVEL_HUD );
#endif
pEvent->SetClearWhenDone( true );
pEvent->SetKeepLayersFrozen( true );
pEvent->SetSkippable(IsSkippable);
if( StopMusic )
{
pEvent->KillMusic();
}
mpPlayCallback = pCallback;
}
/*=============================================================================
Description: This is a callback when the event queued by PlayFMV.
=============================================================================*/
void PresentationManager::OnPresentationEventBegin( PresentationEvent* pEvent )
{
Context* context = GetGameFlow()->GetContext( GetGameFlow()->GetCurrentContext() );
if( dynamic_cast<GameplayContext*>( context ) )
{
static_cast<GameplayContext*>( context )->PauseAllButPresentation( true );
}
GetGuiSystem()->HandleMessage( GUI_MSG_RELEASE_INGAME );
if( mpPlayCallback )
{
mpPlayCallback->OnPresentationEventBegin( pEvent );
}
RenderLayer* rl = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( rl );
rl->RemoveGuts( mOverlay );
}
/*=============================================================================
Description: This is a callback when the event queued by PlayFMV.
=============================================================================*/
void PresentationManager::OnPresentationEventLoadComplete( PresentationEvent* pEvent )
{
if( mpPlayCallback )
{
mpPlayCallback->OnPresentationEventLoadComplete( pEvent );
}
}
/*=============================================================================
Description: This is a callback when the event queued by PlayFMV.
=============================================================================*/
void PresentationManager::OnPresentationEventEnd( PresentationEvent* pEvent )
{
HeapMgr()->PushHeap (GMA_LEVEL_HUD);
GetGuiSystem()->HandleMessage( GUI_MSG_INIT_INGAME );
HeapMgr()->PopHeap (GMA_LEVEL_HUD);
GetLoadingManager()->AddCallback( this );
if( mOverlay )
{
mOverlay->SetStart( BLACK_TRANSPARENT );
mOverlay->SetEnd( BLACK );
mOverlay->SetDuration( 0.5f );
//mOverlay->SetRemoveOnComplete( true );
RenderLayer* pLayer = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( pLayer );
pLayer->AddGuts( mOverlay );
}
}
/*=============================================================================
Description:
=============================================================================*/
void PresentationManager::OnProcessRequestsComplete( void* pUserData )
{
Context* context = GetGameFlow()->GetContext( GetGameFlow()->GetCurrentContext() );
if( dynamic_cast<GameplayContext*>( context ) )
{
static_cast<GameplayContext*>( context )->PauseAllButPresentation( false );
}
GetRenderManager()->ThawFromPresentation();
GetGuiSystem()->HandleMessage( GUI_MSG_RUN_INGAME );
if( mpPlayCallback )
{
mpPlayCallback->OnPresentationEventEnd( 0 );
}
mpPlayCallback = 0;
if( mOverlay )
{
mOverlay->SetEnd( BLACK );
mOverlay->SetFrames( 10 );
mOverlay->SetRemoveOnComplete( true );
RenderLayer* pLayer = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( pLayer );
pLayer->AddGuts( mOverlay );
}
}
//=============================================================================
// PresentationManager::QueueFMV
//=============================================================================
// Description: Comment
//
// Parameters: ( FMVEvent** pFMVEvent, PresentationEvent::PresentationEventCallBack* pCallback )
//
// Return: void
//
//=============================================================================
void PresentationManager::QueueFMV( FMVEvent** pFMVEvent, PresentationEvent::PresentationEventCallBack* pCallback )
{
(*pFMVEvent) = mFMVPool->AllocateFromPool();
(*pFMVEvent)->Init();
(*pFMVEvent)->SetAllocator(GMA_LEVEL_MOVIE);
(*pFMVEvent)->pCallback = pCallback;
AddToQueue( *pFMVEvent );
}
//=============================================================================
// PresentationManager::QueueNIS
//=============================================================================
// Description: Comment
//
// Parameters: ( NISEvent** pNISEvent, PresentationEvent::PresentationEventCallBack* pCallback )
//
// Return: void
//
//=============================================================================
void PresentationManager::QueueNIS( NISEvent** pNISEvent, PresentationEvent::PresentationEventCallBack* pCallback )
{
(*pNISEvent) = mNISPool->AllocateFromPool();
(*pNISEvent)->Init();
(*pNISEvent)->pCallback = pCallback;
AddToQueue( *pNISEvent );
}
//=============================================================================
// PresentationManager::QueueTransition
//=============================================================================
// Description: Comment
//
// Parameters: ( TransitionEvent** pTransitionEvent,
// PresentationEvent::PresentationEventCallBack* pCallback )
//
// Return: void
//
//=============================================================================
void PresentationManager::QueueTransition( TransitionEvent** pTransitionEvent,
PresentationEvent::PresentationEventCallBack* pCallback )
{
(*pTransitionEvent) = mTransitionPool->AllocateFromPool();
(*pTransitionEvent)->Init();
(*pTransitionEvent)->pCallback = pCallback;
AddToQueue( *pTransitionEvent );
}
bool PresentationManager::IsBusy(void) const
{
return (mpCurrent != 0) || mWaitingOnFade;
}
//=============================================================================
// PresentationManager::Update
//=============================================================================
// Description: Comment
//
// Parameters: ( unsigned int elapsedTime )
//
// Return: void
//
//=============================================================================
void PresentationManager::Update( unsigned int elapsedTime )
{
GetTutorialManager()->Update( static_cast< float >( elapsedTime ) );
if( mp_PCAnimator != NULL )
{
mp_PCAnimator->Update( static_cast<int>( elapsedTime ));
}
if( mp_NPCAnimator != NULL )
{
mp_NPCAnimator->Update( static_cast<int>( elapsedTime ));
}
rAssert( mOverlay != NULL );
mOverlay->Update( elapsedTime );
if( mWaitingOnFade )
{
if( mOverlay->GetAlpha() == 0.0f )
{
// get one extra frame of full black.
mWaitingOnFade = false;
}
return;
}
if( mpCurrent == NULL )
{
mpCurrent = GetFirst();
if (mpCurrent != NULL )
{
if( mpCurrent->pCallback != NULL )
{
mpCurrent->pCallback->OnPresentationEventBegin( mpCurrent );
}
mpPlayerDrawable->SetPlayer( mpCurrent->GetPlayer() );
mpPlayerDrawable->SetRenderLayer( mpCurrent->GetRenderLayer() );
mpCurrent->Start();
mWaitingOnFade = false;
}
}
if( mpCurrent != NULL )
{
bool finished = !mpCurrent->Update( elapsedTime );
if( finished )
{
if( mpCurrent->pCallback != NULL )
{
mpCurrent->pCallback->OnPresentationEventEnd( mpCurrent );
}
mpCurrent->Stop();
mpPlayerDrawable->SetPlayer( NULL );
ReturnToPool( mpCurrent );
mpCurrent = NULL;
}
}
}
//=============================================================================
// PresentationManager::ClearQueue
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void PresentationManager::ClearQueue()
{
if( mpCurrent == NULL )
{
mpCurrent = GetFirst();
}
while ( mpCurrent != NULL )
{
if( mpCurrent->pCallback != NULL )
{
mpCurrent->pCallback->OnPresentationEventEnd( mpCurrent );
}
mpCurrent->Stop();
ReturnToPool( mpCurrent );
mpCurrent = GetFirst();
};
mpPlayerDrawable->SetPlayer( NULL );
}
//=============================================================================
// PresentationManager::GetCameraTargetForLineOfDialog
//=============================================================================
// Description: what should the camera look at for this line of dialog
//
// Parameters: lineOfDialog - which line are we on?
//
// Return: CameraTarget - PC, NPC, or Don't Care
//
//=============================================================================
const tName PresentationManager::GetCameraTargetForLineOfDialog( const unsigned int lineOfDialog ) const
{
size_t size = mCameraForLineOfDialog.size();
if( lineOfDialog >= size )
{
return tName( "NONE" );
}
else
{
const tName& returnMe = mCameraForLineOfDialog[ lineOfDialog ];
return returnMe;
}
}
//=============================================================================
// PresentationManager::HandleEvent
//=============================================================================
// Description: Comment
//
// Parameters: ( EventEnum id, void* pEventData )
//
// Return: void
//
//=============================================================================
void PresentationManager::HandleEvent( EventEnum id, void* pEventData )
{
switch( id )
{
case EVENT_GUI_FADE_OUT_DONE:
{
if( mWaitingOnFade )
{
mWaitingOnFade = false;
}
}
break;
case EVENT_LOCATOR:
{
/*
EventLocator* locator = (EventLocator*)pEventData;
if( locator->GetFlag(Locator::ACTIVE) )
{
if( strcmp( locator->GetTriggerVolume()->GetName(), "TestTrigger" ) == 0 )
{
NISEvent* pEvent;
QueueNIS( &pEvent, NULL );
pEvent->fileName = "art\\camtest.p3d";
pEvent->type = NISEvent::NIS_CAMERA;
strcpy( pEvent->camera, "cameraShape1" );
strcpy( pEvent->animation, "CAM_cameraShape1" );
strcpy( pEvent->controller, "MasterController" );
pEvent->LoadFromInventory();
}
}
*/
break;
}
case EVENT_CONVERSATION_INIT:
{
DialogEventData* p_dialogstruct = static_cast <DialogEventData*> (pEventData);
//
// Register the character and the NPC with the conversation camera
//
SuperCam* camera = GetSuperCamManager()->GetSCC( 0 )->GetSuperCam( SuperCam::CONVERSATION_CAM );
ConversationCam* convCam = dynamic_cast< ConversationCam* >( camera );
convCam->SetCharacter( 0, p_dialogstruct->char1 );
convCam->SetCharacter( 1, p_dialogstruct->char2 );
rAssert(p_dialogstruct);
rAssert( p_dialogstruct->char1 != NULL );
rAssert( p_dialogstruct->char2 != NULL );
//
// some conversations are special - race missions for example
// require different bitmaps
//
Character* char1 = p_dialogstruct->char1;
Character* char2 = p_dialogstruct->char2;
Character* npc = NULL;
Character* pc = NULL;
if( char1->IsNPC() )
{
npc = char1;
pc = char2;
}
else
{
rAssert( char2->IsNPC() );
npc = char2;
pc = char1;
}
mp_PCAnimator->SetCharacter(pc);
mp_NPCAnimator->SetCharacter(npc);
if(pc->GetStateManager()->GetState() == CharacterAi::INCAR)
{
GetAvatarManager()->PutCharacterOnGround(pc, pc->GetTargetVehicle());
}
//
// Make the characters face one another
//
// If we're talking to patty and selma, we need to make selma face the user
GameplayManager* gpm = GetGameplayManager();
Mission* mission = gpm->GetCurrentMission();
bool pattyAndSelma = mission->GetCurrentStage()->GetObjective()->IsPattyAndSelmaDialog();
if( pattyAndSelma )
{
CharacterManager* cm = GetCharacterManager();
Character* selma = cm->GetCharacterByName( "selma" );
if(selma == NULL && GetGameplayManager()->GetCurrentLevelIndex() == RenderEnums::L7)
{
selma = cm->GetMissionCharacter("zmale1");
rTuneAssert(selma != NULL);
}
MakeCharactersFaceEachOther( selma, pc );
}
MakeCharactersFaceEachOther( char1, char2 );
mDialogLineNumber = -1;
mOldCamIndexNum= GetSuperCamManager()->GetSCC(PLAYER_ONE)->GetActiveSuperCamIndex();
// don't swap to close up camera if we are using a static cam (generally in an interior,
// where the camera movement could screw us up)
if(GetSuperCamManager()->GetSCC(PLAYER_ONE)->AllowCameraToggle())
{
if ( GetGameplayManager()->GetCurrentMission()->DialogueCharactersTeleported() )
{
GetSuperCamManager()->GetSCC(PLAYER_ONE)->SelectSuperCam(SuperCam::CONVERSATION_CAM, SuperCamCentral::CUT, 0 );
}
else
{
GetSuperCamManager()->GetSCC(PLAYER_ONE)->SelectSuperCam(SuperCam::CONVERSATION_CAM, 0 );
}
GetSuperCamManager()->GetSCC(PLAYER_ONE)->AddTarget( mp_NPCAnimator->GetCharacter()->GetTarget() );
}
//TO DO call Character eye blinking
mInConversation =true;
// make the talk-to NPC stand still
rAssert( npc );
static_cast<NPCController*>(npc->GetController())->TransitToState( NPCController::TALKING_WITH_PLAYER );
tName name = npc->GetNameObject();
ReplaceMissionBriefingBitmap( name );
break;
}
case EVENT_PC_TALK:
{
if( InConversation() )
{
++mDialogLineNumber;
tName target = GetCameraTargetForLineOfDialog( mDialogLineNumber );
if( target == tName( "NONE" ) )
{
ConversationCam::UsePcCam();
}
else
{
ConversationCam::SetCameraByName( target );
}
mp_PCAnimator->PlaySpecialAmbientAnimation();
mp_NPCAnimator->PlaySpecialAmbientAnimation();
}
else
{
Avatar* av = GetAvatarManager()->GetAvatarForPlayer( 0 );
Character* character = av->GetCharacter();
mp_PCAnimator->SetCharacter( character );
}
mp_PCAnimator->StartTalking();
break;
}
case EVENT_PC_SHUTUP:
{
mp_PCAnimator->StopTalking();
break;
}
case EVENT_NPC_TALK:
{
if( InConversation() )
{
++mDialogLineNumber;
const tName& target = GetCameraTargetForLineOfDialog( mDialogLineNumber );
if( target == tName( "NONE" ) )
{
ConversationCam::UseNpcCam();
}
else
{
ConversationCam::SetCameraByName( target );
}
mp_NPCAnimator->PlaySpecialAmbientAnimation();
mp_PCAnimator->PlaySpecialAmbientAnimation();
}
else
{
Character* character = reinterpret_cast< Character* >( pEventData );
mp_NPCAnimator->SetCharacter( character );
}
mp_NPCAnimator->StartTalking();
break;
}
case EVENT_NPC_SHUTUP:
{
mp_NPCAnimator->StopTalking();
if( !InConversation() )
{
mp_NPCAnimator->SetCharacter( NULL );
}
break;
}
case EVENT_CONVERSATION_SKIP:
{
//
// Eventually this will take us to CONVERSATION_DONE
//
mInConversation = false;
break;
}
case EVENT_CONVERSATION_DONE:
{
//change camera to previous
if ( GetGameplayManager()->GetCurrentMission()->DialogueCharactersTeleported() )
{
GetSuperCamManager()->GetSCC(PLAYER_ONE)->SelectSuperCam(mOldCamIndexNum, SuperCamCentral::CUT, 0);
}
else
{
GetSuperCamManager()->GetSCC(PLAYER_ONE)->SelectSuperCam(mOldCamIndexNum, 0);
}
// resume walking...
Character* npc = mp_NPCAnimator->GetCharacter();
if( npc )
{
static_cast<NPCController*>(npc->GetController())->TransitToState( NPCController::STOPPED );
}
//TO DO stop eyeblinking.
mInConversation = false;
if ( mp_PCAnimator->GetCharacter() != NULL)
{
mp_PCAnimator->StopTalking();
mp_PCAnimator->SetCharacter(NULL);
}
if ( mp_NPCAnimator->GetCharacter() != NULL)
{
mp_NPCAnimator->StopTalking();
mp_NPCAnimator->SetCharacter(NULL);
}
break;
}
default:
{
// don't be lazy! handle the event!
rAssert( false );
}
}
}
//******************************************************************************
//
// Private Member Functions
//
//******************************************************************************
//=============================================================================
// PresentationManager::AddToQueue
//=============================================================================
// Description: Comment
//
// Parameters: ( PresentationEvent* pEvent )
//
// Return: void
//
//=============================================================================
void PresentationManager::AddToQueue( PresentationEvent* pEvent )
{
// if you hit this assert then chances are the presentation queue is full
rAssert( mFIFOEnd < MAX_EVENT_SIZE );
rAssert( mEventFIFO[ mFIFOEnd ] == NULL );
mEventFIFO[ mFIFOEnd ] = pEvent;
mFIFOEnd++;
if( mFIFOEnd >= MAX_EVENT_SIZE )
{
mFIFOEnd = 0;
}
}
//=============================================================================
// PresentationManager::ReturnToPool
//=============================================================================
// Description: Comment
//
// Parameters: ( PresentationEvent* presevent )
//
// Return: void
//
//=============================================================================
void PresentationManager::ReturnToPool( PresentationEvent* presevent )
{
// change to use appropriate pool without doing it the dumb way
mFMVPool->ReturnToPool( (unsigned int)presevent );
mNISPool->ReturnToPool( (unsigned int)presevent );
mTransitionPool->ReturnToPool( (unsigned int)presevent );
}
//=============================================================================
// PresentationManager::GetFirst
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: PresentationEvent
//
//=============================================================================
PresentationEvent* PresentationManager::GetFirst()
{
rAssert( mFIFOBegin < MAX_EVENT_SIZE );
if( mEventFIFO[ mFIFOBegin ] != NULL )
{
PresentationEvent* pEvent = mEventFIFO[ mFIFOBegin ];
mEventFIFO[ mFIFOBegin ] = NULL;
mFIFOBegin++;
if( mFIFOBegin >= MAX_EVENT_SIZE )
{
mFIFOBegin = 0;
}
return( pEvent );
}
else
{
return( NULL );
}
}
//Do stuff once we are in the gameplay context
void PresentationManager::OnGameplayStart()
{
//get ptr to the Players Avatar
mp_PCAnimator->SetCharacter(GetCharacterManager()->GetCharacter(0) );
}
void PresentationManager::OnGameplayStop()
{
}
//=============================================================================
// PresentationManager::SetCamerasForLineOfDialog
//=============================================================================
// Description: sets the cameras for specific lines of dialog
//
// Parameters: names - a vector of names that represnet cameras for lines of
// dialog
//
// Return: NONE
//
//=============================================================================
void PresentationManager::SetCamerasForLineOfDialog( const TNAMEVECTOR& names )
{
#ifdef RAD_DEBUG
size_t size = names.size();
size_t i;
for( i = 0; i < size; ++i )
{
tName name = names[ i ];
}
#endif
mCameraForLineOfDialog.erase( mCameraForLineOfDialog.begin(), mCameraForLineOfDialog.end() );
mCameraForLineOfDialog.insert( mCameraForLineOfDialog.begin(), names.begin(), names.end() );
}
//=============================================================================
// PresentationManager::InConversation()
//=============================================================================
// Description: determines if the game is in a conversation or not
//
// Parameters: NONE
//
// Return: bool - are we in a conversation or not?
//
//=============================================================================
bool PresentationManager::InConversation() const
{
return mInConversation;
}
//=============================================================================
// PresentationManager::StopAll
//=============================================================================
// Description: Comment
//
// Parameters: ()
//
// Return: void
//
//=============================================================================
void PresentationManager::StopAll()
{
#ifdef RAD_WIN32
mpFMVPlayer->ForceStop();
#else
mpFMVPlayer->Stop();
#endif
mpNISPlayer->Stop();
mpTransitionPlayer->Stop();
mpCameraPlayer->Stop();
}
PresentationOverlay::PresentationOverlay() :
mAlpha( 0.0f ),
mInvDuration( 0.0f ),
mStart( BLACK_TRANSPARENT ),
mEnd( BLACK_TRANSPARENT ),
mFrameCount( -1 ),
mIsAutoRemove( false )
{}
void PresentationOverlay::Update( unsigned int ElapsedTime )
{
if( mFrameCount == 0 )
{
mAlpha = 0.0f;
mInvDuration = 0.0f;
mFrameCount = -1;
if( mIsAutoRemove )
{
RenderLayer* rl = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( rl );
rl->RemoveGuts( this );
rl->Freeze();
mIsAutoRemove = false;
}
}
else if( mAlpha > 0.0f )
{
mAlpha -= ( (float)ElapsedTime * mInvDuration );
if( mAlpha < 0.0f )
{
mAlpha = 0.0f;
mInvDuration = 0.0f;
if( mIsAutoRemove )
{
RenderLayer* rl = GetRenderManager()->mpLayer( RenderEnums::PresentationSlot );
rAssert( rl );
rl->RemoveGuts( this );
rl->Freeze();
mIsAutoRemove = false;
}
}
}
}
void PresentationOverlay::Display( void )
{
// First check if anything is visible...
int alpha = 0;
if( mFrameCount == -1 )
{
alpha = int( ( mStart.Alpha() * mAlpha ) + ( mEnd.Alpha() * ( 1.0f - mAlpha ) ) );
}
else
{
--mFrameCount;
if( mFrameCount < 0 )
{
mFrameCount = 0;
}
alpha = mEnd.Alpha();
}
if( alpha <= 0 )
{
return;
}
// Now figure out the colour.
tColour c;
if( mFrameCount == -1 )
{
int red = int( ( mStart.Red() * mAlpha ) + ( mEnd.Red() * ( 1.0f - mAlpha ) ) );
int green = int( ( mStart.Green() * mAlpha ) + ( mEnd.Green() * ( 1.0f - mAlpha ) ) );
int blue = int( ( mStart.Blue() * mAlpha ) + ( mEnd.Blue() * ( 1.0f - mAlpha ) ) );
c.Set( red, green, blue, alpha );
}
else
{
c.c = mEnd.c;
}
// Let's draw poly!
p3d::stack->Push();
bool oldZWrite = p3d::pddi->GetZWrite();
pddiCompareMode oldZComp = p3d::pddi->GetZCompare();
if( oldZWrite )
{
p3d::pddi->SetZWrite( false );
}
if( oldZComp != PDDI_COMPARE_ALWAYS )
{
p3d::pddi->SetZCompare( PDDI_COMPARE_ALWAYS );
}
p3d::stack->LoadIdentity();
p3d::pddi->SetProjectionMode( PDDI_PROJECTION_ORTHOGRAPHIC );
pddiColour oldAmbient = p3d::pddi->GetAmbientLight();
p3d::pddi->SetAmbientLight( pddiColour( 255, 255, 255 ) );
pddiPrimStream* overlay = 0;
pddiShader* overlayShader = BootupContext::GetInstance()->GetSharedShader();
rAssert( overlayShader );
overlayShader->SetInt( PDDI_SP_BLENDMODE, PDDI_BLEND_ALPHA );
overlayShader->SetInt( PDDI_SP_ISLIT, 0 );
overlayShader->SetInt( PDDI_SP_SHADEMODE, PDDI_SHADE_FLAT );
overlayShader->SetInt( PDDI_SP_TWOSIDED, 1 );
overlay = p3d::pddi->BeginPrims( overlayShader, PDDI_PRIM_TRISTRIP, PDDI_V_C, 4 );
overlay->Colour( c );
overlay->Coord( 0.5f, -0.5f, 1.0f );
overlay->Colour( c );
overlay->Coord( -0.5f, -0.5f, 1.0f );
overlay->Colour( c );
overlay->Coord( 0.5f, 0.5f, 1.0f );
overlay->Colour( c );
overlay->Coord( -0.5f, 0.5f, 1.0f );
p3d::pddi->EndPrims( overlay );
p3d::pddi->SetProjectionMode(PDDI_PROJECTION_PERSPECTIVE);
p3d::pddi->SetAmbientLight( oldAmbient );
if( oldZWrite )
{
p3d::pddi->SetZWrite( true );
}
if( oldZComp != PDDI_COMPARE_ALWAYS )
{
p3d::pddi->SetZCompare( oldZComp );
}
p3d::stack->Pop();
}
//=============================================================================
// PresentationManager::CheckRaceMissionBitmaps
//=============================================================================
// Description: updates bitmaps on the mission start screen if we're entering
// a race mission
//
// Parameters: none7
//
// Return: void
//
//=============================================================================
void PresentationManager::CheckRaceMissionBitmaps()
{
}
//=============================================================================
// PresentationManager::ReplaceMissionBriefingBitmap
//=============================================================================
// Description: depending on who we're talking to, we need to replace the
// picture on the mission briefing screen
//
// Parameters: conversationCharacterName - name of the character that led to
// this screen
//
// Return: void
//
//=============================================================================
void PresentationManager::ReplaceMissionBriefingBitmap( const tName& conversationCharacterName )
{
const tName& name = conversationCharacterName;
//
// These are for the race missions
//
if( name == "b_nelson" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_CT.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_milhouse" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_TT.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_ralph" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_CP.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_louie" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_GB.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_witch" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_HW.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_zfem1" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_HW.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_zmale1" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_HW.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_zmale3" )
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/misXX_HW.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
//
// these are for the bonus missions
//
else if( name == "b_cletus")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis01_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_grandpa")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis02_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_skinner")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis03_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_cbg")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis04_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_frink")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis05_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_snake")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis06_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else if( name == "b_smithers")
{
CGuiScreenMissionLoad::SetBitmapName( "art/frontend/dynaload/images/mis07_08.p3d" );
CGuiScreenMissionLoad::ClearBitmap();
}
else
{
return;
}
//
// Trigger an update of the picture via scrooby
//
CGuiScreenMissionLoad::ReplaceBitmap();
}
//=============================================================================
// PresentationManager::MakeCharactersFaceEachOther
//=============================================================================
// Description: depending on who we're talking to, we need to replace the
// picture on the mission briefing screen
//
// Parameters: c1, c2 - the two characters that we want to face each other
//
// Return: void
//
//=============================================================================
void PresentationManager::MakeCharactersFaceEachOther( Character* c0, Character* c1 )
{
rmt::Vector position0;
rmt::Vector position1;
c0->GetPosition( &position0 );
c1->GetPosition( &position1 );
rmt::Vector offset = position1 - position0;
offset.Normalize();
float rotation = choreo::GetWorldAngle( offset.x, offset.z );
c0->RelocateAndReset( position0, rotation, false );
c1->RelocateAndReset( position1, rotation + rmt::PI, false );
}