//===== Copyright (c) 1996-2009, Valve Corporation, All rights reserved. ====// // // Purpose: Contains all utility methods for the new game UI system // //===========================================================================// #include "cbase.h" #include "gameui.h" #include "game_controls/igameuisystemmgr.h" #include "tier1/timeutils.h" #include "cdll_client_int.h" #include "soundemittersystem/isoundemittersystembase.h" #include "engine/ienginesound.h" #include "filesystem.h" #include "inputsystem/iinputstacksystem.h" #include "gameui/basemodpanel.h" #include "gameui/nuggets/ui_nugget.h" // memdbgon must be the last include file in a .cpp file!!! #include "tier0/memdbgon.h" // A logging channel used during engine initialization DEFINE_LOGGING_CHANNEL_NO_TAGS( LOG_GameUI, "GameUI" ); LINK_GAME_CONTROLS_LIB(); // A utility function to determine if we are running as part of game ui base mod panel inline bool IsPartOfGameUiBaseModPanel() { BaseModUI::CBaseModPanel *pPanel = BaseModUI::CBaseModPanel::GetSingletonPtr(); if ( !pPanel ) return false; return pPanel->IsVisible(); } //----------------------------------------------------------------------------- // Default game ui sound playback implementation //----------------------------------------------------------------------------- class CInGameUISoundPlayback : public IGameUISoundPlayback { public: void *EmitSound( const char *pSoundName ) { if ( developer.GetBool() ) { // Ensure the sound is valid int nSoundIndex = g_pSoundEmitterSystem->GetSoundIndex( pSoundName ); if ( !g_pSoundEmitterSystem->IsValidIndex( nSoundIndex ) ) { Log_Warning( LOG_GameUI, "Attempted to play invalid sound \"%s\"\n", pSoundName ); return NULL; } const char *pSourceFile = g_pSoundEmitterSystem->GetSourceFileForSound( nSoundIndex ); if ( !Q_stristr( pSourceFile, "game_sounds_ui.txt" ) ) { Log_Warning( LOG_GameUI, "Attempted to play invalid sound \"%s\". This sound must be defined\n" "in game_sounds_ui.txt but was defined in \"%s\" instead.\n", pSoundName, pSourceFile ); return NULL; } } // Pull data from parameters CSoundParameters params; HSOUNDSCRIPTHASH handle = SOUNDEMITTER_INVALID_HASH; if ( !soundemitterbase->GetParametersForSoundEx( pSoundName, handle, params, GENDER_NONE, true ) ) { Log_Warning( LOG_GameUI, "Attempted to play invalid sound \"%s\"\n", pSoundName ); return NULL; } if ( !params.soundname[0] ) { Log_Warning( LOG_GameUI, "Attempted to play invalid sound \"%s\", which has no .wav!\n", pSoundName ); return NULL; } float st = 0.0f; if ( params.delay_msec != 0.0f ) { st = gpGlobals->curtime + (float)params.delay_msec / 1000.f; } CLocalPlayerFilter filter; enginesound->EmitSound( filter, SOUND_FROM_LOCAL_PLAYER, params.channel, pSoundName, handle, params.soundname, params.volume, (soundlevel_t)params.soundlevel, params.m_nRandomSeed, 0, // flags params.pitch, NULL, NULL, NULL, true, st ); return (void*)enginesound->GetGuidForLastSoundEmitted(); } void StopSound( void *pSoundHandle ) { if ( !pSoundHandle || !g_pSoundSystem ) return; int nGuid = (int)pSoundHandle; enginesound->StopSoundByGuid( nGuid ); } }; static CInGameUISoundPlayback s_InGameUISoundPlayback; //----------------------------------------------------------------------------- // Instantiate singleton game system //----------------------------------------------------------------------------- static CGameUIGameSystem s_GameUIGameSystem; CGameUIGameSystem *g_pGameUIGameSystem = &s_GameUIGameSystem; //----------------------------------------------------------------------------- // Initialization //----------------------------------------------------------------------------- bool CGameUIGameSystem::Init() { g_pGameUISystemMgr->UseGameInputSystemEventQueue( true ); g_pGameUISystemMgr->SetSoundPlayback( &s_InGameUISoundPlayback ); g_pGameUISystemMgr->SetInputContext( engine->GetInputContext( ENGINE_INPUT_CONTEXT_GAMEUI ) ); // Register all client nugget factories CUiNuggetFactoryRegistrarBase::RegisterAll(); return true; } void CGameUIGameSystem::Shutdown() { g_pGameUISystemMgr->SetSoundPlayback( NULL ); g_pGameUISystemMgr->SetInputContext( INPUT_CONTEXT_HANDLE_INVALID ); } //----------------------------------------------------------------------------- // PostInit //----------------------------------------------------------------------------- void CGameUIGameSystem::PostInit() { // This cannot happen in Init() because the audio system isn't set up // at that point, and it needs to be for precache to succeed PrecacheGameUISounds(); } //----------------------------------------------------------------------------- // Precaches all game UI sounds //----------------------------------------------------------------------------- void CGameUIGameSystem::PrecacheGameUISounds() { // Precache all UI sounds. These must exist in the game_sounds_ui.txt script file KeyValues *pUIGameSounds = new KeyValues( "Game Instructor Counts" ); if ( !pUIGameSounds->LoadFromFile( g_pFullFileSystem, "scripts/game_sounds_ui.txt", "GAME" ) ) { pUIGameSounds->deleteThis(); return; } for ( KeyValues *pKey = pUIGameSounds; pKey; pKey = pKey->GetNextKey() ) { const char *pSoundName = pKey->GetName(); int nSoundIndex = soundemitterbase->GetSoundIndex( pSoundName ); if ( !soundemitterbase->IsValidIndex( nSoundIndex ) ) { Log_Warning( LOG_GameUI, "GameUI: Unable to precache gamesound \"%s\"\n", pSoundName ); continue; } CSoundParametersInternal *pInternal = soundemitterbase->InternalGetParametersForSound( nSoundIndex ); if ( !pInternal ) { Log_Warning( LOG_GameUI, "GameUI: Unable to precache gamesound \"%s\"\n", pSoundName ); continue; } int nWaveCount = pInternal->NumSoundNames(); if ( !nWaveCount ) { Log_Warning( LOG_GameUI, "GameUI: game_sounds_ui.txt entry '%s' has no waves listed under 'wave' or 'rndwave' key!!!\n", pSoundName ); continue; } for( int nWave = 0; nWave < nWaveCount; ++nWave ) { const char *pWavName = soundemitterbase->GetWaveName( pInternal->GetSoundNames()[ nWave ].symbol ); enginesound->PrecacheSound( pWavName, true, true ); } } pUIGameSounds->deleteThis(); } //----------------------------------------------------------------------------- // Reloads game GUI sounds //----------------------------------------------------------------------------- void CGameUIGameSystem::ReloadSounds() { // Should I stop all currently playing sounds? PrecacheGameUISounds(); } //----------------------------------------------------------------------------- // Init any render targets needed by the UI. //----------------------------------------------------------------------------- void CGameUIGameSystem::InitRenderTargets() { g_pGameUISystemMgr->InitRenderTargets(); } //----------------------------------------------------------------------------- // Init any render targets needed by the UI. //----------------------------------------------------------------------------- IMaterialProxy *CGameUIGameSystem::CreateProxy( const char *proxyName ) { return g_pGameUISystemMgr->CreateProxy( proxyName ); } //----------------------------------------------------------------------------- // Renders the game UI //----------------------------------------------------------------------------- void CGameUIGameSystem::Render( const Rect_t &viewport, float flCurrentTime ) { g_pGameUISystemMgr->Render( viewport, DmeTime_t( flCurrentTime ) ); } //----------------------------------------------------------------------------- // Registers an input event //----------------------------------------------------------------------------- bool CGameUIGameSystem::RegisterInputEvent( const InputEvent_t &iEvent ) { if ( !g_pGameUISystemMgr->GetGameUIVisible() ) return false; switch( iEvent.m_nType ) { case IE_ButtonPressed: { // NOTE: data2 is the virtual key code (data1 contains the scan-code one) ButtonCode_t code = (ButtonCode_t)iEvent.m_nData2; if ( code == KEY_BACKQUOTE ) { return false; } else if ( code == KEY_ESCAPE ) { return false; } } break; case IE_ButtonReleased: { // NOTE: data2 is the virtual key code (data1 contains the scan-code one) ButtonCode_t code = (ButtonCode_t)iEvent.m_nData2; if ( code == KEY_BACKQUOTE ) { return false; } else if ( code == KEY_ESCAPE ) { return false; } } break; default: break; } g_pGameUISystemMgr->RegisterInputEvent( iEvent ); // FIXME: This is a hack; we're saying that the system eats the // input as long as a menu is visible return g_pGameUISystemMgr->GetGameUIVisible(); } //----------------------------------------------------------------------------- // Simulates the next frame //----------------------------------------------------------------------------- void CGameUIGameSystem::Update( float frametime ) { if ( IsPartOfGameUiBaseModPanel() ) // Prevent double-updates during a frame when running as part of game ui // base mod panel rendering and event processing return; g_pGameUISystemMgr->RunFrame(); }