Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1705 lines
50 KiB

  1. //========= Copyright 1996-2008, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=====================================================================================//
  6. #include "cbase.h"
  7. #include "basemodpanel.h"
  8. #include "uigamedata.h"
  9. #include "./GameUI/IGameUI.h"
  10. #include "ienginevgui.h"
  11. #include "engine/ienginesound.h"
  12. #include "EngineInterface.h"
  13. #include "tier0/dbg.h"
  14. #include "ixboxsystem.h"
  15. #include "GameUI_Interface.h"
  16. #include "game/client/IGameClientExports.h"
  17. #include "gameui/igameconsole.h"
  18. #include "inputsystem/iinputsystem.h"
  19. #include "FileSystem.h"
  20. #include "filesystem/IXboxInstaller.h"
  21. #ifdef _GAMECONSOLE
  22. #include "xbox/xbox_launch.h"
  23. #endif
  24. #include "gameconsole.h"
  25. #include "vgui/ISystem.h"
  26. #include "vgui/ISurface.h"
  27. #include "vgui/ILocalize.h"
  28. #include "vgui_controls/AnimationController.h"
  29. #include "vguimatsurface/imatsystemsurface.h"
  30. #include "materialsystem/imaterialsystem.h"
  31. #include "materialsystem/imesh.h"
  32. #include "tier0/icommandline.h"
  33. #include "fmtstr.h"
  34. #include "smartptr.h"
  35. // Embedded GameUI
  36. #include "../gameui.h"
  37. #include "game_controls/igameuisystemmgr.h"
  38. // memdbgon must be the last include file in a .cpp file!!!
  39. #include "tier0/memdbgon.h"
  40. using namespace BaseModUI;
  41. using namespace vgui;
  42. //setup in GameUI_Interface.cpp
  43. extern class IMatchSystem *matchsystem;
  44. extern const char *COM_GetModDirectory( void );
  45. extern IGameConsole *IGameConsole();
  46. //=============================================================================
  47. CBaseModPanel* CBaseModPanel::m_CFactoryBasePanel = 0;
  48. #ifndef _CERT
  49. #ifdef _GAMECONSOLE
  50. ConVar ui_gameui_debug( "ui_gameui_debug", "1" );
  51. #else
  52. ConVar ui_gameui_debug( "ui_gameui_debug", "0", FCVAR_RELEASE );
  53. #endif
  54. int UI_IsDebug()
  55. {
  56. return (*(int *)(&ui_gameui_debug)) ? ui_gameui_debug.GetInt() : 0;
  57. }
  58. #endif
  59. #if defined( _GAMECONSOLE )
  60. static void InstallStatusChanged( IConVar *pConVar, const char *pOldValue, float flOldValue )
  61. {
  62. // spew out status
  63. if ( ((ConVar *)pConVar)->GetBool() && g_pXboxInstaller )
  64. {
  65. g_pXboxInstaller->SpewStatus();
  66. }
  67. }
  68. ConVar xbox_install_status( "xbox_install_status", "0", 0, "Show install status", InstallStatusChanged );
  69. #endif
  70. // Use for show demos to force the correct campaign poster
  71. ConVar demo_campaign_name( "demo_campaign_name", "L4D2C5", FCVAR_DEVELOPMENTONLY, "Short name of campaign (i.e. L4D2C5), used to show correct poster in demo mode." );
  72. ConVar ui_lobby_noresults_create_msg_time( "ui_lobby_noresults_create_msg_time", "2.5", FCVAR_DEVELOPMENTONLY );
  73. //=============================================================================
  74. void SetGameUiEmbeddedScreen( char const *szBaseName )
  75. {
  76. if ( !szBaseName || !*szBaseName )
  77. {
  78. g_pGameUISystemMgr->ReleaseAllGameUIScreens();
  79. g_pGameUISystemMgr->SetGameUIVisible( false );
  80. return;
  81. }
  82. IGameUISystem *pGameUiSystem = g_pGameUISystemMgr->LoadGameUIScreen(
  83. KeyValues::AutoDeleteInline( new KeyValues( szBaseName ) ) );
  84. pGameUiSystem;
  85. g_pGameUISystemMgr->SetGameUIVisible( true );
  86. }
  87. //=============================================================================
  88. CBaseModPanel::CBaseModPanel(): BaseClass(0, "CBaseModPanel"),
  89. m_bClosingAllWindows( false ),
  90. m_lastActiveUserId( 0 )
  91. {
  92. #if !defined( _GAMECONSOLE ) && !defined( NOSTEAM )
  93. // Set Steam overlay position
  94. if ( steamapicontext && steamapicontext->SteamUtils() )
  95. {
  96. steamapicontext->SteamUtils()->SetOverlayNotificationPosition( k_EPositionTopRight );
  97. }
  98. // Set special DLC parameters mask
  99. static ConVarRef mm_dlcs_mask_extras( "mm_dlcs_mask_extras" );
  100. if ( mm_dlcs_mask_extras.IsValid() && steamapicontext && steamapicontext->SteamUtils() )
  101. {
  102. int iDLCmask = mm_dlcs_mask_extras.GetInt();
  103. // Low Violence and Germany (or bordering countries) = CS.GUNS
  104. char const *cc = steamapicontext->SteamUtils()->GetIPCountry();
  105. char const *ccGuns = ":DE:DK:PL:CZ:AT:CH:FR:LU:BE:NL:";
  106. if ( engine->IsLowViolence() && Q_stristr( ccGuns, CFmtStr( ":%s:", cc ) ) )
  107. {
  108. // iDLCmask |= ( 1 << ? );
  109. }
  110. // PreOrder DLC AppId Ownership = BAT
  111. if ( steamapicontext->SteamApps()->BIsSubscribedApp( 565 ) )
  112. {
  113. // iDLCmask |= ( 1 << ? );
  114. }
  115. mm_dlcs_mask_extras.SetValue( iDLCmask );
  116. }
  117. #endif
  118. MakePopup( false );
  119. Assert(m_CFactoryBasePanel == 0);
  120. m_CFactoryBasePanel = this;
  121. g_pVGuiLocalize->AddFile( "Resource/basemodui_%language%.txt");
  122. g_pVGuiLocalize->AddFile( "Resource/basemodui_tu_%language%.txt" );
  123. m_LevelLoading = false;
  124. // delay 3 frames before doing activation on initialization
  125. // needed to allow engine to exec startup commands (background map signal is 1 frame behind)
  126. m_DelayActivation = 3;
  127. m_UIScheme = vgui::scheme()->LoadSchemeFromFileEx( 0, "resource/BaseModScheme.res", "BaseModScheme" );
  128. SetScheme( m_UIScheme );
  129. // Only one user on the PC, so set it now
  130. SetLastActiveUserId( IsPC() ? 0 : -1 );
  131. // Precache critical font characters for the 360, dampens severity of these runtime i/o hitches
  132. IScheme *pScheme = vgui::scheme()->GetIScheme( m_UIScheme );
  133. m_hDefaultFont = pScheme->GetFont( "Default", true );
  134. vgui::surface()->PrecacheFontCharacters( m_hDefaultFont, NULL );
  135. vgui::surface()->PrecacheFontCharacters( pScheme->GetFont( "DefaultBold", true ), NULL );
  136. vgui::surface()->PrecacheFontCharacters( pScheme->GetFont( "DefaultLarge", true ), NULL );
  137. vgui::surface()->PrecacheFontCharacters( pScheme->GetFont( "FrameTitle", true ), NULL );
  138. m_bWarmRestartMode = false;
  139. m_ExitingFrameCount = 0;
  140. m_flBlurScale = 0;
  141. m_flLastBlurTime = 0;
  142. // Background movie
  143. m_BIKHandle = BIKHANDLE_INVALID;
  144. m_pMovieMaterial = NULL;
  145. m_flU0 = m_flV0 = m_flU1 = m_flV1 = 0.0f;
  146. m_bMovieFailed = false;
  147. m_iBackgroundImageID = -1;
  148. m_iFadeToBackgroundImageID = -1;
  149. m_backgroundMusic = "";
  150. m_nBackgroundMusicGUID = 0;
  151. m_bFadeMusicUp = false;
  152. m_flMovieFadeInTime = 0;
  153. m_iMovieTransitionImage = 0;
  154. // Subscribe to event notifications
  155. g_pMatchFramework->GetEventsSubscription()->Subscribe( this );
  156. }
  157. //=============================================================================
  158. CBaseModPanel::~CBaseModPanel()
  159. {
  160. // Unsubscribe from event notifications
  161. g_pMatchFramework->GetEventsSubscription()->Unsubscribe( this );
  162. Assert(m_CFactoryBasePanel == this);
  163. m_CFactoryBasePanel = 0;
  164. // Free our movie resources
  165. ShutdownBackgroundMovie();
  166. surface()->DestroyTextureID( m_iBackgroundImageID );
  167. surface()->DestroyTextureID( m_iFadeToBackgroundImageID );
  168. // Shutdown UI game data
  169. CUIGameData::Shutdown();
  170. }
  171. //=============================================================================
  172. CBaseModPanel& CBaseModPanel::GetSingleton()
  173. {
  174. Assert(m_CFactoryBasePanel != 0);
  175. return *m_CFactoryBasePanel;
  176. }
  177. //=============================================================================
  178. CBaseModPanel* CBaseModPanel::GetSingletonPtr()
  179. {
  180. return m_CFactoryBasePanel;
  181. }
  182. //=============================================================================
  183. void CBaseModPanel::ReloadScheme()
  184. {
  185. }
  186. bool CBaseModPanel::IsLevelLoading()
  187. {
  188. return m_LevelLoading;
  189. }
  190. #if defined( _GAMECONSOLE ) && defined( _DEMO )
  191. void CBaseModPanel::OnDemoTimeout()
  192. {
  193. if ( !engine->IsInGame() && !engine->IsConnected() && !engine->IsDrawingLoadingImage() )
  194. {
  195. // exit is terminal and unstoppable
  196. StartExitingProcess( false );
  197. }
  198. else
  199. {
  200. engine->ExecuteClientCmd( "disconnect" );
  201. }
  202. }
  203. #endif
  204. bool CBaseModPanel::ActivateBackgroundEffects()
  205. {
  206. // PC needs to keep start music, can't loop MP3's
  207. if ( IsPC() && !IsBackgroundMusicPlaying() )
  208. {
  209. StartBackgroundMusic( 1.0f );
  210. m_bFadeMusicUp = false;
  211. }
  212. // bring up the video if we haven't before
  213. if ( m_BIKHandle == BIKHANDLE_INVALID )
  214. {
  215. if ( !InitBackgroundMovie() )
  216. {
  217. // couldn't start movie, don't do the music either
  218. return false;
  219. }
  220. if ( IsGameConsole() && !IsBackgroundMusicPlaying() )
  221. {
  222. // only xbox's fades non-playing music up
  223. m_bFadeMusicUp = StartBackgroundMusic( 0 );
  224. }
  225. else
  226. {
  227. m_bFadeMusicUp = false;
  228. }
  229. m_flMovieFadeInTime = 0;
  230. }
  231. return true;
  232. }
  233. //=============================================================================
  234. void CBaseModPanel::OnGameUIActivated()
  235. {
  236. if ( UI_IsDebug() )
  237. {
  238. Msg( "[GAMEUI] CBaseModPanel::OnGameUIActivated( delay = %d )\n", m_DelayActivation );
  239. }
  240. if ( m_DelayActivation )
  241. {
  242. return;
  243. }
  244. COM_TimestampedLog( "CBaseModPanel::OnGameUIActivated()" );
  245. #if defined( _GAMECONSOLE )
  246. if ( !engine->IsInGame() && !engine->IsConnected() && !engine->IsDrawingLoadingImage() )
  247. {
  248. #if defined( _DEMO )
  249. if ( engine->IsDemoExiting() )
  250. {
  251. // just got activated, maybe from a disconnect
  252. // exit is terminal and unstoppable
  253. SetVisible( true );
  254. StartExitingProcess( false );
  255. return;
  256. }
  257. #endif
  258. if ( !GameUI().IsInLevel() && !GameUI().IsInBackgroundLevel() )
  259. {
  260. // not using a background map
  261. // start the menu movie and music now, as the main menu is about to open
  262. // these are very large i/o operations on the xbox
  263. // they must occur before the installer takes over the DVD
  264. // otherwise the transfer rate is so slow and we sync stall for 10-15 seconds
  265. ActivateBackgroundEffects();
  266. }
  267. // the installer runs in the background during the main menu
  268. g_pXboxInstaller->Start();
  269. #if defined( _DEMO )
  270. // ui valid can now adhere to demo timeout rules
  271. engine->EnableDemoTimeout( true );
  272. #endif
  273. }
  274. #endif
  275. SetVisible( true );
  276. if ( !IsGameConsole() && IsLevelLoading() )
  277. {
  278. // Ignore UI activations when loading poster is up
  279. return;
  280. }
  281. else if ( ( !m_LevelLoading && !engine->IsConnected() ) || GameUI().IsInBackgroundLevel() )
  282. {
  283. OpenFrontScreen();
  284. }
  285. else if ( engine->IsConnected() && !m_LevelLoading )
  286. {
  287. SetGameUiEmbeddedScreen( "ingamemenu" );
  288. }
  289. }
  290. void CBaseModPanel::OpenFrontScreen()
  291. {
  292. char const *szScreen = NULL;
  293. #ifdef _GAMECONSOLE
  294. // make sure we are in the startup menu.
  295. if ( !GameUI().IsInBackgroundLevel() )
  296. {
  297. engine->ClientCmd( "startupmenu" );
  298. }
  299. if ( g_pMatchFramework->GetMatchSession() )
  300. {
  301. Warning( "CBaseModPanel::OpenFrontScreen during active game ignored!\n" );
  302. return;
  303. }
  304. if( XBX_GetNumGameUsers() > 0 )
  305. {
  306. if ( 0 ) // ( CL4DFrame *pAttractScreen = GetWindow( WT_ATTRACTSCREEN ) )
  307. {
  308. szScreen = "attractscreen";
  309. }
  310. else
  311. {
  312. szScreen = "mainmenu";
  313. }
  314. }
  315. else
  316. {
  317. szScreen = "attractscreen";
  318. }
  319. #else
  320. szScreen = "mainmenu";
  321. #endif // _GAMECONSOLE
  322. if( szScreen )
  323. {
  324. SetGameUiEmbeddedScreen( NULL ); // TEMP HACK: only devconsole interferes with this event being fired multiple times in main menu
  325. // need a better fix for devconsole to be a little smarter about gameui activation events
  326. SetGameUiEmbeddedScreen( szScreen );
  327. }
  328. }
  329. //=============================================================================
  330. void CBaseModPanel::OnGameUIHidden()
  331. {
  332. if ( UI_IsDebug() )
  333. {
  334. Msg( "[GAMEUI] CBaseModPanel::OnGameUIHidden()\n" );
  335. }
  336. #if defined( _GAMECONSOLE )
  337. // signal the installer to stop
  338. g_pXboxInstaller->Stop();
  339. #endif
  340. SetVisible(false);
  341. // Close all gameui screens
  342. SetGameUiEmbeddedScreen( NULL );
  343. // Free the movie resouces
  344. ShutdownBackgroundMovie();
  345. }
  346. //=============================================================================
  347. void CBaseModPanel::RunFrame()
  348. {
  349. if ( s_NavLock > 0 )
  350. {
  351. --s_NavLock;
  352. }
  353. GetAnimationController()->UpdateAnimations( Plat_FloatTime() );
  354. CUIGameData::Get()->RunFrame();
  355. if ( m_DelayActivation )
  356. {
  357. m_DelayActivation--;
  358. if ( !m_LevelLoading && !m_DelayActivation )
  359. {
  360. if ( UI_IsDebug() )
  361. {
  362. Msg( "[GAMEUI] Executing delayed UI activation\n");
  363. }
  364. OnGameUIActivated();
  365. }
  366. }
  367. bool bDoBlur = true;
  368. bDoBlur = false;
  369. #if 0 // TODO: UI: determine blur
  370. WINDOW_TYPE wt = GetActiveWindowType();
  371. switch ( wt )
  372. {
  373. case WT_NONE:
  374. case WT_MAINMENU:
  375. case WT_LOADINGPROGRESSBKGND:
  376. case WT_LOADINGPROGRESS:
  377. case WT_AUDIOVIDEO:
  378. bDoBlur = false;
  379. break;
  380. }
  381. if ( GetWindow( WT_ATTRACTSCREEN ) || ( enginevguifuncs && !enginevguifuncs->IsGameUIVisible() ) )
  382. {
  383. // attract screen might be open, but not topmost due to notification dialogs
  384. bDoBlur = false;
  385. }
  386. #endif
  387. if ( !bDoBlur )
  388. {
  389. bDoBlur = GameClientExports()->ClientWantsBlurEffect();
  390. }
  391. float nowTime = Plat_FloatTime();
  392. float deltaTime = nowTime - m_flLastBlurTime;
  393. if ( deltaTime > 0 )
  394. {
  395. m_flLastBlurTime = nowTime;
  396. m_flBlurScale += deltaTime * bDoBlur ? 0.05f : -0.05f;
  397. m_flBlurScale = clamp( m_flBlurScale, 0, 0.85f );
  398. engine->SetBlurFade( m_flBlurScale );
  399. }
  400. if ( IsGameConsole() && m_ExitingFrameCount )
  401. {
  402. #if 0 // TODO: UI: CTransitionScreen
  403. CTransitionScreen *pTransitionScreen = static_cast< CTransitionScreen* >( GetWindow( WT_TRANSITIONSCREEN ) );
  404. if ( pTransitionScreen && pTransitionScreen->IsTransitionComplete() )
  405. {
  406. // totally obscured, safe to shutdown movie
  407. ShutdownBackgroundMovie();
  408. if ( m_ExitingFrameCount > 1 )
  409. {
  410. m_ExitingFrameCount--;
  411. if ( m_ExitingFrameCount == 1 )
  412. {
  413. // enough frames have transpired, send the single shot quit command
  414. if ( m_bWarmRestartMode )
  415. {
  416. // restarts self, skips any intros
  417. engine->ClientCmd_Unrestricted( "quit_x360 restart\n" );
  418. }
  419. else
  420. {
  421. // cold restart, quits to any startup app
  422. engine->ClientCmd_Unrestricted( "quit_x360\n" );
  423. }
  424. }
  425. }
  426. }
  427. #endif
  428. }
  429. }
  430. //=============================================================================
  431. void CBaseModPanel::OnLevelLoadingStarted( char const *levelName, bool bShowProgressDialog )
  432. {
  433. Assert( !m_LevelLoading );
  434. #if defined( _GAMECONSOLE )
  435. // stop the installer
  436. g_pXboxInstaller->Stop();
  437. g_pXboxInstaller->SpewStatus();
  438. // If the installer has finished while we are in the menus, then this is the ONLY place we
  439. // know that there is no open files and we can redirect the search paths
  440. if ( g_pXboxInstaller->ForceCachePaths() )
  441. {
  442. // the search paths got changed
  443. // notify other systems who may have hooked absolute paths
  444. engine->SearchPathsChangedAfterInstall();
  445. }
  446. #endif
  447. // close all UI screens
  448. SetGameUiEmbeddedScreen( NULL );
  449. // Stop the background movie
  450. ShutdownBackgroundMovie();
  451. DevMsg( 2, "[GAMEUI] OnLevelLoadingStarted - opening loading progress (%s)...\n",
  452. levelName ? levelName : "<< no level specified >>" );
  453. //
  454. // If playing on listen server then "levelName" is set to the map being loaded,
  455. // so it is authoritative - it might be a background map or a real level.
  456. //
  457. if ( levelName )
  458. {
  459. // Derive the mission info from the server game details
  460. KeyValues *pGameSettings = g_pMatchFramework->GetMatchNetworkMsgController()->GetActiveServerGameDetails( NULL );
  461. if ( !pGameSettings )
  462. {
  463. // In this particular case we need to speculate about game details
  464. // this happens when user types "map c5m2 versus easy" from console, so there's no
  465. // active server spawned yet, nor is the local client connected to any server.
  466. // We have to force server DLL to apply the map command line to the settings and then
  467. // speculatively construct the settings key.
  468. if ( IServerGameDLL *pServerDLL = ( IServerGameDLL * ) g_pMatchFramework->GetMatchExtensions()->GetRegisteredExtensionInterface( INTERFACEVERSION_SERVERGAMEDLL ) )
  469. {
  470. KeyValues *pApplyServerSettings = new KeyValues( "::ExecGameTypeCfg" );
  471. KeyValues::AutoDelete autodelete_pApplyServerSettings( pApplyServerSettings );
  472. pApplyServerSettings->SetString( "map/mapname", levelName );
  473. pServerDLL->ApplyGameSettings( pApplyServerSettings );
  474. }
  475. // Now we can retrieve all the settings from convars here!
  476. static ConVarRef r_mp_gamemode( "mp_gamemode" );
  477. if ( r_mp_gamemode.IsValid() )
  478. {
  479. pGameSettings = new KeyValues( "CmdLineSettings" );
  480. pGameSettings->SetString( "game/mode", r_mp_gamemode.GetString() );
  481. }
  482. }
  483. KeyValues::AutoDelete autodelete_pGameSettings( pGameSettings );
  484. if ( pGameSettings )
  485. {
  486. // It is critical to get map info by the actual levelname that is being loaded, because
  487. // for level transitions the server is still in the old map and the game settings returned
  488. // will reflect the old state of the server.
  489. // - pChapterInfo = g_pMatchExtPortal2->GetMapInfoByBspName( pGameSettings, levelName, &pMissionInfo );
  490. // - Q_strncpy( chGameMode, pGameSettings->GetString( "game/mode", "" ), ARRAYSIZE( chGameMode ) );
  491. }
  492. // Let the ui nuggets know the loading map
  493. IGameUIScreenControllerFactory *pFactory = g_pGameUISystemMgr->GetScreenControllerFactory( "loadingprogress" );
  494. if ( pFactory && pFactory->GetControllerInstancesCount() )
  495. {
  496. KeyValues *kvEvent = new KeyValues( "OnLevelLoadingProgress" );
  497. KeyValues::AutoDelete autodelete_kvEvent( kvEvent );
  498. kvEvent->SetString( "map", levelName );
  499. kvEvent->SetFloat( "progress", 0.0f );
  500. for ( int j = 0; j < pFactory->GetControllerInstancesCount(); ++ j )
  501. {
  502. pFactory->GetControllerInstance(j)->BroadcastEventToScreens( kvEvent );
  503. }
  504. }
  505. }
  506. m_LevelLoading = true;
  507. // Bring up the level loading screen
  508. SetGameUiEmbeddedScreen( "loadingbar" );
  509. }
  510. void CBaseModPanel::OnEngineLevelLoadingSession( KeyValues *pEvent )
  511. {
  512. #if 0 // TODO: UI: OnEngineLevelLoadingSession
  513. // We must keep the default loading poster because it will be replaced by
  514. // the real campaign loading poster shortly
  515. float flProgress = 0.0f;
  516. if ( LoadingProgress *pLoadingProgress = static_cast<LoadingProgress*>( GetWindow( WT_LOADINGPROGRESS ) ) )
  517. {
  518. flProgress = pLoadingProgress->GetProgress();
  519. pLoadingProgress->Close();
  520. m_Frames[ WT_LOADINGPROGRESS ] = NULL;
  521. }
  522. CloseAllWindows( CLOSE_POLICY_DEFAULT );
  523. // Pop up a fake bkgnd poster
  524. if ( LoadingProgress *pLoadingProgress = static_cast<LoadingProgress*>( OpenWindow( WT_LOADINGPROGRESSBKGND, NULL ) ) )
  525. {
  526. pLoadingProgress->SetLoadingType( LoadingProgress::LT_POSTER );
  527. pLoadingProgress->SetProgress( flProgress );
  528. }
  529. #endif
  530. }
  531. //=============================================================================
  532. void CBaseModPanel::OnLevelLoadingFinished( KeyValues *kvEvent )
  533. {
  534. int bError = kvEvent->GetInt( "error" );
  535. const char *failureReason = kvEvent->GetString( "reason" );
  536. Assert( m_LevelLoading );
  537. if ( UI_IsDebug() )
  538. {
  539. Msg( "[GAMEUI] CBaseModPanel::OnLevelLoadingFinished( %s, %s )\n", bError ? "Had Error" : "No Error", failureReason );
  540. }
  541. #if defined( _GAMECONSOLE )
  542. if ( GameUI().IsInBackgroundLevel() )
  543. {
  544. // start the installer when running the background map has finished
  545. g_pXboxInstaller->Start();
  546. }
  547. #endif
  548. // Let the ui nuggets know
  549. IGameUIScreenControllerFactory *pFactory = g_pGameUISystemMgr->GetScreenControllerFactory( "loadingprogress" );
  550. if ( pFactory && pFactory->GetControllerInstancesCount() )
  551. {
  552. KeyValues *kvEvent = new KeyValues( "OnLevelLoadingProgress" );
  553. KeyValues::AutoDelete autodelete_kvEvent( kvEvent );
  554. kvEvent->SetFloat( "progress", 1.0f );
  555. for ( int j = 0; j < pFactory->GetControllerInstancesCount(); ++ j )
  556. {
  557. pFactory->GetControllerInstance(j)->BroadcastEventToScreens( kvEvent );
  558. }
  559. }
  560. // Close all embedded gameui screens
  561. SetGameUiEmbeddedScreen( NULL );
  562. m_LevelLoading = false;
  563. // - CBaseModFrame *pFrame = CBaseModPanel::GetSingleton().GetWindow( WT_GENERICCONFIRMATION );
  564. // - if ( !pFrame )
  565. {
  566. // no confirmation up, hide the UI
  567. GameUI().HideGameUI();
  568. }
  569. #if 0 // TODO: UI: handle errors after loading
  570. // if we are loading into the lobby, then skip the UIActivation code path
  571. // this can happen if we accepted an invite to player who is in the lobby while we were in-game
  572. if ( WT_GAMELOBBY != GetActiveWindowType() )
  573. {
  574. // if we are loading into the front-end, then activate the main menu (or attract screen, depending on state)
  575. // or if a message box is pending force open game ui
  576. if ( GameUI().IsInBackgroundLevel() || pFrame )
  577. {
  578. GameUI().OnGameUIActivated();
  579. }
  580. }
  581. if ( bError )
  582. {
  583. GenericConfirmation* pMsg = ( GenericConfirmation* ) OpenWindow( WT_GENERICCONFIRMATION, NULL, false );
  584. if ( pMsg )
  585. {
  586. GenericConfirmation::Data_t data;
  587. data.pWindowTitle = "#L4D360UI_MsgBx_DisconnectedFromServer";
  588. data.bOkButtonEnabled = true;
  589. data.pMessageText = failureReason;
  590. pMsg->SetUsageData( data );
  591. }
  592. }
  593. #endif
  594. }
  595. class CMatchSessionCreationAsyncOperation : public IMatchAsyncOperation
  596. {
  597. public:
  598. CMatchSessionCreationAsyncOperation() : m_eState( AOS_RUNNING ) {}
  599. public:
  600. virtual bool IsFinished() { return false; }
  601. virtual AsyncOperationState_t GetState() { return m_eState; }
  602. virtual uint64 GetResult() { return 0ull; }
  603. virtual void Abort();
  604. virtual void Release() { Assert( 0 ); } // we are a global object, cannot release
  605. public:
  606. IMatchAsyncOperation * Prepare() { m_eState = AOS_RUNNING; return this; }
  607. protected:
  608. AsyncOperationState_t m_eState;
  609. }
  610. g_MatchSessionCreationAsyncOperation;
  611. void CMatchSessionCreationAsyncOperation::Abort()
  612. {
  613. m_eState = AOS_ABORTING;
  614. Assert( g_pMatchFramework->GetMatchSession() );
  615. g_pMatchFramework->CloseSession();
  616. #if 0 // TODO: UI: Abort session create
  617. CBaseModPanel::GetSingleton().CloseAllWindows();
  618. CBaseModPanel::GetSingleton().OpenFrontScreen();
  619. #endif
  620. }
  621. void CBaseModPanel::OnEvent( KeyValues *pEvent )
  622. {
  623. char const *szEvent = pEvent->GetName();
  624. if ( !Q_stricmp( "OnMatchSessionUpdate", szEvent ) )
  625. {
  626. char const *szState = pEvent->GetString( "state", "" );
  627. if ( !Q_stricmp( "ready", szState ) )
  628. {
  629. // Session has finished creating:
  630. IMatchSession *pSession = g_pMatchFramework->GetMatchSession();
  631. if ( !pSession )
  632. return;
  633. KeyValues *pSettings = pSession->GetSessionSettings();
  634. if ( !pSettings )
  635. return;
  636. char const *szNetwork = pSettings->GetString( "system/network", "" );
  637. int numLocalPlayers = pSettings->GetInt( "members/numPlayers", 1 );
  638. // TODO: UI: session has been created!
  639. // - WINDOW_TYPE wtGameLobby = WT_GAMELOBBY;
  640. if ( !Q_stricmp( "offline", szNetwork ) &&
  641. numLocalPlayers <= 1 )
  642. {
  643. // We have a single-player offline session
  644. // - wtGameLobby = WT_GAMESETTINGS;
  645. }
  646. // We have created a session
  647. // - CloseAllWindows();
  648. // Special case when we are creating a public session after empty search
  649. if ( !Q_stricmp( pSettings->GetString( "options/createreason" ), "searchempty" ) &&
  650. !Q_stricmp( pSettings->GetString( "system/access" ), "public" ) )
  651. {
  652. // We are creating a public lobby after our search turned out empty
  653. char const *szWaitScreenText = "#Matchmaking_NoResultsCreating";
  654. REFERENCE(szWaitScreenText);
  655. // - CUIGameData::Get()->OpenWaitScreen( szWaitScreenText, ui_lobby_noresults_create_msg_time.GetFloat() );
  656. // - CUIGameData::Get()->CloseWaitScreen( NULL, NULL );
  657. // Delete the "createreason" key from the session settings
  658. pSession->UpdateSessionSettings( KeyValues::AutoDeleteInline( KeyValues::FromString( "delete",
  659. " delete { options { createreason delete } } " ) ) );
  660. }
  661. // - CBaseModFrame *pLobbyWindow = OpenWindow( wtGameLobby, NULL, true, pSettings ); // derive from session
  662. // - if ( CBaseModFrame *pWaitScreen = GetWindow( WT_GENERICWAITSCREEN ) )
  663. {
  664. // Normally "CloseAllWindows" above would take down the waitscreen, but
  665. // we could pop it up for the special case of empty search results
  666. // - pWaitScreen->SetNavBack( pLobbyWindow );
  667. }
  668. // Check for a special case when we lost connection to host and that's why we are going to lobby
  669. if ( KeyValues *pOnEngineDisconnectReason = g_pMatchFramework->GetEventsSubscription()->GetEventData( "OnEngineDisconnectReason" ) )
  670. {
  671. if ( !Q_stricmp( "lobby", pOnEngineDisconnectReason->GetString( "disconnecthdlr" ) ) )
  672. {
  673. // - CUIGameData::Get()->OpenWaitScreen( "#L4D360UI_MsgBx_DisconnectedFromServer" );
  674. // - CUIGameData::Get()->CloseWaitScreen( NULL, NULL );
  675. }
  676. }
  677. }
  678. else if ( !Q_stricmp( "created", szState ) )
  679. {
  680. //
  681. // This section of code catches when we just connected to a lobby that
  682. // is playing a campaign that we do not have installed.
  683. // In this case we abort loading, forcefully close all windows including
  684. // loading poster and game lobby and display the download info msg.
  685. //
  686. #if 1 // TODO: UI: connected to dlc session
  687. return;
  688. #else
  689. IMatchSession *pSession = g_pMatchFramework->GetMatchSession();
  690. if ( !pSession )
  691. return;
  692. KeyValues *pSettings = pSession->GetSessionSettings();
  693. KeyValues *pInfoMission = NULL;
  694. KeyValues *pInfoChapter = GetMapInfoRespectingAnyChapter( pSettings, &pInfoMission );
  695. // If we do not have a valid chapter/mission, then we need to quit
  696. if ( pInfoChapter && pInfoMission &&
  697. ( !*pInfoMission->GetName() || pInfoMission->GetInt( "version" ) == pSettings->GetInt( "game/missioninfo/version", -1 ) ) )
  698. return;
  699. if ( pSettings )
  700. pSettings = pSettings->MakeCopy();
  701. engine->ExecuteClientCmd( "disconnect" );
  702. g_pMatchFramework->CloseSession();
  703. CloseAllWindows( CLOSE_POLICY_EVEN_MSGS | CLOSE_POLICY_EVEN_LOADING );
  704. OpenFrontScreen();
  705. const char *szCampaignWebsite = pSettings->GetString( "game/missioninfo/website", NULL );
  706. if ( szCampaignWebsite && *szCampaignWebsite )
  707. {
  708. OpenWindow( WT_DOWNLOADCAMPAIGN,
  709. GetWindow( CBaseModPanel::GetSingleton().GetActiveWindowType() ),
  710. true, pSettings );
  711. }
  712. else
  713. {
  714. GenericConfirmation::Data_t data;
  715. data.pWindowTitle = "#L4D360UI_Lobby_MissingContent";
  716. data.pMessageText = "#L4D360UI_Lobby_MissingContent_Message";
  717. data.bOkButtonEnabled = true;
  718. GenericConfirmation* confirmation =
  719. static_cast< GenericConfirmation* >( OpenWindow( WT_GENERICCONFIRMATION, NULL, true ) );
  720. confirmation->SetUsageData(data);
  721. }
  722. #endif
  723. }
  724. else if ( !Q_stricmp( "progress", szState ) )
  725. {
  726. struct WaitText_t
  727. {
  728. char const *m_szProgress;
  729. char const *m_szText;
  730. int m_eCloseAllWindowsFlags;
  731. };
  732. // TODO: UI: session create progress
  733. // - int eDefaultFlags = CLOSE_POLICY_EVEN_MSGS | CLOSE_POLICY_KEEP_BKGND;
  734. int eDefaultFlags = -1;
  735. WaitText_t arrWaits[] = {
  736. { "creating", "#Matchmaking_creating", eDefaultFlags },
  737. { "joining", "#Matchmaking_joining", eDefaultFlags },
  738. { "searching", "#Matchmaking_searching", eDefaultFlags },
  739. };
  740. char const *szProgress = pEvent->GetString( "progress", "" );
  741. WaitText_t const *pWaitText = NULL;
  742. for ( int k = 0; k < ARRAYSIZE( arrWaits ); ++ k )
  743. {
  744. if ( !Q_stricmp( arrWaits[k].m_szProgress, szProgress ) )
  745. {
  746. pWaitText = &arrWaits[k];
  747. break;
  748. }
  749. }
  750. // Wait screen options to cancel async process
  751. KeyValues *pSettings = new KeyValues( "WaitScreen" );
  752. KeyValues::AutoDelete autodelete_pSettings( pSettings );
  753. pSettings->SetPtr( "options/asyncoperation", g_MatchSessionCreationAsyncOperation.Prepare() );
  754. // For PC we don't want to cancel lobby creation
  755. if ( IsPC() && !Q_stricmp( "creating", szProgress ) )
  756. pSettings = NULL;
  757. // Put up a wait screen
  758. if ( pWaitText )
  759. {
  760. if ( pWaitText->m_eCloseAllWindowsFlags != -1 )
  761. {
  762. // - CloseAllWindows( pWaitText->m_eCloseAllWindowsFlags );
  763. }
  764. char const *szWaitScreenText = pWaitText->m_szText;
  765. float flMinDisplayTime = 0.0f;
  766. REFERENCE(flMinDisplayTime);
  767. if ( IMatchSession *pMatchSession = g_pMatchFramework->GetMatchSession() )
  768. {
  769. KeyValues *pMatchSettings = pMatchSession->GetSessionSettings();
  770. if ( !Q_stricmp( szProgress, "creating" ) &&
  771. !Q_stricmp( pMatchSettings->GetString( "options/createreason" ), "searchempty" ) &&
  772. !Q_stricmp( pMatchSettings->GetString( "system/access" ), "public" ) )
  773. {
  774. // We are creating a public lobby after our search turned out empty
  775. szWaitScreenText = "#Matchmaking_NoResultsCreating";
  776. }
  777. }
  778. // - CUIGameData::Get()->OpenWaitScreen( szWaitScreenText, flMinDisplayTime, pSettings );
  779. }
  780. else if ( !Q_stricmp( "searchresult", szProgress ) )
  781. {
  782. char const *arrText[] = { "#Matchmaking_SearchResults",
  783. "#Matchmaking_SearchResults1", "#Matchmaking_SearchResults2", "#Matchmaking_SearchResults3" };
  784. int numResults = pEvent->GetInt( "numResults", 0 );
  785. if ( numResults < 0 || numResults >= ARRAYSIZE( arrText ) )
  786. numResults = 0;
  787. // TODO: UI: session search progress
  788. // - CUIGameData::Get()->OpenWaitScreen( arrText[numResults], 0.0f, pSettings );
  789. }
  790. }
  791. }
  792. else if ( !Q_stricmp( "OnEngineLevelLoadingSession", szEvent ) )
  793. {
  794. OnEngineLevelLoadingSession( pEvent );
  795. }
  796. else if ( !Q_stricmp( "OnEngineLevelLoadingFinished", szEvent ) )
  797. {
  798. OnLevelLoadingFinished( pEvent );
  799. }
  800. }
  801. //=============================================================================
  802. bool CBaseModPanel::UpdateProgressBar( float progress, const char *statusText )
  803. {
  804. if ( !m_LevelLoading )
  805. {
  806. // Warning( "WARN: CBaseModPanel::UpdateProgressBar called outside of level loading, discarded!\n" );
  807. return false;
  808. }
  809. // Need to call this periodically to collect sign in and sign out notifications,
  810. // do NOT dispatch events here in the middle of loading and rendering!
  811. if ( ThreadInMainThread() )
  812. {
  813. XBX_ProcessEvents();
  814. }
  815. IGameUIScreenControllerFactory *pFactory = g_pGameUISystemMgr->GetScreenControllerFactory( "loadingprogress" );
  816. if ( pFactory && pFactory->GetControllerInstancesCount() )
  817. {
  818. KeyValues *kvEvent = new KeyValues( "OnLevelLoadingProgress" );
  819. KeyValues::AutoDelete autodelete_kvEvent( kvEvent );
  820. kvEvent->SetFloat( "progress", progress );
  821. for ( int j = 0; j < pFactory->GetControllerInstancesCount(); ++ j )
  822. {
  823. pFactory->GetControllerInstance(j)->BroadcastEventToScreens( kvEvent );
  824. }
  825. }
  826. // update required
  827. return true;
  828. }
  829. void CBaseModPanel::SetLastActiveUserId( int userId )
  830. {
  831. if ( m_lastActiveUserId != userId )
  832. {
  833. DevWarning( "SetLastActiveUserId: %d -> %d\n", m_lastActiveUserId, userId );
  834. }
  835. m_lastActiveUserId = userId;
  836. }
  837. int CBaseModPanel::GetLastActiveUserId( )
  838. {
  839. return m_lastActiveUserId;
  840. }
  841. //-----------------------------------------------------------------------------
  842. // Purpose: moves the game menu button to the right place on the taskbar
  843. //-----------------------------------------------------------------------------
  844. static void BaseUI_PositionDialog(vgui::PHandle dlg)
  845. {
  846. if (!dlg.Get())
  847. return;
  848. int x, y, ww, wt, wide, tall;
  849. vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
  850. dlg->GetSize(wide, tall);
  851. // Center it, keeping requested size
  852. dlg->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
  853. }
  854. //=============================================================================
  855. void CBaseModPanel::ApplySchemeSettings(IScheme *pScheme)
  856. {
  857. BaseClass::ApplySchemeSettings(pScheme);
  858. SetBgColor(pScheme->GetColor("Blank", Color(0, 0, 0, 0)));
  859. char filename[MAX_PATH];
  860. engine->GetStartupImage( filename, sizeof( filename ) );
  861. m_iBackgroundImageID = surface()->CreateNewTextureID();
  862. surface()->DrawSetTextureFile( m_iBackgroundImageID, filename, true, false );
  863. const AspectRatioInfo_t &aspectRatioInfo = materials->GetAspectRatioInfo();
  864. bool bIsWidescreen = aspectRatioInfo.m_bIsWidescreen;
  865. m_iFadeToBackgroundImageID = -1;
  866. const char *pWhich = V_stristr( filename, "background" );
  867. if ( pWhich )
  868. {
  869. int nWhich = atoi( pWhich + 10 );
  870. if ( nWhich )
  871. {
  872. bool bIsWidescreen = ( V_stristr( pWhich, "widescreen" ) != NULL );
  873. CFmtStr pFadeFilename( "vgui/maps/background%02d_exit%s", nWhich, ( bIsWidescreen ? "_widescreen" : "" ) );
  874. m_iFadeToBackgroundImageID = surface()->CreateNewTextureID();
  875. surface()->DrawSetTextureFile( m_iFadeToBackgroundImageID, pFadeFilename, true, false );
  876. }
  877. }
  878. // Recalculate the movie parameters if our video size has changed
  879. CalculateMovieParameters();
  880. bool bUseMono = false;
  881. bUseMono; // silence warnings on non-demo, PC build
  882. #if defined( _GAMECONSOLE )
  883. // cannot use the very large stereo version during the install
  884. bUseMono = g_pXboxInstaller->IsInstallEnabled() && !g_pXboxInstaller->IsFullyInstalled();
  885. #if defined( _DEMO )
  886. bUseMono = true;
  887. #endif
  888. #endif
  889. // TODO: GetBackgroundMusic
  890. #if 0
  891. char backgroundMusic[MAX_PATH];
  892. engine->GetBackgroundMusic( backgroundMusic, sizeof( backgroundMusic ), bUseMono );
  893. // the precache will be a memory or stream wave as needed
  894. // on 360 the sound system will detect the install state and force it to a memory wave to finalize the the i/o now
  895. // it will be a stream resource if the installer is dormant
  896. // On PC it will be a streaming MP3
  897. if ( enginesound->PrecacheSound( backgroundMusic, true, false ) )
  898. {
  899. // successfully precached
  900. m_backgroundMusic = backgroundMusic;
  901. }
  902. #endif
  903. }
  904. void CBaseModPanel::DrawColoredText( vgui::HFont hFont, int x, int y, unsigned int color, const char *pAnsiText )
  905. {
  906. wchar_t szconverted[256];
  907. int len = g_pVGuiLocalize->ConvertANSIToUnicode( pAnsiText, szconverted, sizeof( szconverted ) );
  908. if ( len <= 0 )
  909. {
  910. return;
  911. }
  912. int r = ( color >> 24 ) & 0xFF;
  913. int g = ( color >> 16 ) & 0xFF;
  914. int b = ( color >> 8 ) & 0xFF;
  915. int a = ( color >> 0 ) & 0xFF;
  916. vgui::surface()->DrawSetTextFont( hFont );
  917. vgui::surface()->DrawSetTextPos( x, y );
  918. vgui::surface()->DrawSetTextColor( r, g, b, a );
  919. vgui::surface()->DrawPrintText( szconverted, len );
  920. }
  921. void CBaseModPanel::DrawCopyStats()
  922. {
  923. #if defined( _GAMECONSOLE )
  924. int wide, tall;
  925. GetSize( wide, tall );
  926. int xPos = 0.1f * wide;
  927. int yPos = 0.1f * tall;
  928. // draw copy status
  929. char textBuffer[256];
  930. const CopyStats_t *pCopyStats = g_pXboxInstaller->GetCopyStats();
  931. V_snprintf( textBuffer, sizeof( textBuffer ), "Version: %d (%s)", g_pXboxInstaller->GetVersion(), XBX_GetLanguageString() );
  932. DrawColoredText( m_hDefaultFont, xPos, yPos, 0xffff00ff, textBuffer );
  933. yPos += 20;
  934. V_snprintf( textBuffer, sizeof( textBuffer ), "DVD Hosted: %s", g_pFullFileSystem->IsDVDHosted() ? "Enabled" : "Disabled" );
  935. DrawColoredText( m_hDefaultFont, xPos, yPos, 0xffff00ff, textBuffer );
  936. yPos += 20;
  937. bool bDrawProgress = true;
  938. if ( g_pFullFileSystem->IsInstalledToXboxHDDCache() )
  939. {
  940. DrawColoredText( m_hDefaultFont, xPos, yPos, 0x00ff00ff, "Existing Image Found." );
  941. yPos += 20;
  942. bDrawProgress = false;
  943. }
  944. if ( !g_pXboxInstaller->IsInstallEnabled() )
  945. {
  946. DrawColoredText( m_hDefaultFont, xPos, yPos, 0xff0000ff, "Install Disabled." );
  947. yPos += 20;
  948. bDrawProgress = false;
  949. }
  950. if ( g_pXboxInstaller->IsFullyInstalled() )
  951. {
  952. DrawColoredText( m_hDefaultFont, xPos, yPos, 0x00ff00ff, "Install Completed." );
  953. yPos += 20;
  954. }
  955. if ( bDrawProgress )
  956. {
  957. yPos += 20;
  958. V_snprintf( textBuffer, sizeof( textBuffer ), "From: %s (%.2f MB)", pCopyStats->m_srcFilename, (float)pCopyStats->m_ReadSize/(1024.0f*1024.0f) );
  959. DrawColoredText( m_hDefaultFont, xPos, yPos, 0xffff00ff, textBuffer );
  960. V_snprintf( textBuffer, sizeof( textBuffer ), "To: %s (%.2f MB)", pCopyStats->m_dstFilename, (float)pCopyStats->m_WriteSize/(1024.0f*1024.0f) );
  961. DrawColoredText( m_hDefaultFont, xPos, yPos + 20, 0xffff00ff, textBuffer );
  962. float elapsed = 0;
  963. float rate = 0;
  964. if ( pCopyStats->m_InstallStartTime )
  965. {
  966. elapsed = (float)(GetTickCount() - pCopyStats->m_InstallStartTime) * 0.001f;
  967. }
  968. if ( pCopyStats->m_InstallStopTime )
  969. {
  970. elapsed = (float)(pCopyStats->m_InstallStopTime - pCopyStats->m_InstallStartTime) * 0.001f;
  971. }
  972. if ( elapsed )
  973. {
  974. rate = pCopyStats->m_TotalWriteSize/elapsed;
  975. }
  976. V_snprintf( textBuffer, sizeof( textBuffer ), "Progress: %d/%d MB Elapsed: %d secs (%.2f MB/s)", pCopyStats->m_BytesCopied/(1024*1024), g_pXboxInstaller->GetTotalSize()/(1024*1024), (int)elapsed, rate/(1024.0f*1024.0f) );
  977. DrawColoredText( m_hDefaultFont, xPos, yPos + 40, 0xffff00ff, textBuffer );
  978. }
  979. #endif
  980. }
  981. //-----------------------------------------------------------------------------
  982. // Returns true if menu background movie is valid
  983. //-----------------------------------------------------------------------------
  984. bool CBaseModPanel::IsMenuBackgroundMovieValid( void )
  985. {
  986. if ( !m_bMovieFailed && m_BIKHandle != BIKHANDLE_INVALID )
  987. {
  988. return true;
  989. }
  990. return false;
  991. }
  992. //=============================================================================
  993. void CBaseModPanel::CalculateMovieParameters( void )
  994. {
  995. if ( m_BIKHandle == BIKHANDLE_INVALID )
  996. return;
  997. m_flU0 = m_flV0 = 0.0f;
  998. g_pBIK->GetTexCoordRange( m_BIKHandle, &m_flU1, &m_flV1 );
  999. m_pMovieMaterial = g_pBIK->GetMaterial( m_BIKHandle );
  1000. int nWidth, nHeight;
  1001. g_pBIK->GetFrameSize( m_BIKHandle, &nWidth, &nHeight );
  1002. float flFrameRatio = ( (float) GetWide() / (float) GetTall() );
  1003. float flVideoRatio = ( (float) nWidth / (float) nHeight );
  1004. if ( flVideoRatio > flFrameRatio )
  1005. {
  1006. // Width must be adjusted
  1007. float flImageWidth = (float) GetTall() * flVideoRatio;
  1008. const float flSpanScaled = ( m_flU1 - m_flU0 ) * GetWide() / flImageWidth;
  1009. m_flU0 = ( m_flU1 - flSpanScaled ) / 2.0f;
  1010. m_flU1 = m_flU0 + flSpanScaled;
  1011. }
  1012. else if ( flVideoRatio < flFrameRatio )
  1013. {
  1014. // Height must be adjusted
  1015. float flImageHeight = (float) GetWide() * ( (float) nHeight / (float) nWidth );
  1016. const float flSpanScaled = ( m_flV1 - m_flV0 ) * GetTall() / flImageHeight;
  1017. m_flV0 = ( m_flV1 - flSpanScaled ) / 2.0f;
  1018. m_flV1 = m_flV0 + flSpanScaled;
  1019. }
  1020. }
  1021. //=============================================================================
  1022. bool CBaseModPanel::InitBackgroundMovie( void )
  1023. {
  1024. if ( m_bMovieFailed || m_ExitingFrameCount )
  1025. {
  1026. // prevent constant i/o testing after failure condition
  1027. // do not restart the movie (after its been stopped), we are trying to stabilize the app for exit
  1028. return false;
  1029. }
  1030. if ( CommandLine()->FindParm( "-nomenuvid" ) )
  1031. {
  1032. // mimic movie i/o failure, render will fallback to use product image
  1033. m_bMovieFailed = false;
  1034. return false;
  1035. }
  1036. static bool bFirstTime = true;
  1037. if ( bFirstTime )
  1038. {
  1039. // one time only, on app startup transition from the product image
  1040. m_iMovieTransitionImage = m_iBackgroundImageID;
  1041. bFirstTime = false;
  1042. }
  1043. else
  1044. {
  1045. // otherwise use the blur fade in
  1046. m_iMovieTransitionImage = m_iFadeToBackgroundImageID;
  1047. }
  1048. // Grab our scheme to get the filename from
  1049. IScheme *pScheme = vgui::scheme()->GetIScheme( m_UIScheme );
  1050. if ( pScheme == NULL )
  1051. return false;
  1052. // Destroy any previously allocated video
  1053. if ( m_BIKHandle != BIKHANDLE_INVALID )
  1054. {
  1055. g_pBIK->DestroyMaterial( m_BIKHandle );
  1056. m_BIKHandle = BIKHANDLE_INVALID;
  1057. }
  1058. const char *pFilename;
  1059. char movieFilename[MAX_PATH] = {0};
  1060. pFilename = movieFilename;
  1061. // TODO: engine->GetBackgroundMovie( movieFilename, sizeof( movieFilename ) );
  1062. if ( !g_pFullFileSystem->FileExists( movieFilename, "GAME" ) )
  1063. {
  1064. // bgnd movie not available, fallback and try this one
  1065. pFilename = pScheme->GetResourceString( "BackgroundMovie" );
  1066. }
  1067. COM_TimestampedLog( "Load Background Movie - %s", pFilename );
  1068. // Load and create our BINK video
  1069. // This menu background movie needs to loop and !!reside!! in memory (CRITICAL: Xbox is installing to HDD, w/o this it will frag the drive)
  1070. #ifndef _GAMECONSOLE
  1071. // Address bug caused by searchpath manipulation
  1072. materials ? materials->UncacheAllMaterials() : NULL;
  1073. #endif
  1074. m_BIKHandle = BIKHANDLE_INVALID; // TODO: g_pBIK->CreateMaterial( "VideoBIKMaterial_Background", pFilename, "GAME", BIK_LOOP | BIK_PRELOAD );
  1075. if ( m_BIKHandle == BIKHANDLE_INVALID )
  1076. {
  1077. m_bMovieFailed = true;
  1078. return false;
  1079. }
  1080. COM_TimestampedLog( "Load Background Movie - End" );
  1081. // Find frame size and letterboxing information
  1082. CalculateMovieParameters();
  1083. return true;
  1084. }
  1085. //=============================================================================
  1086. void CBaseModPanel::ShutdownBackgroundMovie( void )
  1087. {
  1088. if ( m_BIKHandle != BIKHANDLE_INVALID )
  1089. {
  1090. // FIXME: Make sure the m_pMaterial is actually destroyed at this point!
  1091. g_pBIK->DestroyMaterial( m_BIKHandle );
  1092. m_BIKHandle = BIKHANDLE_INVALID;
  1093. }
  1094. // allow a retry
  1095. m_bMovieFailed = false;
  1096. ReleaseBackgroundMusic();
  1097. }
  1098. //=============================================================================
  1099. bool CBaseModPanel::RenderBackgroundMovie( float *pflFadeDelta )
  1100. {
  1101. // goes from [0..1]
  1102. // provided to the caller to track the movie fade in
  1103. // callers may have other overlay elements to sync
  1104. *pflFadeDelta = 1.0f;
  1105. if ( IsGameConsole() && m_BIKHandle == BIKHANDLE_INVALID )
  1106. {
  1107. // should have already started, cannot be started now
  1108. return false;
  1109. }
  1110. if ( IsPC() )
  1111. {
  1112. // Bring up the video if we haven't before or Alt+Tab has made it invalid
  1113. // The Xbox cannot start the movie at this point, the installer may be using the DVD
  1114. if ( !ActivateBackgroundEffects() )
  1115. {
  1116. return false;
  1117. }
  1118. }
  1119. if ( !m_flMovieFadeInTime )
  1120. {
  1121. // do the fade a little bit after the movie starts (needs to be stable)
  1122. // the product overlay will fade out
  1123. m_flMovieFadeInTime = Plat_FloatTime() + TRANSITION_TO_MOVIE_DELAY_TIME;
  1124. }
  1125. // There are cases where our texture may never have been rendered (immediately alt+tabbing away on startup). This check allows us to
  1126. // recalculate the correct UVs in that case.
  1127. if ( m_flU1 == 0.0f || m_flV1 == 0.0f )
  1128. {
  1129. CalculateMovieParameters();
  1130. }
  1131. // Update our frame, but only if Bink is ready for us to process another frame.
  1132. // We aren't really swapping here, but ReadyForSwap is a good way to throttle.
  1133. // We'd rather throttle this way so that we don't limit the overall frame rate of the system.
  1134. if ( false ) // TODO: if ( g_pBIK->ReadyForSwap( m_BIKHandle ) )
  1135. {
  1136. if ( g_pBIK->Update( m_BIKHandle ) == false )
  1137. {
  1138. // Issue a close command
  1139. ShutdownBackgroundMovie();
  1140. return false;
  1141. }
  1142. }
  1143. // Draw the polys to draw the movie out
  1144. CMatRenderContextPtr pRenderContext( materials );
  1145. pRenderContext->MatrixMode( MATERIAL_VIEW );
  1146. pRenderContext->PushMatrix();
  1147. pRenderContext->LoadIdentity();
  1148. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  1149. pRenderContext->PushMatrix();
  1150. pRenderContext->LoadIdentity();
  1151. IMaterial *pMaterial = g_pBIK->GetMaterial( m_BIKHandle );
  1152. pRenderContext->Bind( pMaterial, NULL );
  1153. CMeshBuilder meshBuilder;
  1154. IMesh* pMesh = pRenderContext->GetDynamicMesh( true );
  1155. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  1156. float flLeftX = 0;
  1157. float flRightX = GetWide()-1;
  1158. float flTopY = 0;
  1159. float flBottomY = GetTall()-1;
  1160. // Map our UVs to cut out just the portion of the video we're interested in
  1161. float flLeftU = m_flU0;
  1162. float flTopV = m_flV0;
  1163. // We need to subtract off a pixel to make sure we don't bleed
  1164. float flRightU = m_flU1 - ( 1.0f / (float) GetWide() );
  1165. float flBottomV = m_flV1 - ( 1.0f / (float) GetTall() );
  1166. // Get the current viewport size
  1167. int vx, vy, vw, vh;
  1168. pRenderContext->GetViewport( vx, vy, vw, vh );
  1169. // map from screen pixel coords to -1..1
  1170. flRightX = FLerp( -1, 1, 0, vw, flRightX );
  1171. flLeftX = FLerp( -1, 1, 0, vw, flLeftX );
  1172. flTopY = FLerp( 1, -1, 0, vh ,flTopY );
  1173. flBottomY = FLerp( 1, -1, 0, vh, flBottomY );
  1174. for ( int corner=0; corner<4; corner++ )
  1175. {
  1176. bool bLeft = (corner==0) || (corner==3);
  1177. meshBuilder.Position3f( (bLeft) ? flLeftX : flRightX, (corner & 2) ? flBottomY : flTopY, 0.0f );
  1178. meshBuilder.Normal3f( 0.0f, 0.0f, 1.0f );
  1179. meshBuilder.TexCoord2f( 0, (bLeft) ? flLeftU : flRightU, (corner & 2) ? flBottomV : flTopV );
  1180. meshBuilder.TangentS3f( 0.0f, 1.0f, 0.0f );
  1181. meshBuilder.TangentT3f( 1.0f, 0.0f, 0.0f );
  1182. meshBuilder.Color4f( 1.0f, 1.0f, 1.0f, 1.0f );
  1183. meshBuilder.AdvanceVertex();
  1184. }
  1185. meshBuilder.End();
  1186. pMesh->Draw();
  1187. pRenderContext->MatrixMode( MATERIAL_VIEW );
  1188. pRenderContext->PopMatrix();
  1189. pRenderContext->MatrixMode( MATERIAL_PROJECTION );
  1190. pRenderContext->PopMatrix();
  1191. if ( IsGameConsole() )
  1192. {
  1193. // The product screen has more range than the movie, so the fade works better if the overlay draws after and fades out.
  1194. // Fading the product screen out, modulate alpha [1..0]
  1195. float flFadeDelta = RemapValClamped( Plat_FloatTime(), m_flMovieFadeInTime, m_flMovieFadeInTime + TRANSITION_TO_MOVIE_FADE_TIME, 1.0f, 0.0f );
  1196. if ( flFadeDelta > 0.0f )
  1197. {
  1198. surface()->DrawSetColor( 255, 255, 255, flFadeDelta * 255.0f );
  1199. surface()->DrawSetTexture( m_iMovieTransitionImage );
  1200. surface()->DrawTexturedRect( 0, 0, GetWide(), GetTall() );
  1201. }
  1202. // goes from [0..1]
  1203. flFadeDelta = 1.0f - flFadeDelta;
  1204. if ( m_bFadeMusicUp )
  1205. {
  1206. CBaseModPanel::GetSingleton().UpdateBackgroundMusicVolume( flFadeDelta );
  1207. if ( flFadeDelta >= 1.0f )
  1208. {
  1209. // stop updating
  1210. m_bFadeMusicUp = false;
  1211. }
  1212. }
  1213. *pflFadeDelta = flFadeDelta;
  1214. }
  1215. #if defined( ENABLE_BIK_PERF_SPEW ) && ENABLE_BIK_PERF_SPEW
  1216. {
  1217. // timing debug code for bink playback
  1218. static double flPreviousTime = -1.0;
  1219. double flTime = Plat_FloatTime();
  1220. double flDeltaTime = flTime - flPreviousTime;
  1221. if ( flDeltaTime > 0.0 )
  1222. {
  1223. Warning( "%0.2lf sec*60 %0.2lf fps\n", flDeltaTime * 60.0, 1.0 / flDeltaTime );
  1224. }
  1225. flPreviousTime = flTime;
  1226. }
  1227. #endif
  1228. return true;
  1229. }
  1230. //=============================================================================
  1231. void CBaseModPanel::PaintBackground()
  1232. {
  1233. int wide, tall;
  1234. GetSize( wide, tall );
  1235. if ( !m_LevelLoading &&
  1236. !GameUI().IsInLevel() &&
  1237. !GameUI().IsInBackgroundLevel() )
  1238. {
  1239. if ( engine->IsTransitioningToLoad() )
  1240. {
  1241. // ensure the background is clear
  1242. // the loading progress is about to take over in a few frames
  1243. // this keeps us from flashing a different graphic
  1244. surface()->DrawSetColor( 0, 0, 0, 255 );
  1245. surface()->DrawSetTexture( m_iBackgroundImageID );
  1246. surface()->DrawTexturedRect( 0, 0, wide, tall );
  1247. }
  1248. else
  1249. {
  1250. // Render the background movie
  1251. float flFadeDelta;
  1252. if ( !RenderBackgroundMovie( &flFadeDelta ) )
  1253. {
  1254. // movie failed used product screen as background
  1255. surface()->DrawSetColor( 255, 255, 255, 255 );
  1256. surface()->DrawSetTexture( m_iBackgroundImageID );
  1257. surface()->DrawTexturedRect( 0, 0, wide, tall );
  1258. }
  1259. }
  1260. }
  1261. // Update and render the new UI
  1262. if ( g_pGameUIGameSystem )
  1263. {
  1264. Rect_t uiViewport;
  1265. uiViewport.x = 0;
  1266. uiViewport.y = 0;
  1267. uiViewport.width = wide;
  1268. uiViewport.height = tall;
  1269. g_pGameUISystemMgr->RunFrame();
  1270. // Need to use realtime so animations will play even when paused.
  1271. g_pGameUIGameSystem->Render( uiViewport, gpGlobals->realtime );
  1272. }
  1273. #if defined( _GAMECONSOLE )
  1274. if ( !m_LevelLoading && !GameUI().IsInLevel() && xbox_install_status.GetBool() )
  1275. {
  1276. DrawCopyStats();
  1277. }
  1278. #endif
  1279. }
  1280. void CBaseModPanel::OnCommand(const char *command)
  1281. {
  1282. if ( !Q_stricmp( command, "QuitRestartNoConfirm" ) )
  1283. {
  1284. if ( IsGameConsole() )
  1285. {
  1286. StartExitingProcess( false );
  1287. }
  1288. }
  1289. else if ( !Q_stricmp( command, "RestartWithNewLanguage" ) )
  1290. {
  1291. if ( !IsGameConsole() )
  1292. {
  1293. // TODO: UI: RestartWithNewLanguage
  1294. // - const char *pUpdatedAudioLanguage = Audio::GetUpdatedAudioLanguage();
  1295. const char *pUpdatedAudioLanguage = "english";
  1296. if ( pUpdatedAudioLanguage[ 0 ] != '\0' )
  1297. {
  1298. char szSteamURL[50];
  1299. char szAppId[50];
  1300. // hide everything while we quit
  1301. SetVisible( false );
  1302. vgui::surface()->RestrictPaintToSinglePanel( GetVPanel() );
  1303. engine->ClientCmd_Unrestricted( "quit\n" );
  1304. // Construct Steam URL. Pattern is steam://run/<appid>/<language>. (e.g. Ep1 In French ==> steam://run/380/french)
  1305. Q_strcpy(szSteamURL, "steam://run/");
  1306. itoa( engine->GetAppID(), szAppId, 10 );
  1307. Q_strcat( szSteamURL, szAppId, sizeof( szSteamURL ) );
  1308. Q_strcat( szSteamURL, "/", sizeof( szSteamURL ) );
  1309. Q_strcat( szSteamURL, pUpdatedAudioLanguage, sizeof( szSteamURL ) );
  1310. // Set Steam URL for re-launch in registry. Launcher will check this registry key and exec it in order to re-load the game in the proper language
  1311. vgui::system()->SetRegistryString("HKEY_CURRENT_USER\\Software\\Valve\\Source\\Relaunch URL", szSteamURL );
  1312. }
  1313. }
  1314. }
  1315. else
  1316. {
  1317. BaseClass::OnCommand( command );
  1318. }
  1319. }
  1320. bool CBaseModPanel::RequestInfo( KeyValues *data )
  1321. {
  1322. if ( !Q_stricmp( "InputControlState", data->GetName() ) )
  1323. {
  1324. data->SetInt( "passthrough", 1 );
  1325. return true;
  1326. }
  1327. return BaseClass::RequestInfo( data );
  1328. }
  1329. bool CBaseModPanel::IsReadyToWriteConfig( void )
  1330. {
  1331. // For cert we only want to write config files is it has been at least 3 seconds
  1332. #ifdef _GAMECONSOLE
  1333. static ConVarRef r_host_write_last_time( "host_write_last_time" );
  1334. return ( Plat_FloatTime() > r_host_write_last_time.GetFloat() + 3.05f );
  1335. #endif
  1336. return false;
  1337. }
  1338. //=============================================================================
  1339. // Start system shutdown. Cannot be stopped.
  1340. // A Restart is cold restart, plays the intro movie again.
  1341. //=============================================================================
  1342. void CBaseModPanel::StartExitingProcess( bool bWarmRestart )
  1343. {
  1344. if ( !IsGameConsole() )
  1345. {
  1346. // xbox only
  1347. Assert( 0 );
  1348. return;
  1349. }
  1350. if ( m_ExitingFrameCount )
  1351. {
  1352. // already fired
  1353. return;
  1354. }
  1355. #if defined( _GAMECONSOLE )
  1356. // signal the installer to stop
  1357. g_pXboxInstaller->Stop();
  1358. #endif
  1359. // cold restart or warm
  1360. m_bWarmRestartMode = bWarmRestart;
  1361. // the exiting screen will transition to obscure all the game and UI
  1362. // TODO: UI: - OpenWindow( WT_TRANSITIONSCREEN, 0, false );
  1363. // must let a non trivial number of screen swaps occur to stabilize image
  1364. // ui runs in a constrained state, while shutdown is occurring
  1365. m_ExitingFrameCount = 15;
  1366. // exiting cannot be stopped
  1367. // do not allow any input to occur
  1368. g_pInputSystem->DetachFromWindow();
  1369. // start shutting down systems
  1370. engine->StartXboxExitingProcess();
  1371. }
  1372. void CBaseModPanel::OnSetFocus()
  1373. {
  1374. BaseClass::OnSetFocus();
  1375. if ( IsPC() )
  1376. {
  1377. GameConsole().Hide();
  1378. }
  1379. }
  1380. void CBaseModPanel::OnMovedPopupToFront()
  1381. {
  1382. if ( IsPC() )
  1383. {
  1384. GameConsole().Hide();
  1385. }
  1386. }
  1387. bool CBaseModPanel::IsBackgroundMusicPlaying()
  1388. {
  1389. if ( m_backgroundMusic.IsEmpty() )
  1390. return false;
  1391. if ( m_nBackgroundMusicGUID == 0 )
  1392. return false;
  1393. return enginesound->IsSoundStillPlaying( m_nBackgroundMusicGUID );
  1394. }
  1395. // per Morasky
  1396. #define BACKGROUND_MUSIC_DUCK 0.15f
  1397. bool CBaseModPanel::StartBackgroundMusic( float fVol )
  1398. {
  1399. if ( IsBackgroundMusicPlaying() )
  1400. return true;
  1401. if ( m_backgroundMusic.IsEmpty() )
  1402. return false;
  1403. // trying to exit, cannot start it
  1404. if ( m_ExitingFrameCount )
  1405. return false;
  1406. m_nBackgroundMusicGUID = 0; // TODO: enginesound->EmitAmbientSound( m_backgroundMusic, BACKGROUND_MUSIC_DUCK * fVol );
  1407. return ( m_nBackgroundMusicGUID != 0 );
  1408. }
  1409. void CBaseModPanel::UpdateBackgroundMusicVolume( float fVol )
  1410. {
  1411. if ( !IsBackgroundMusicPlaying() )
  1412. return;
  1413. // mixes too loud against soft ui sounds
  1414. enginesound->SetVolumeByGuid( m_nBackgroundMusicGUID, BACKGROUND_MUSIC_DUCK * fVol );
  1415. }
  1416. void CBaseModPanel::ReleaseBackgroundMusic()
  1417. {
  1418. if ( m_backgroundMusic.IsEmpty() )
  1419. return;
  1420. if ( m_nBackgroundMusicGUID == 0 )
  1421. return;
  1422. // need to stop the sound now, do not queue the stop
  1423. // we must release the 2-5 MB held by this resource
  1424. // TODO: enginesound->StopSoundByGuid( m_nBackgroundMusicGUID, true );
  1425. #if defined( _GAMECONSOLE )
  1426. // TODO: enginesound->UnloadSound( m_backgroundMusic );
  1427. #endif
  1428. m_nBackgroundMusicGUID = 0;
  1429. }
  1430. void CBaseModPanel::SafeNavigateTo( Panel *pExpectedFrom, Panel *pDesiredTo, bool bAllowStealFocus )
  1431. {
  1432. Panel *pOriginalFocus = ipanel()->GetPanel( GetCurrentKeyFocus(), GetModuleName() );
  1433. bool bSomeoneElseHasFocus = pOriginalFocus && (pOriginalFocus != pExpectedFrom);
  1434. bool bActuallyChangingFocus = (pExpectedFrom != pDesiredTo);
  1435. bool bNeedToReturnKeyFocus = !bAllowStealFocus && bSomeoneElseHasFocus && bActuallyChangingFocus;
  1436. pDesiredTo->NavigateTo();
  1437. if ( bNeedToReturnKeyFocus )
  1438. {
  1439. pDesiredTo->NavigateFrom();
  1440. pOriginalFocus->NavigateTo();
  1441. }
  1442. }