Team Fortress 2 Source Code as on 22/4/2020
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.

3427 lines
105 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "tf_hud_mainmenuoverride.h"
  9. #include "ienginevgui.h"
  10. #include "tf_viewport.h"
  11. #include "clientmode_tf.h"
  12. #include "confirm_dialog.h"
  13. #include <vgui/ILocalize.h>
  14. #include "tf_controls.h"
  15. #include "tf_gamerules.h"
  16. #include "tf_statsummary.h"
  17. #include "rtime.h"
  18. #include "tf_gcmessages.h"
  19. #include "econ_notifications.h"
  20. #include "c_tf_freeaccount.h"
  21. #include "econ_gcmessages.h"
  22. #include "econ_item_inventory.h"
  23. #include "gcsdk/gcclient.h"
  24. #include "gcsdk/gcclientjob.h"
  25. #include "econ_item_system.h"
  26. #include <vgui_controls/AnimationController.h>
  27. #include "store/store_panel.h"
  28. #include "gc_clientsystem.h"
  29. #include <vgui_controls/ScrollBarSlider.h>
  30. #include "filesystem.h"
  31. #include "tf_hud_disconnect_prompt.h"
  32. #include "tf_gc_client.h"
  33. #include "sourcevr/isourcevirtualreality.h"
  34. #include "materialsystem/imaterialsystem.h"
  35. #include "materialsystem/materialsystem_config.h"
  36. #include "tf_warinfopanel.h"
  37. #include "quest_log_panel.h"
  38. #include "tf_item_inventory.h"
  39. #include "quest_log_panel.h"
  40. #include "econ_quests.h"
  41. #include "tf_streams.h"
  42. #include "tf_matchmaking_shared.h"
  43. #include "tf_lobby_container_frame_comp.h"
  44. #include "tf_lobby_container_frame_mvm.h"
  45. #include "tf_lobby_container_frame_casual.h"
  46. #include "replay/ireplaysystem.h"
  47. #include "replay/ienginereplay.h"
  48. #include "replay/vgui/replayperformanceeditor.h"
  49. #include "materialsystem/itexture.h"
  50. #include "imageutils.h"
  51. #include "icommandline.h"
  52. #include "vgui/ISystem.h"
  53. #include "report_player_dialog.h"
  54. #ifdef SAXXYMAINMENU_ENABLED
  55. #include "tf_hud_saxxycontest.h"
  56. #endif
  57. #include "c_tf_gamestats.h"
  58. // memdbgon must be the last include file in a .cpp file!!!
  59. #include "tier0/memdbgon.h"
  60. void AddSubKeyNamed( KeyValues *pKeys, const char *pszName );
  61. extern const char *g_sImagesBlue[];
  62. extern int EconWear_ToIntCategory( float flWear );
  63. void cc_tf_safemode_toggle( IConVar *pConVar, const char *pOldString, float flOldValue )
  64. {
  65. CHudMainMenuOverride *pMMOverride = (CHudMainMenuOverride*)( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  66. if ( pMMOverride )
  67. {
  68. pMMOverride->InvalidateLayout();
  69. }
  70. }
  71. ConVar tf_recent_achievements( "tf_recent_achievements", "0", FCVAR_ARCHIVE );
  72. ConVar tf_training_has_prompted_for_training( "tf_training_has_prompted_for_training", "0", FCVAR_ARCHIVE, "Whether the user has been prompted for training" );
  73. ConVar tf_training_has_prompted_for_offline_practice( "tf_training_has_prompted_for_offline_practice", "0", FCVAR_ARCHIVE, "Whether the user has been prompted to try offline practice." );
  74. ConVar tf_training_has_prompted_for_forums( "tf_training_has_prompted_for_forums", "0", FCVAR_ARCHIVE, "Whether the user has been prompted to view the new user forums." );
  75. ConVar tf_training_has_prompted_for_options( "tf_training_has_prompted_for_options", "0", FCVAR_ARCHIVE, "Whether the user has been prompted to view the TF2 advanced options." );
  76. ConVar tf_training_has_prompted_for_loadout( "tf_training_has_prompted_for_loadout", "0", FCVAR_ARCHIVE, "Whether the user has been prompted to equip something in their loadout." );
  77. ConVar cl_ask_bigpicture_controller_opt_out( "cl_ask_bigpicture_controller_opt_out", "0", FCVAR_ARCHIVE, "Whether the user has opted out of being prompted for controller support in Big Picture." );
  78. ConVar cl_mainmenu_operation_motd_start( "cl_mainmenu_operation_motd_start", "0", FCVAR_ARCHIVE | FCVAR_HIDDEN );
  79. ConVar cl_mainmenu_operation_motd_reset( "cl_mainmenu_operation_motd_reset", "0", FCVAR_ARCHIVE | FCVAR_HIDDEN );
  80. ConVar cl_mainmenu_safemode( "cl_mainmenu_safemode", "0", FCVAR_NONE, "Enable safe mode", cc_tf_safemode_toggle );
  81. ConVar cl_mainmenu_updateglow( "cl_mainmenu_updateglow", "1", FCVAR_ARCHIVE | FCVAR_HIDDEN );
  82. void cc_promotional_codes_button_changed( IConVar *pConVar, const char *pOldString, float flOldValue )
  83. {
  84. IViewPortPanel *pMMOverride = ( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  85. if ( pMMOverride )
  86. {
  87. ( (CHudMainMenuOverride*)pMMOverride )->UpdatePromotionalCodes();
  88. }
  89. }
  90. ConVar cl_promotional_codes_button_show( "cl_promotional_codes_button_show", "1", FCVAR_ARCHIVE, "Toggles the 'View Promotional Codes' button in the main menu for players that have used the 'RIFT Well Spun Hat Claim Code'.", cc_promotional_codes_button_changed );
  91. extern bool Training_IsComplete();
  92. //-----------------------------------------------------------------------------
  93. // Callback to launch the lobby UI
  94. //-----------------------------------------------------------------------------
  95. static void CL_OpenMatchmakingLobby( const CCommand &args )
  96. {
  97. if ( GTFGCClientSystem()->GetMatchmakingUIState() != eMatchmakingUIState_InGame )
  98. {
  99. const char *arg1 = "";
  100. if ( args.ArgC() > 1 )
  101. {
  102. arg1 = args[1];
  103. }
  104. // Make sure we are connected to steam, or they are going to be disappointed
  105. if ( steamapicontext == NULL
  106. || steamapicontext->SteamUtils() == NULL
  107. || steamapicontext->SteamMatchmakingServers() == NULL
  108. || steamapicontext->SteamUser() == NULL
  109. || !steamapicontext->SteamUser()->BLoggedOn()
  110. ) {
  111. Warning( "Steam not properly initialized or connected.\n" );
  112. ShowMessageBox( "#TF_MM_GenericFailure_Title", "#TF_MM_GenericFailure", "#GameUI_OK" );
  113. return;
  114. }
  115. // Make sure we have a GC connection
  116. if ( !GCClientSystem()->BConnectedtoGC() )
  117. {
  118. Warning( "Not connected to GC.\n" );
  119. ShowMessageBox( "#TF_MM_NoGC_Title", "#TF_MM_NoGC", "#GameUI_OK" );
  120. return;
  121. }
  122. // If we're idle, use our argument to start matchmaking.
  123. if ( GTFGCClientSystem()->GetMatchmakingUIState() == eMatchmakingUIState_Inactive )
  124. {
  125. TF_MatchmakingMode mode = TF_Matchmaking_LADDER;
  126. if ( FStrEq( args[1], "mvm" ) )
  127. {
  128. mode = TF_Matchmaking_MVM;
  129. }
  130. else if ( FStrEq( args[1], "ladder" ) )
  131. {
  132. mode = TF_Matchmaking_LADDER;
  133. }
  134. else if ( FStrEq( args[1], "casual" ) )
  135. {
  136. mode = TF_Matchmaking_CASUAL;
  137. }
  138. GTFGCClientSystem()->BeginMatchmaking( mode );
  139. }
  140. }
  141. CHudMainMenuOverride* pMMOverride = (CHudMainMenuOverride*)( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  142. if ( pMMOverride )
  143. {
  144. switch( GTFGCClientSystem()->GetSearchMode() )
  145. {
  146. case TF_Matchmaking_MVM:
  147. pMMOverride->OpenMvMMMPanel();
  148. break;
  149. case TF_Matchmaking_LADDER:
  150. pMMOverride->OpenCompMMPanel();
  151. break;
  152. case TF_Matchmaking_CASUAL:
  153. pMMOverride->OpenCasualMMPanel();
  154. default:
  155. return;
  156. }
  157. }
  158. }
  159. static ConCommand openmatchmakinglobby_command( "OpenMatchmakingLobby", &CL_OpenMatchmakingLobby, "Activates the matchmaking lobby." );
  160. static void CL_ReloadMMPanels( const CCommand &args )
  161. {
  162. CHudMainMenuOverride* pMMOverride = (CHudMainMenuOverride*)( gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE ) );
  163. if ( pMMOverride )
  164. {
  165. pMMOverride->ReloadMMPanels();
  166. }
  167. }
  168. ConCommand reload_mm_panels( "reload_mm_panels", &CL_ReloadMMPanels );
  169. //-----------------------------------------------------------------------------
  170. // Purpose: Prompt the user and ask if they really want to start training (if they are in a game)
  171. //-----------------------------------------------------------------------------
  172. class CTFConfirmTrainingDialog : public CConfirmDialog
  173. {
  174. DECLARE_CLASS_SIMPLE( CTFConfirmTrainingDialog, CConfirmDialog );
  175. public:
  176. CTFConfirmTrainingDialog( const char *pText, const char *pTitle, vgui::Panel *parent ) : BaseClass(parent), m_pText( pText ), m_pTitle( pTitle ) {}
  177. virtual const wchar_t *GetText()
  178. {
  179. return g_pVGuiLocalize->Find( m_pText );
  180. }
  181. virtual void ApplySchemeSettings( vgui::IScheme *pScheme )
  182. {
  183. BaseClass::ApplySchemeSettings( pScheme );
  184. // Set the X to be bright, and the rest dull
  185. if ( m_pConfirmButton )
  186. {
  187. m_pConfirmButton->SetText( "#TF_Training_Prompt_ConfirmButton" );
  188. }
  189. if ( m_pCancelButton )
  190. {
  191. m_pCancelButton->SetText( "#TF_Training_Prompt_CancelButton" );
  192. }
  193. CExLabel *pTitle = dynamic_cast< CExLabel* >( FindChildByName( "TitleLabel" ) );
  194. if ( pTitle )
  195. {
  196. pTitle->SetText( m_pTitle );
  197. }
  198. }
  199. protected:
  200. const char *m_pText;
  201. const char *m_pTitle;
  202. };
  203. class CCompetitiveAccessInfoPanel : public EditablePanel, public CLocalSteamSharedObjectListener
  204. {
  205. DECLARE_CLASS_SIMPLE( CCompetitiveAccessInfoPanel, EditablePanel );
  206. public:
  207. CCompetitiveAccessInfoPanel( Panel* pParent, const char* pszName )
  208. : EditablePanel( pParent, pszName )
  209. {
  210. m_pPhoneButton = NULL;
  211. m_pPremiumButton = NULL;
  212. m_pPhoneCheckImage = NULL;
  213. m_pPremiumCheckImage = NULL;
  214. }
  215. virtual void ApplySchemeSettings( IScheme *pScheme ) OVERRIDE
  216. {
  217. BaseClass::ApplySchemeSettings( pScheme );
  218. LoadControlSettings( "resource/ui/CompetitiveAccessInfo.res" );
  219. m_pPhoneButton = FindControl< CExImageButton >( "PhoneButton", true );
  220. m_pPremiumButton = FindControl< CExImageButton >( "PremiumButton", true );
  221. m_pPhoneCheckImage = FindControl< ImagePanel >( "PhoneCheckImage", true );
  222. m_pPremiumCheckImage = FindControl< ImagePanel >( "PremiumCheckImage", true );
  223. }
  224. virtual void PerformLayout() OVERRIDE
  225. {
  226. BaseClass::PerformLayout();
  227. bool bIsFreeAccount = IsFreeTrialAccount();
  228. if ( m_pPremiumButton )
  229. {
  230. m_pPremiumButton->SetEnabled( bIsFreeAccount );
  231. }
  232. if ( m_pPremiumCheckImage )
  233. {
  234. m_pPremiumCheckImage->SetVisible( !bIsFreeAccount );
  235. }
  236. bool bIsPhoneVerified = GTFGCClientSystem()->BIsPhoneVerified();
  237. bool bIsPhoneIdentifying = GTFGCClientSystem()->BIsPhoneIdentifying();
  238. bool bPhoneReady = bIsPhoneVerified && bIsPhoneIdentifying;
  239. if ( m_pPhoneButton )
  240. {
  241. m_pPhoneButton->SetEnabled( !bPhoneReady );
  242. }
  243. if ( m_pPhoneCheckImage )
  244. {
  245. m_pPhoneCheckImage->SetVisible( bPhoneReady );
  246. }
  247. }
  248. virtual void OnCommand( const char *command ) OVERRIDE
  249. {
  250. if ( FStrEq( command, "close" ) )
  251. {
  252. SetVisible( false );
  253. return;
  254. }
  255. else if ( FStrEq( command, "addphone" ) )
  256. {
  257. if ( steamapicontext && steamapicontext->SteamFriends() )
  258. {
  259. steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "https://support.steampowered.com/kb_article.php?ref=8625-WRAH-9030#addphone" );
  260. }
  261. return;
  262. }
  263. else if ( FStrEq( command, "addpremium" ) )
  264. {
  265. if ( steamapicontext && steamapicontext->SteamFriends() )
  266. {
  267. steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "https://steamcommunity.com/sharedfiles/filedetails/?id=143430756" );
  268. }
  269. return;
  270. }
  271. BaseClass::OnCommand( command );
  272. }
  273. virtual void SOCreated( const CSteamID & steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent ) OVERRIDE
  274. {
  275. if ( pObject->GetTypeID() != CEconGameAccountClient::k_nTypeID )
  276. return;
  277. if ( GTFGCClientSystem()->BHasCompetitiveAccess() )
  278. {
  279. SetVisible( false );
  280. }
  281. else
  282. {
  283. InvalidateLayout();
  284. }
  285. }
  286. virtual void SOUpdated( const CSteamID & steamIDOwner, const CSharedObject *pObject, ESOCacheEvent eEvent ) OVERRIDE
  287. {
  288. if ( pObject->GetTypeID() != CEconGameAccountClient::k_nTypeID )
  289. return;
  290. if ( GTFGCClientSystem()->BHasCompetitiveAccess() )
  291. {
  292. SetVisible( false );
  293. }
  294. else
  295. {
  296. InvalidateLayout();
  297. }
  298. }
  299. private:
  300. CExImageButton *m_pPhoneButton;
  301. CExImageButton *m_pPremiumButton;
  302. ImagePanel *m_pPhoneCheckImage;
  303. ImagePanel *m_pPremiumCheckImage;
  304. };
  305. DECLARE_BUILD_FACTORY( CCompetitiveAccessInfoPanel );
  306. class CMainMenuPlayListEntry : public EditablePanel
  307. {
  308. DECLARE_CLASS_SIMPLE( CMainMenuPlayListEntry, EditablePanel );
  309. public:
  310. enum EDisabledStates_t
  311. {
  312. NOT_DISABLED = 0,
  313. DISABLED_NO_COMP_ACCESS,
  314. DISABLED_NO_GC,
  315. DISABLED_MATCH_RUNNING,
  316. NUM_DISABLED_STATES
  317. };
  318. CMainMenuPlayListEntry( Panel* pParent, const char* pszName )
  319. : EditablePanel( pParent, pszName )
  320. {
  321. m_pToolTip = NULL;
  322. }
  323. ~CMainMenuPlayListEntry()
  324. {
  325. if (m_pToolTip != NULL)
  326. {
  327. delete m_pToolTip;
  328. m_pToolTip = NULL;
  329. }
  330. }
  331. virtual void ApplySchemeSettings( IScheme *pScheme ) OVERRIDE
  332. {
  333. BaseClass::ApplySchemeSettings( pScheme );
  334. LoadControlSettings( "resource/ui/MainMenuPlayListEntry.res" );
  335. CExImageButton *pLockImage = FindControl< CExImageButton >("LockImage");
  336. if (pLockImage)
  337. {
  338. EditablePanel *pToolTipPanel = FindControl< EditablePanel >("TooltipPanel");
  339. if (pToolTipPanel)
  340. {
  341. m_pToolTip = new CTFTextToolTip(this);
  342. m_pToolTip->SetEmbeddedPanel(pToolTipPanel);
  343. pToolTipPanel->MakePopup(false, true);
  344. pToolTipPanel->SetKeyBoardInputEnabled(false);
  345. pToolTipPanel->SetMouseInputEnabled(false);
  346. m_pToolTip->SetText("#TF_Competitive_Requirements");
  347. m_pToolTip->SetTooltipDelay(0);
  348. pLockImage->SetTooltip(m_pToolTip, "#TF_Competitive_Requirements");
  349. }
  350. }
  351. SetDisabledReason( NOT_DISABLED );
  352. }
  353. virtual void ApplySettings( KeyValues *inResourceData ) OVERRIDE
  354. {
  355. BaseClass::ApplySettings( inResourceData );
  356. m_strImageName = inResourceData->GetString( "image_name" );
  357. m_strButtonCommand = inResourceData->GetString( "button_command" );
  358. m_strButtonToken = inResourceData->GetString( "button_token" );
  359. m_strDescToken = inResourceData->GetString( "desc_token" );
  360. }
  361. void SetDisabledReason( EDisabledStates_t eReason )
  362. {
  363. static const DisabledStateDesc_t s_DisabledStates[] = { { NULL, NULL, NULL } // NOT_DISABLED
  364. , { "#TF_Competitive_Requirements", "comp_access_info", "locked_icon" } // DISABLED_NO_COMP_ACCESS
  365. , { "#TF_MM_NoGC", NULL, "gc_dc" } // DISABLED_NO_GC
  366. , { "#TF_Competitive_MatchRunning", NULL, NULL } }; // DISABLED_MATCH_RUNNING
  367. COMPILE_TIME_ASSERT( ARRAYSIZE( s_DisabledStates ) == NUM_DISABLED_STATES );
  368. const DisabledStateDesc_t& stateDisabled = s_DisabledStates[ eReason ];
  369. SetControlEnabled( "ModeButton", stateDisabled.m_pszLocToken == NULL );
  370. SetControlVisible( "LockImage", stateDisabled.m_pszLocToken != NULL );
  371. CExImageButton *pLockImage = FindControl< CExImageButton >("LockImage");
  372. if ( pLockImage )
  373. {
  374. if ( stateDisabled.m_pszImageName )
  375. {
  376. pLockImage->SetSubImage( stateDisabled.m_pszImageName );
  377. }
  378. // Button behavior
  379. pLockImage->SetEnabled( stateDisabled.m_pszButtonCommand != NULL );
  380. pLockImage->SetCommand( stateDisabled.m_pszButtonCommand );
  381. pLockImage->GetImage()->SetVisible( stateDisabled.m_pszImageName != NULL );
  382. m_pToolTip->SetText( stateDisabled.m_pszLocToken );
  383. pLockImage->SetTooltip( m_pToolTip, stateDisabled.m_pszLocToken );
  384. m_pToolTip->PerformLayout();
  385. }
  386. }
  387. virtual void PerformLayout() OVERRIDE
  388. {
  389. BaseClass::PerformLayout();
  390. ImagePanel* pModeImage = FindControl< ImagePanel >( "ModeImage" );
  391. if ( pModeImage )
  392. {
  393. pModeImage->SetImage( m_strImageName );
  394. }
  395. Button* pButton = FindControl< Button >( "ModeButton" );
  396. if ( pButton )
  397. {
  398. pButton->SetCommand( m_strButtonCommand );
  399. }
  400. Label* pLabel = FindControl< Label >( "ModeButton" );
  401. if ( pLabel )
  402. {
  403. pLabel->SetText( m_strButtonToken );
  404. }
  405. pLabel = FindControl< Label >( "DescLabel" );
  406. if ( pLabel )
  407. {
  408. pLabel->SetText( m_strDescToken );
  409. }
  410. pLabel = FindControl< Label >( "DescLabelShadow" );
  411. if ( pLabel )
  412. {
  413. pLabel->SetText( m_strDescToken );
  414. }
  415. }
  416. private:
  417. struct DisabledStateDesc_t
  418. {
  419. const char* m_pszLocToken;
  420. const char* m_pszButtonCommand;
  421. const char* m_pszImageName;
  422. };
  423. CUtlString m_strImageName;
  424. CUtlString m_strButtonCommand;
  425. CUtlString m_strButtonToken;
  426. CUtlString m_strDescToken;
  427. CTFTextToolTip *m_pToolTip;
  428. };
  429. DECLARE_BUILD_FACTORY( CMainMenuPlayListEntry );
  430. //-----------------------------------------------------------------------------
  431. // Purpose:
  432. //-----------------------------------------------------------------------------
  433. CHudMainMenuOverride::CHudMainMenuOverride( IViewPort *pViewPort ) : BaseClass( NULL, PANEL_MAINMENUOVERRIDE )
  434. {
  435. // We don't want the gameui to delete us, or things get messy
  436. SetAutoDelete( false );
  437. SetVisible( true );
  438. m_bPlayListExpanded = false;
  439. m_pVRModeButton = NULL;
  440. m_pVRModeBackground = NULL;
  441. m_pButtonKV = NULL;
  442. m_pQuitButton = NULL;
  443. m_pDisconnectButton = NULL;
  444. m_pBackToReplaysButton = NULL;
  445. m_pStoreHasNewItemsImage = NULL;
  446. m_nLastMOTDRequestAt = 0;
  447. m_nLastMOTDRequestLanguage = k_Lang_English;
  448. m_bReloadedAllMOTDs = false;
  449. m_iCurrentMOTD = -1;
  450. m_bInitMOTD = false;
  451. m_pMOTDPanel = NULL;
  452. m_pMOTDShowPanel = NULL;
  453. m_pMOTDURLButton = NULL;
  454. m_pMOTDNextButton = NULL;
  455. m_pMOTDPrevButton = NULL;
  456. m_iNotiPanelWide = 0;
  457. m_pFeaturedItemPanel = NULL;//new CItemModelPanel( m_pStoreSpecialPanel, "FeaturedItemModelPanel" );
  458. m_bReapplyButtonKVs = false;
  459. m_pMouseOverItemPanel = vgui::SETUP_PANEL( new CItemModelPanel( this, "mouseoveritempanel" ) );
  460. m_pMouseOverTooltip = new CItemModelPanelToolTip( this );
  461. m_pMouseOverTooltip->SetupPanels( this, m_pMouseOverItemPanel );
  462. m_pMOTDHeaderLabel = NULL;
  463. m_pMOTDHeaderIcon = NULL;
  464. m_pMOTDTitleLabel = NULL;
  465. m_pMOTDTitleImageContainer = NULL;
  466. m_pMOTDTitleImage = NULL;
  467. m_hTitleLabelFont = vgui::INVALID_FONT;
  468. m_pQuestLogButton = new EditablePanel( this, "QuestLogButton" );
  469. #ifdef STAGING_ONLY
  470. m_bGeneratingIcons = false;
  471. m_pIconData = NULL;
  472. #endif
  473. m_bHaveNewMOTDs = false;
  474. m_bMOTDShownAtStartup = false;
  475. m_pCharacterImagePanel = NULL;
  476. m_iCharacterImageIdx = -1;
  477. #ifdef SAXXYMAINMENU_ENABLED
  478. m_pSaxxyAwardsPanel = NULL;
  479. m_pSaxxySettings = NULL;
  480. #endif
  481. m_pWarLandingPage = new CWarLandingPanel( this, "WarPanel" );
  482. m_flCheckTrainingAt = 0;
  483. m_bWasInTraining = false;
  484. m_flLastWarNagTime = 0.f;
  485. ScheduleItemCheck();
  486. m_pToolTip = new CMainMenuToolTip( this );
  487. m_pToolTipEmbeddedPanel = new vgui::EditablePanel( this, "TooltipPanel" );
  488. m_pToolTipEmbeddedPanel->MakePopup( false, true );
  489. m_pToolTipEmbeddedPanel->SetKeyBoardInputEnabled( false );
  490. m_pToolTipEmbeddedPanel->SetMouseInputEnabled( false );
  491. m_pToolTip->SetEmbeddedPanel( m_pToolTipEmbeddedPanel );
  492. m_pToolTip->SetTooltipDelay( 0 );
  493. ListenForGameEvent( "gc_connected" );
  494. ListenForGameEvent( "item_schema_initialized" );
  495. ListenForGameEvent( "store_pricesheet_updated" );
  496. ListenForGameEvent( "inventory_updated" );
  497. ListenForGameEvent( "gameui_activated" );
  498. ListenForGameEvent( "party_updated" );
  499. // Create our MOTD scrollable section
  500. m_pMOTDPanel = new vgui::EditablePanel( this, "MOTD_Panel" );
  501. m_pMOTDPanel->SetVisible( true );
  502. m_pMOTDTextPanel = new vgui::EditablePanel( this, "MOTD_TextPanel" );
  503. m_pMOTDTextScroller = new vgui::ScrollableEditablePanel( m_pMOTDPanel, m_pMOTDTextPanel, "MOTD_TextScroller" );
  504. m_pMOTDTextScroller->GetScrollbar()->SetAutohideButtons( true );
  505. m_pMOTDTextScroller->GetScrollbar()->SetPaintBorderEnabled( false );
  506. m_pMOTDTextScroller->GetScrollbar()->SetPaintBackgroundEnabled( false );
  507. m_pMOTDTextScroller->GetScrollbar()->GetButton(0)->SetPaintBorderEnabled( false );
  508. m_pMOTDTextScroller->GetScrollbar()->GetButton(0)->SetPaintBackgroundEnabled( false );
  509. m_pMOTDTextScroller->GetScrollbar()->GetButton(1)->SetPaintBorderEnabled( false );
  510. m_pMOTDTextScroller->GetScrollbar()->GetButton(1)->SetPaintBackgroundEnabled( false );
  511. m_pMOTDTextScroller->GetScrollbar()->SetAutoResize( PIN_TOPRIGHT, AUTORESIZE_DOWN, -24, 0, -16, 0 );
  512. m_pMOTDTextLabel = NULL;
  513. m_pNotificationsShowPanel = NULL;
  514. m_pNotificationsPanel = new vgui::EditablePanel( this, "Notifications_Panel" );
  515. m_pNotificationsControl = NotificationQueue_CreateMainMenuUIElement( m_pNotificationsPanel, "Notifications_Control" );
  516. m_pNotificationsScroller = new vgui::ScrollableEditablePanel( m_pNotificationsPanel, m_pNotificationsControl, "Notifications_Scroller" );
  517. m_iNumNotifications = 0;
  518. m_pFeaturedItemMouseOverPanel = new CItemModelPanel( this, "FeaturedItemMouseOverItemPanel" );
  519. m_pFeaturedItemToolTip = new CSimplePanelToolTip( this );
  520. m_pFeaturedItemToolTip->SetControlledPanel( m_pFeaturedItemMouseOverPanel );
  521. m_pBackground = new vgui::ImagePanel( this, "Background" );
  522. m_pEventPromoContainer = new EditablePanel( this, "EventPromo" );
  523. m_pSafeModeContainer = new EditablePanel( this, "SafeMode" );
  524. // Cause the quest UI to be created
  525. GetQuestLog();
  526. m_bStabilizedInitialLayout = false;
  527. m_bBackgroundUsesCharacterImages = true;
  528. m_pWatchStreamsPanel = new CTFStreamListPanel( this, "StreamListPanel" );
  529. vgui::ivgui()->AddTickSignal( GetVPanel(), 50 );
  530. }
  531. //-----------------------------------------------------------------------------
  532. // Purpose:
  533. //-----------------------------------------------------------------------------
  534. CHudMainMenuOverride::~CHudMainMenuOverride( void )
  535. {
  536. C_CTFGameStats::ImmediateWriteInterfaceEvent( "interface_close", "main_menu_override" );
  537. if ( GetClientModeTFNormal()->GameUI() )
  538. {
  539. GetClientModeTFNormal()->GameUI()->SetMainMenuOverride( NULL );
  540. }
  541. if ( m_pButtonKV )
  542. {
  543. m_pButtonKV->deleteThis();
  544. m_pButtonKV = NULL;
  545. }
  546. // Stop Animation Sequences
  547. if ( m_pNotificationsShowPanel )
  548. {
  549. g_pClientMode->GetViewportAnimationController()->CancelAnimationsForPanel( m_pNotificationsShowPanel );
  550. }
  551. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  552. }
  553. //-----------------------------------------------------------------------------
  554. // Purpose: Override painting traversal to suppress main menu painting if we're not ready to show yet
  555. //-----------------------------------------------------------------------------
  556. void CHudMainMenuOverride::PaintTraverse( bool Repaint, bool allowForce )
  557. {
  558. // Ugly hack: disable painting until we're done screwing around with updating the layout during initialization.
  559. // Use -menupaintduringinit command line parameter to reinstate old behavior
  560. if ( m_bStabilizedInitialLayout || CommandLine()->CheckParm("-menupaintduringinit") )
  561. {
  562. BaseClass::PaintTraverse( Repaint, allowForce );
  563. }
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Purpose:
  567. //-----------------------------------------------------------------------------
  568. void CHudMainMenuOverride::OnTick()
  569. {
  570. if ( m_iNumNotifications != NotificationQueue_GetNumNotifications() )
  571. {
  572. m_iNumNotifications = NotificationQueue_GetNumNotifications();
  573. UpdateNotifications();
  574. CheckForNewQuests();
  575. }
  576. else if ( m_pNotificationsPanel->IsVisible() )
  577. {
  578. AdjustNotificationsPanelHeight();
  579. }
  580. static bool s_bRanOnce = false;
  581. if ( !s_bRanOnce )
  582. {
  583. s_bRanOnce = true;
  584. if ( char const *szConnectAdr = CommandLine()->ParmValue( "+connect" ) )
  585. {
  586. Msg( "Executing deferred connect command: %s\n", szConnectAdr );
  587. engine->ExecuteClientCmd( CFmtStr( "connect %s -%s\n", szConnectAdr, "ConnectStringOnCommandline" ) );
  588. }
  589. }
  590. // See if its time to nag about joining the war
  591. float flTimeSinceWarNag = Plat_FloatTime() - m_flLastWarNagTime;
  592. if ( !m_bPlayListExpanded && m_pHighlightAnims[ MMHA_WAR ] && ( flTimeSinceWarNag > 300.f || m_flLastWarNagTime == 0.f ) )
  593. {
  594. // Make sure our SOCache is ready
  595. GCSDK::CGCClientSharedObjectCache *pSOCache = NULL;
  596. if ( steamapicontext && steamapicontext->SteamUser() )
  597. {
  598. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  599. pSOCache = GCClientSystem()->GetSOCache( steamID );
  600. }
  601. // Need to be initialized. If we're not, we'll get false positives
  602. // when we actually go to look for our war data
  603. if ( pSOCache && pSOCache->BIsInitialized() )
  604. {
  605. m_flLastWarNagTime = Plat_FloatTime();
  606. // Get war data
  607. const CWarDefinition* pWarDef = GetItemSchema()->GetWarDefinitionByIndex( PYRO_VS_HEAVY_WAR_DEF_INDEX );
  608. CWarData *pWarData = GetLocalPlayerWarData( pWarDef->GetDefIndex() );
  609. war_side_t nAffiliation = INVALID_WAR_SIDE;
  610. if ( pWarData )
  611. {
  612. // Get affiliation if they have one.
  613. nAffiliation = pWarData->Obj().affiliation();
  614. }
  615. // They haven't joined the war! Nag 'em
  616. if ( nAffiliation == INVALID_WAR_SIDE && pWarDef->IsActive() )
  617. {
  618. StartHighlightAnimation( MMHA_WAR );
  619. }
  620. }
  621. }
  622. #ifdef STAGING_ONLY
  623. if ( m_bGeneratingIcons )
  624. {
  625. GenerateIconsThink();
  626. }
  627. #endif
  628. }
  629. //-----------------------------------------------------------------------------
  630. // Purpose:
  631. //-----------------------------------------------------------------------------
  632. void CHudMainMenuOverride::AttachToGameUI( void )
  633. {
  634. C_CTFGameStats::ImmediateWriteInterfaceEvent( "interface_open", "main_menu_override" );
  635. if ( GetClientModeTFNormal()->GameUI() )
  636. {
  637. GetClientModeTFNormal()->GameUI()->SetMainMenuOverride( GetVPanel() );
  638. }
  639. SetKeyBoardInputEnabled( true );
  640. SetMouseInputEnabled( true );
  641. SetCursor(dc_arrow);
  642. }
  643. //-----------------------------------------------------------------------------
  644. // Purpose:
  645. //-----------------------------------------------------------------------------
  646. ConVar tf_last_store_pricesheet_version( "tf_last_store_pricesheet_version", "0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE | FCVAR_DONTRECORD | FCVAR_HIDDEN );
  647. void CHudMainMenuOverride::FireGameEvent( IGameEvent *event )
  648. {
  649. const char * type = event->GetName();
  650. if ( FStrEq( type, "gameui_activated" ) )
  651. {
  652. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "MMenu_PlayList_Collapse_Immediate", false );
  653. m_bPlayListExpanded = false;
  654. return;
  655. }
  656. if ( Q_strcmp( type, "gc_connected" ) == 0 )
  657. {
  658. char uilanguage[ 64 ];
  659. uilanguage[0] = 0;
  660. engine->GetUILanguage( uilanguage, sizeof( uilanguage ) );
  661. //V_strcpy_safe( uilanguage, "german" );
  662. ELanguage nCurLang = PchLanguageToELanguage( uilanguage );
  663. // If we've changed language from when we last requested, we ask for all MOTDs again.
  664. if ( nCurLang != m_nLastMOTDRequestLanguage )
  665. {
  666. m_nLastMOTDRequestAt = 0;
  667. m_nLastMOTDRequestLanguage = nCurLang;
  668. m_bReloadedAllMOTDs = true;
  669. }
  670. // Ask the GC for the MOTD
  671. GCSDK::CGCMsg<MsgGCMOTDRequest_t> msg( k_EMsgGCMOTDRequest );
  672. msg.Body().m_eLanguage = nCurLang;
  673. msg.Body().m_nLastMOTDRequest = m_nLastMOTDRequestAt;
  674. GCClientSystem()->BSendMessage( msg );
  675. // Roll our last asked time forward here. It won't get written to our
  676. // cache file if we don't get a response from the GC.
  677. CRTime cTimeHack;
  678. m_nLastMOTDRequestAt = CRTime::RTime32TimeCur();
  679. // Load the store info, so we can display the current special
  680. CStorePanel::RequestPricesheet();
  681. CheckForNewQuests();
  682. UpdatePlaylistEntries();
  683. }
  684. else if ( Q_strcmp( type, "item_schema_initialized" ) == 0 )
  685. {
  686. // Tell the schema to load its MOTD block from our clientside cache file
  687. CUtlVector< CUtlString > vecErrors;
  688. KeyValues *pEntriesKV = new KeyValues( "motd_entries");
  689. if ( pEntriesKV->LoadFromFile( g_pFullFileSystem, GC_MOTD_CACHE_FILE ) )
  690. {
  691. // Extract our last MOTD request time
  692. const char *pszTime = pEntriesKV->GetString( "last_request_time", NULL );
  693. m_nLastMOTDRequestAt = ( pszTime && pszTime[0] ) ? CRTime::RTime32FromString(pszTime) : 0;
  694. const char *pszLang = pEntriesKV->GetString( "last_request_language", NULL );
  695. m_nLastMOTDRequestLanguage = ( pszLang && pszLang[0] ) ? PchLanguageToELanguage(pszLang) : k_Lang_English;
  696. // Parse the entries
  697. GetMOTDManager().BInitMOTDEntries( pEntriesKV, &vecErrors );
  698. GetMOTDManager().PurgeUnusedMOTDEntries( pEntriesKV );
  699. }
  700. }
  701. else if ( Q_strcmp( type, "store_pricesheet_updated" ) == 0 )
  702. {
  703. // If the contents of the store have changed since the last time we went in and/or launched
  704. // the game, change the button color so that players know there's new content available.
  705. if ( EconUI() &&
  706. EconUI()->GetStorePanel() &&
  707. EconUI()->GetStorePanel()->GetPriceSheet() )
  708. {
  709. const CEconStorePriceSheet *pPriceSheet = EconUI()->GetStorePanel()->GetPriceSheet();
  710. // The cvar system can't deal with integers that lose data when represented as floating point
  711. // numbers. We don't really care about supreme accuracy for detecting changes -- worst case if
  712. // we change the price sheet almost exactly 18 hours apart, some subset of players won't get the
  713. // "new!" label and that's fine.
  714. const uint32 unPriceSheetVersion = (uint32)pPriceSheet->GetVersionStamp() & 0xffff;
  715. if ( unPriceSheetVersion != (uint32)tf_last_store_pricesheet_version.GetInt() )
  716. {
  717. tf_last_store_pricesheet_version.SetValue( (int)unPriceSheetVersion );
  718. if ( m_pStoreHasNewItemsImage )
  719. {
  720. m_pStoreHasNewItemsImage->SetVisible( true );
  721. }
  722. }
  723. }
  724. // might as well do this here too
  725. UpdatePromotionalCodes();
  726. LoadCharacterImageFile();
  727. if ( NeedsToChooseMostHelpfulFriend() )
  728. {
  729. NotifyNeedsToChooseMostHelpfulFriend();
  730. }
  731. }
  732. else if ( FStrEq( "inventory_updated", type ) )
  733. {
  734. CheckForNewQuests();
  735. }
  736. else if ( FStrEq( "party_updated", type ) )
  737. {
  738. UpdatePlaylistEntries();
  739. }
  740. }
  741. //-----------------------------------------------------------------------------
  742. // Purpose:
  743. //-----------------------------------------------------------------------------
  744. void CHudMainMenuOverride::ApplySettings( KeyValues *inResourceData )
  745. {
  746. BaseClass::ApplySettings( inResourceData );
  747. KeyValues *pItemKV = inResourceData->FindKey( "button_kv" );
  748. if ( pItemKV )
  749. {
  750. if ( m_pButtonKV )
  751. {
  752. m_pButtonKV->deleteThis();
  753. }
  754. m_pButtonKV = new KeyValues("button_kv");
  755. pItemKV->CopySubkeys( m_pButtonKV );
  756. m_bReapplyButtonKVs = true;
  757. }
  758. #ifdef SAXXYMAINMENU_ENABLED
  759. KeyValues *pSaxxySettings = inResourceData->FindKey( "SaxxySettings" );
  760. if ( pSaxxySettings )
  761. {
  762. if ( m_pSaxxySettings )
  763. {
  764. m_pSaxxySettings->deleteThis();
  765. }
  766. m_pSaxxySettings = pSaxxySettings->MakeCopy();
  767. if ( m_pSaxxyAwardsPanel )
  768. {
  769. m_pSaxxyAwardsPanel->ApplySettings( m_pSaxxySettings );
  770. }
  771. }
  772. #endif
  773. m_bPlayListExpanded = false;
  774. UpdatePlaylistEntries();
  775. }
  776. //-----------------------------------------------------------------------------
  777. // Purpose:
  778. //-----------------------------------------------------------------------------
  779. void CHudMainMenuOverride::ApplySchemeSettings( IScheme *scheme )
  780. {
  781. // We need to re-hook ourselves up to the TF client scheme, because the GameUI will try to change us their its scheme
  782. vgui::HScheme pScheme = vgui::scheme()->LoadSchemeFromFileEx( enginevgui->GetPanel( PANEL_CLIENTDLL ), "resource/ClientScheme.res", "ClientScheme");
  783. SetScheme(pScheme);
  784. SetProportional( true );
  785. m_pFeaturedItemMouseOverPanel->InvalidateLayout( true, true );
  786. m_bBackgroundUsesCharacterImages = true;
  787. bool bHolidayActive = false;
  788. KeyValues *pConditions = NULL;
  789. const char *pszHoliday = UTIL_GetActiveHolidayString();
  790. if ( pszHoliday && pszHoliday[0] )
  791. {
  792. pConditions = new KeyValues( "conditions" );
  793. char szCondition[64];
  794. Q_snprintf( szCondition, sizeof( szCondition ), "if_%s", pszHoliday );
  795. AddSubKeyNamed( pConditions, szCondition );
  796. if ( FStrEq( pszHoliday, "halloween" ) )
  797. {
  798. // for Halloween we also want to pick a random background
  799. int nBackground = RandomInt( 0, 4 );
  800. AddSubKeyNamed( pConditions, CFmtStr( "if_halloween_%d", nBackground ) );
  801. if ( ( nBackground == 3 ) || ( nBackground == 4 ) )
  802. {
  803. m_bBackgroundUsesCharacterImages = false;
  804. }
  805. }
  806. bHolidayActive = true;
  807. }
  808. if ( !bHolidayActive )
  809. {
  810. FOR_EACH_MAP_FAST( GetItemSchema()->GetOperationDefinitions(), iOperation )
  811. {
  812. CEconOperationDefinition *pOperation = GetItemSchema()->GetOperationDefinitions()[iOperation];
  813. if ( !pOperation || !pOperation->IsActive() || !pOperation->IsCampaign() )
  814. continue;
  815. if ( !pConditions )
  816. pConditions = new KeyValues( "conditions" );
  817. AddSubKeyNamed( pConditions, "if_operation" );
  818. break;
  819. }
  820. }
  821. if ( !pConditions )
  822. {
  823. pConditions = new KeyValues( "conditions" );
  824. }
  825. // Put in ratio condition
  826. float aspectRatio = engine->GetScreenAspectRatio();
  827. AddSubKeyNamed( pConditions, aspectRatio >= 1.6 ? "if_wider" : "if_taller" );
  828. RemoveAllMenuEntries();
  829. LoadControlSettings( "resource/UI/MainMenuOverride.res", NULL, NULL, pConditions );
  830. BaseClass::ApplySchemeSettings( vgui::scheme()->GetIScheme(pScheme) );
  831. if ( pConditions )
  832. {
  833. pConditions->deleteThis();
  834. }
  835. m_pQuitButton = dynamic_cast<CExButton*>( FindChildByName("QuitButton") );
  836. m_pDisconnectButton = dynamic_cast<CExButton*>( FindChildByName("DisconnectButton") );
  837. m_pBackToReplaysButton = dynamic_cast<CExButton*>( FindChildByName("BackToReplaysButton") );
  838. m_pStoreHasNewItemsImage = dynamic_cast<ImagePanel*>( FindChildByName( "StoreHasNewItemsImage", true ) );
  839. {
  840. Panel *pButton = FindChildByName( "VRModeButton" );
  841. if( pButton )
  842. {
  843. m_pVRModeButton = dynamic_cast< CExButton *>( pButton->GetChild( 0 ) );
  844. }
  845. }
  846. m_pVRModeBackground = FindChildByName( "VRBGPanel" );
  847. bool bShowVR = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter();
  848. if ( m_pVRModeBackground )
  849. {
  850. m_pVRModeBackground->SetVisible( bShowVR );
  851. }
  852. m_bIsDisconnectText = true;
  853. // Tell all the MOTD buttons that we want their messages
  854. m_pMOTDPrevButton = dynamic_cast<CExImageButton*>( m_pMOTDPanel->FindChildByName("MOTD_PrevButton") );
  855. m_pMOTDNextButton = dynamic_cast<CExImageButton*>( m_pMOTDPanel->FindChildByName("MOTD_NextButton") );
  856. m_pMOTDURLButton = dynamic_cast<CExButton*>( m_pMOTDPanel->FindChildByName("MOTD_URLButton") );
  857. // m_pNotificationsShowPanel shows number of unread notifications. Pressing it pops up the first notification.
  858. m_pNotificationsShowPanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName("Notifications_ShowButtonPanel") );
  859. m_iNotiPanelWide = m_pNotificationsPanel->GetWide();
  860. // m_pMOTDShowPanel shows that the player has an unread MOTD. Pressing it pops up the MOTD.
  861. m_pMOTDShowPanel = dynamic_cast<vgui::EditablePanel*>( FindChildByName("MOTD_ShowButtonPanel") );
  862. vgui::EditablePanel* pHeaderContainer = dynamic_cast<vgui::EditablePanel*>( m_pMOTDPanel->FindChildByName( "MOTD_HeaderContainer" ) );
  863. if ( pHeaderContainer )
  864. {
  865. m_pMOTDHeaderLabel = dynamic_cast<vgui::Label*>( pHeaderContainer->FindChildByName( "MOTD_HeaderLabel" ) );
  866. }
  867. m_pMOTDHeaderIcon = dynamic_cast<vgui::ImagePanel*>( m_pMOTDPanel->FindChildByName("MOTD_HeaderIcon") );
  868. m_pMOTDTitleLabel = dynamic_cast<vgui::Label*>( m_pMOTDPanel->FindChildByName("MOTD_TitleLabel") );
  869. if ( m_pMOTDTitleLabel )
  870. {
  871. m_hTitleLabelFont = m_pMOTDTitleLabel->GetFont();
  872. }
  873. m_pMOTDTextLabel = dynamic_cast<vgui::Label*>( m_pMOTDTextPanel->FindChildByName( "MOTD_TextLabel" ) );
  874. m_pMOTDTitleImageContainer = dynamic_cast<vgui::EditablePanel*>( m_pMOTDPanel->FindChildByName("MOTD_TitleImageContainer") );
  875. if ( m_pMOTDTitleImageContainer )
  876. {
  877. m_pMOTDTitleImage = dynamic_cast<vgui::ImagePanel*>( m_pMOTDTitleImageContainer->FindChildByName("MOTD_TitleImage") );
  878. }
  879. m_pNotificationsScroller->GetScrollbar()->SetAutohideButtons( true );
  880. m_pNotificationsScroller->GetScrollbar()->SetPaintBorderEnabled( false );
  881. m_pNotificationsScroller->GetScrollbar()->SetPaintBackgroundEnabled( false );
  882. m_pNotificationsScroller->GetScrollbar()->GetButton(0)->SetPaintBorderEnabled( false );
  883. m_pNotificationsScroller->GetScrollbar()->GetButton(0)->SetPaintBackgroundEnabled( false );
  884. m_pNotificationsScroller->GetScrollbar()->GetButton(1)->SetPaintBorderEnabled( false );
  885. m_pNotificationsScroller->GetScrollbar()->GetButton(1)->SetPaintBackgroundEnabled( false );
  886. // Add tooltips for various buttons
  887. CExImageButton *pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("CommentaryButton") );
  888. if ( pImageButton )
  889. {
  890. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_Commentary" );
  891. }
  892. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("CoachPlayersButton") );
  893. if ( pImageButton )
  894. {
  895. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_Coach" );
  896. }
  897. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("ReportBugButton") );
  898. if ( pImageButton )
  899. {
  900. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_ReportBug" );
  901. }
  902. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("AchievementsButton") );
  903. if ( pImageButton )
  904. {
  905. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_Achievements" );
  906. }
  907. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("NewUserForumsButton") );
  908. if ( pImageButton )
  909. {
  910. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_NewUserForum" );
  911. }
  912. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("ReplayButton") );
  913. if ( pImageButton )
  914. {
  915. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_Replay" );
  916. }
  917. pImageButton = dynamic_cast<CExImageButton *>( FindChildByName("WorkshopButton") );
  918. if ( pImageButton )
  919. {
  920. pImageButton->SetTooltip( m_pToolTip, "#MMenu_Tooltip_Workshop" );
  921. }
  922. // Highlights
  923. m_pHighlightAnims[ MMHA_TUTORIAL ] = FindControl< CExplanationPopup >( "TutorialHighlight" );
  924. m_pHighlightAnims[ MMHA_PRACTICE ] = FindControl< CExplanationPopup >( "PracticeHighlight" );
  925. m_pHighlightAnims[ MMHA_NEWUSERFORUM ] = FindControl< CExplanationPopup >( "NewUserForumHighlight" );
  926. m_pHighlightAnims[ MMHA_OPTIONS ] = FindControl< CExplanationPopup >( "OptionsHighlightPanel" );
  927. m_pHighlightAnims[ MMHA_LOADOUT ] = FindControl< CExplanationPopup >( "LoadoutHighlightPanel" );
  928. m_pHighlightAnims[ MMHA_STORE ] = FindControl< CExplanationPopup >( "StoreHighlightPanel" );
  929. m_pHighlightAnims[ MMHA_WAR ] = FindControl< CExplanationPopup >( "WarHighlightPanel" );
  930. m_pCompetitiveAccessInfo = dynamic_cast<vgui::EditablePanel*>( FindChildByName("CompetitiveAccessInfoPanel") );
  931. LoadCharacterImageFile();
  932. RemoveAllMenuEntries();
  933. LoadMenuEntries();
  934. UpdateNotifications();
  935. UpdatePromotionalCodes();
  936. ScheduleTrainingCheck( false );
  937. PerformKeyRebindings();
  938. CheckForNewQuests();
  939. // Asking for these will create them if they dont already exist.
  940. GetCasualLobbyPanel()->InvalidateLayout( false, true );
  941. GetCompLobbyPanel()->InvalidateLayout( false, true );
  942. GetMvMLobbyPanel()->InvalidateLayout( false, true );
  943. }
  944. //-----------------------------------------------------------------------------
  945. // Purpose:
  946. //-----------------------------------------------------------------------------
  947. void CHudMainMenuOverride::LoadCharacterImageFile( void )
  948. {
  949. if ( !m_bBackgroundUsesCharacterImages )
  950. return;
  951. m_pCharacterImagePanel = dynamic_cast<vgui::ImagePanel*>( FindChildByName( "TFCharacterImage" ) );
  952. if ( m_pCharacterImagePanel )
  953. {
  954. KeyValues *pCharacterFile = new KeyValues( "CharacterBackgrounds" );
  955. if ( pCharacterFile->LoadFromFile( g_pFullFileSystem, "scripts/CharacterBackgrounds.txt" ) )
  956. {
  957. CUtlVector<KeyValues *> vecUseableCharacters;
  958. const char* pszActiveWarName = NULL;
  959. const WarDefinitionMap_t& mapWars = GetItemSchema()->GetWarDefinitions();
  960. FOR_EACH_MAP_FAST( mapWars, i )
  961. {
  962. const CWarDefinition* pWarDef = mapWars[i];
  963. if ( pWarDef->IsActive() )
  964. {
  965. pszActiveWarName = pWarDef->GetDefName();
  966. break;
  967. }
  968. }
  969. // Count the number of possible characters.
  970. FOR_EACH_SUBKEY( pCharacterFile, pCharacter )
  971. {
  972. EHoliday eHoliday = (EHoliday)UTIL_GetHolidayForString( pCharacter->GetString( "holiday_restriction" ) );
  973. const char* pszAssociatedWar = pCharacter->GetString( "war_restriction" );
  974. int iWeight = 1;
  975. // If a War is active, that's all we want to show. If not, then bias towards holidays
  976. if ( pszActiveWarName != NULL )
  977. {
  978. if ( !FStrEq( pszAssociatedWar, pszActiveWarName ) )
  979. {
  980. iWeight = 0;
  981. }
  982. }
  983. else if ( eHoliday != kHoliday_None )
  984. {
  985. iWeight = UTIL_IsHolidayActive( eHoliday ) ? 6 : 0;
  986. }
  987. for ( int i = 0; i < iWeight; i++ )
  988. {
  989. vecUseableCharacters.AddToTail( pCharacter );
  990. }
  991. }
  992. // Pick a character at random.
  993. if ( m_iCharacterImageIdx < 0 && vecUseableCharacters.Count() > 0 )
  994. {
  995. m_iCharacterImageIdx = rand() % vecUseableCharacters.Count();
  996. }
  997. // Make sure we found a character we can use.
  998. if ( vecUseableCharacters.IsValidIndex( m_iCharacterImageIdx ) )
  999. {
  1000. KeyValues *pCharacter = vecUseableCharacters[m_iCharacterImageIdx];
  1001. if ( IsFreeTrialAccount( ) && m_pHighlightAnims[ MMHA_STORE ] && !m_bPlayListExpanded )
  1002. {
  1003. const char* text = pCharacter->GetString( "store_text" );
  1004. if ( text )
  1005. {
  1006. m_pHighlightAnims[ MMHA_STORE ]->SetDialogVariable( "highlighttext", g_pVGuiLocalize->Find( text ) );
  1007. StartHighlightAnimation( MMHA_STORE );
  1008. }
  1009. }
  1010. const char* image_name = pCharacter->GetString( "image" );
  1011. m_pCharacterImagePanel->SetImage( image_name );
  1012. }
  1013. }
  1014. pCharacterFile->deleteThis();
  1015. }
  1016. }
  1017. //-----------------------------------------------------------------------------
  1018. // Purpose:
  1019. //-----------------------------------------------------------------------------
  1020. void CHudMainMenuOverride::LoadMenuEntries( void )
  1021. {
  1022. KeyValues *datafile = new KeyValues("GameMenu");
  1023. datafile->UsesEscapeSequences( true ); // VGUI uses escape sequences
  1024. bool bLoaded = datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res", "custom_mod" );
  1025. if ( !bLoaded )
  1026. {
  1027. bLoaded = datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res", "vgui" );
  1028. if ( !bLoaded )
  1029. {
  1030. // only allow to load loose files when using insecure mode
  1031. if ( CommandLine()->FindParm( "-insecure" ) )
  1032. {
  1033. bLoaded = datafile->LoadFromFile( g_pFullFileSystem, "Resource/GameMenu.res" );
  1034. }
  1035. }
  1036. }
  1037. for (KeyValues *dat = datafile->GetFirstSubKey(); dat != NULL; dat = dat->GetNextKey())
  1038. {
  1039. const char *label = dat->GetString("label", "<unknown>");
  1040. const char *cmd = dat->GetString("command", NULL);
  1041. const char *name = dat->GetName();
  1042. int iStyle = dat->GetInt("style", 0 );
  1043. if ( !cmd || !cmd[0] )
  1044. {
  1045. int iIdx = m_pMMButtonEntries.AddToTail();
  1046. m_pMMButtonEntries[iIdx].pPanel = NULL;
  1047. m_pMMButtonEntries[iIdx].bOnlyInGame = dat->GetBool( "OnlyInGame" );
  1048. m_pMMButtonEntries[iIdx].bOnlyInReplay = dat->GetBool( "OnlyInReplay" );
  1049. m_pMMButtonEntries[iIdx].bOnlyAtMenu = dat->GetBool( "OnlyAtMenu" );
  1050. m_pMMButtonEntries[iIdx].bOnlyVREnabled = dat->GetBool( "OnlyWhenVREnabled" );
  1051. m_pMMButtonEntries[iIdx].iStyle = iStyle;
  1052. continue;
  1053. }
  1054. // Create the new editable panel (first, see if we have one already)
  1055. vgui::EditablePanel *pPanel = dynamic_cast<vgui::EditablePanel *>( FindChildByName( name, true ) );
  1056. if ( !pPanel )
  1057. {
  1058. Assert( false ); // We don't want to do this anymore. We need an actual hierarchy so things can slide
  1059. // around when the play buttin is pressed and the play options expand
  1060. pPanel = new vgui::EditablePanel( this, name );
  1061. }
  1062. else
  1063. {
  1064. // It already exists in our .res file. Note that it's a custom button.
  1065. iStyle = MMBS_CUSTOM;
  1066. }
  1067. if ( pPanel )
  1068. {
  1069. if ( m_pButtonKV && iStyle != MMBS_CUSTOM )
  1070. {
  1071. pPanel->ApplySettings( m_pButtonKV );
  1072. }
  1073. int iIdx = m_pMMButtonEntries.AddToTail();
  1074. m_pMMButtonEntries[iIdx].pPanel = pPanel;
  1075. m_pMMButtonEntries[iIdx].bOnlyInGame = dat->GetBool( "OnlyInGame" );
  1076. m_pMMButtonEntries[iIdx].bOnlyInReplay = dat->GetBool( "OnlyInReplay" );
  1077. m_pMMButtonEntries[iIdx].bOnlyAtMenu = dat->GetBool( "OnlyAtMenu" );
  1078. m_pMMButtonEntries[iIdx].bOnlyVREnabled = dat->GetBool( "OnlyWhenVREnabled" );
  1079. m_pMMButtonEntries[iIdx].iStyle = iStyle;
  1080. m_pMMButtonEntries[iIdx].pszImage = dat->GetString( "subimage" );
  1081. m_pMMButtonEntries[iIdx].pszTooltip = dat->GetString( "tooltip", NULL );
  1082. // Tell the button that we'd like messages from it
  1083. CExImageButton *pButton = dynamic_cast<CExImageButton*>( pPanel->FindChildByName("SubButton") );
  1084. if ( pButton )
  1085. {
  1086. if ( m_pMMButtonEntries[iIdx].pszTooltip )
  1087. {
  1088. pButton->SetTooltip( m_pToolTip, m_pMMButtonEntries[iIdx].pszTooltip );
  1089. }
  1090. pButton->SetText( label );
  1091. pButton->SetCommand( cmd );
  1092. pButton->SetMouseInputEnabled( true );
  1093. pButton->AddActionSignalTarget( GetVPanel() );
  1094. if ( m_pMMButtonEntries[iIdx].pszImage && m_pMMButtonEntries[iIdx].pszImage[0] )
  1095. {
  1096. pButton->SetSubImage( m_pMMButtonEntries[iIdx].pszImage );
  1097. }
  1098. }
  1099. }
  1100. OnUpdateMenu();
  1101. }
  1102. }
  1103. //-----------------------------------------------------------------------------
  1104. // Purpose:
  1105. //-----------------------------------------------------------------------------
  1106. void CHudMainMenuOverride::RemoveAllMenuEntries( void )
  1107. {
  1108. FOR_EACH_VEC_BACK( m_pMMButtonEntries, i )
  1109. {
  1110. if ( m_pMMButtonEntries[i].pPanel )
  1111. {
  1112. // Manually remove anything that's not going to be removed automatically
  1113. if ( m_pMMButtonEntries[i].pPanel->IsBuildModeDeletable() == false )
  1114. {
  1115. m_pMMButtonEntries[i].pPanel->MarkForDeletion();
  1116. }
  1117. }
  1118. }
  1119. m_pMMButtonEntries.Purge();
  1120. }
  1121. //-----------------------------------------------------------------------------
  1122. // Purpose:
  1123. //-----------------------------------------------------------------------------
  1124. void CHudMainMenuOverride::PerformLayout( void )
  1125. {
  1126. BaseClass::PerformLayout();
  1127. bool bFirstButton = true;
  1128. int iYPos = m_iButtonY;
  1129. FOR_EACH_VEC( m_pMMButtonEntries, i )
  1130. {
  1131. bool bIsVisible = (m_pMMButtonEntries[i].pPanel ? m_pMMButtonEntries[i].pPanel->IsVisible() : m_pMMButtonEntries[i].bIsVisible);
  1132. if ( !bIsVisible )
  1133. continue;
  1134. if ( bFirstButton && m_pMMButtonEntries[i].pPanel != NULL )
  1135. {
  1136. m_pMMButtonEntries[i].pPanel->NavigateTo();
  1137. bFirstButton = false;
  1138. }
  1139. // Don't reposition it if it's a custom button
  1140. if ( m_pMMButtonEntries[i].iStyle == MMBS_CUSTOM )
  1141. continue;
  1142. // If we're a spacer, just leave a blank and move on
  1143. if ( m_pMMButtonEntries[i].pPanel == NULL )
  1144. {
  1145. iYPos += YRES(20);
  1146. continue;
  1147. }
  1148. m_pMMButtonEntries[i].pPanel->SetPos( (GetWide() * 0.5) + m_iButtonXOffset, iYPos );
  1149. iYPos += m_pMMButtonEntries[i].pPanel->GetTall() + m_iButtonYDelta;
  1150. }
  1151. if ( m_pFeaturedItemMouseOverPanel->IsVisible() )
  1152. {
  1153. m_pFeaturedItemMouseOverPanel->SetVisible( false );
  1154. }
  1155. if ( m_pEventPromoContainer && m_pSafeModeContainer )
  1156. {
  1157. m_pEventPromoContainer->SetVisible( !cl_mainmenu_safemode.GetBool() );
  1158. m_pSafeModeContainer->SetVisible( cl_mainmenu_safemode.GetBool() );
  1159. if ( cl_mainmenu_safemode.GetBool() )
  1160. {
  1161. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pSafeModeContainer, "MMenu_SafeMode_Blink" );
  1162. }
  1163. else
  1164. {
  1165. g_pClientMode->GetViewportAnimationController()->CancelAnimationsForPanel( m_pSafeModeContainer );
  1166. }
  1167. }
  1168. // Make the glows behind the update buttons pulse
  1169. if ( m_pEventPromoContainer && cl_mainmenu_updateglow.GetInt() )
  1170. {
  1171. EditablePanel* pUpdateBackground = m_pEventPromoContainer->FindControl< EditablePanel >( "Background", true );
  1172. if ( pUpdateBackground )
  1173. {
  1174. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( pUpdateBackground, "MMenu_UpdateButton_StartGlow" );
  1175. }
  1176. }
  1177. }
  1178. //-----------------------------------------------------------------------------
  1179. // Purpose:
  1180. //-----------------------------------------------------------------------------
  1181. void CHudMainMenuOverride::OnUpdateMenu( void )
  1182. {
  1183. // The dumb gameui.dll basepanel calls this every damn frame it's visible.
  1184. // So try and do the least amount of work if nothing has changed.
  1185. bool bSomethingChanged = false;
  1186. bool bInGame = engine->IsInGame();
  1187. #if defined( REPLAY_ENABLED )
  1188. bool bInReplay = g_pEngineClientReplay->IsPlayingReplayDemo();
  1189. #else
  1190. bool bInReplay = false;
  1191. #endif
  1192. bool bIsVREnabled = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter();
  1193. // First, reapply any KVs we have to reapply
  1194. if ( m_bReapplyButtonKVs )
  1195. {
  1196. m_bReapplyButtonKVs = false;
  1197. if ( m_pButtonKV )
  1198. {
  1199. FOR_EACH_VEC( m_pMMButtonEntries, i )
  1200. {
  1201. if ( m_pMMButtonEntries[i].iStyle != MMBS_CUSTOM && m_pMMButtonEntries[i].pPanel )
  1202. {
  1203. m_pMMButtonEntries[i].pPanel->ApplySettings( m_pButtonKV );
  1204. }
  1205. }
  1206. }
  1207. }
  1208. // Hide the character if we're in game.
  1209. if ( bInGame || bInReplay )
  1210. {
  1211. if ( m_pCharacterImagePanel && m_pCharacterImagePanel->IsVisible() )
  1212. {
  1213. m_pCharacterImagePanel->SetVisible( false );
  1214. }
  1215. }
  1216. else if ( !bInGame && !bInReplay )
  1217. {
  1218. if ( m_pCharacterImagePanel && !m_pCharacterImagePanel->IsVisible() )
  1219. {
  1220. m_pCharacterImagePanel->SetVisible( true );
  1221. }
  1222. }
  1223. // Position the entries
  1224. FOR_EACH_VEC( m_pMMButtonEntries, i )
  1225. {
  1226. bool shouldBeVisible = true;
  1227. if ( m_pMMButtonEntries[i].bOnlyInGame && !bInGame )
  1228. {
  1229. shouldBeVisible = false;
  1230. }
  1231. else if ( m_pMMButtonEntries[i].bOnlyInReplay && !bInReplay )
  1232. {
  1233. shouldBeVisible = false;
  1234. }
  1235. else if ( m_pMMButtonEntries[i].bOnlyAtMenu && (bInGame || bInReplay) )
  1236. {
  1237. shouldBeVisible = false;
  1238. }
  1239. else if ( m_pMMButtonEntries[i].bOnlyVREnabled && ( !bIsVREnabled || ShouldForceVRActive() ) )
  1240. {
  1241. shouldBeVisible = false;
  1242. }
  1243. // Set the right visibility
  1244. bool bIsVisible = (m_pMMButtonEntries[i].pPanel ? m_pMMButtonEntries[i].pPanel->IsVisible() : m_pMMButtonEntries[i].bIsVisible);
  1245. if ( bIsVisible != shouldBeVisible )
  1246. {
  1247. m_pMMButtonEntries[i].bIsVisible = shouldBeVisible;
  1248. if ( m_pMMButtonEntries[i].pPanel )
  1249. {
  1250. m_pMMButtonEntries[i].pPanel->SetVisible( shouldBeVisible );
  1251. }
  1252. bSomethingChanged = true;
  1253. }
  1254. }
  1255. if ( m_pQuitButton && m_pDisconnectButton && m_pBackToReplaysButton )
  1256. {
  1257. bool bShowQuit = !( bInGame || bInReplay );
  1258. bool bShowDisconnect = bInGame && !bInReplay;
  1259. if ( m_pQuitButton->IsVisible() != bShowQuit )
  1260. {
  1261. m_pQuitButton->SetVisible( bShowQuit );
  1262. }
  1263. if ( m_pBackToReplaysButton->IsVisible() != bInReplay )
  1264. {
  1265. m_pBackToReplaysButton->SetVisible( bInReplay );
  1266. }
  1267. if ( m_pDisconnectButton->IsVisible() != bShowDisconnect )
  1268. {
  1269. m_pDisconnectButton->SetVisible( bShowDisconnect );
  1270. }
  1271. if ( bShowDisconnect )
  1272. {
  1273. bool bIsDisconnectText = GTFGCClientSystem()->GetCurrentServerAbandonStatus() != k_EAbandonGameStatus_AbandonWithPenalty;
  1274. if ( m_bIsDisconnectText != bIsDisconnectText )
  1275. {
  1276. m_bIsDisconnectText = bIsDisconnectText;
  1277. m_pDisconnectButton->SetText( m_bIsDisconnectText ? "#GameUI_GameMenu_Disconnect" : "#TF_MM_Rejoin_Abandon" );
  1278. }
  1279. }
  1280. }
  1281. if ( m_pBackground )
  1282. {
  1283. if ( cl_mainmenu_operation_motd_reset.GetBool() && cl_mainmenu_operation_motd_start.GetBool() )
  1284. {
  1285. cl_mainmenu_operation_motd_start.SetValue( 0 );
  1286. cl_mainmenu_operation_motd_reset.SetValue( 0 );
  1287. }
  1288. if ( !cl_mainmenu_operation_motd_start.GetInt() )
  1289. {
  1290. char sztime[k_RTimeRenderBufferSize];
  1291. CRTime::RTime32ToString( CRTime::RTime32TimeCur(), sztime );
  1292. cl_mainmenu_operation_motd_start.SetValue( sztime );
  1293. }
  1294. bool bShouldBeVisible = bInGame == false;
  1295. if ( m_pBackground->IsVisible() != bShouldBeVisible )
  1296. {
  1297. m_pBackground->SetVisible( bShouldBeVisible );
  1298. // Always show this on startup when we have a new campaign
  1299. if ( m_bStabilizedInitialLayout && bShouldBeVisible && ( m_bHaveNewMOTDs || !m_bMOTDShownAtStartup ) )
  1300. {
  1301. RTime32 rtFirstLaunchTime = CRTime::RTime32FromString( cl_mainmenu_operation_motd_start.GetString() );
  1302. RTime32 rtThreeDaysFromStart = CRTime::RTime32DateAdd( rtFirstLaunchTime, 7, k_ETimeUnitDay );
  1303. if ( m_bHaveNewMOTDs || CRTime::RTime32TimeCur() < rtThreeDaysFromStart )
  1304. {
  1305. SetMOTDVisible( true );
  1306. m_bMOTDShownAtStartup = true;
  1307. }
  1308. }
  1309. }
  1310. }
  1311. if ( bSomethingChanged )
  1312. {
  1313. InvalidateLayout();
  1314. ScheduleItemCheck();
  1315. }
  1316. if ( !bInGame && m_flCheckTrainingAt && m_flCheckTrainingAt < engine->Time() )
  1317. {
  1318. m_flCheckTrainingAt = 0;
  1319. CheckTrainingStatus();
  1320. }
  1321. if ( !bInGame && m_flCheckUnclaimedItems && m_flCheckUnclaimedItems < engine->Time() )
  1322. {
  1323. m_flCheckUnclaimedItems = 0;
  1324. CheckUnclaimedItems();
  1325. }
  1326. #ifdef SAXXYMAINMENU_ENABLED
  1327. const bool bSaxxyShouldBeVisible = !bInGame && !bInReplay;
  1328. if ( !m_pSaxxyAwardsPanel && bSaxxyShouldBeVisible )
  1329. {
  1330. m_pSaxxyAwardsPanel = new CSaxxyAwardsPanel( this, "SaxxyPanel" );
  1331. if ( m_pSaxxySettings )
  1332. {
  1333. m_pSaxxyAwardsPanel->ApplySettings( m_pSaxxySettings );
  1334. }
  1335. m_pSaxxyAwardsPanel->InvalidateLayout( true, true );
  1336. }
  1337. else if ( m_pSaxxyAwardsPanel && !bSaxxyShouldBeVisible )
  1338. {
  1339. m_pSaxxyAwardsPanel->MarkForDeletion();
  1340. m_pSaxxyAwardsPanel = NULL;
  1341. }
  1342. #endif
  1343. if ( m_pVRModeButton && m_pVRModeButton->IsVisible() )
  1344. {
  1345. if( UseVR() )
  1346. m_pVRModeButton->SetText( "#MMenu_VRMode_Deactivate" );
  1347. else
  1348. m_pVRModeButton->SetText( "#MMenu_VRMode_Activate" );
  1349. }
  1350. if ( !IsLayoutInvalid() )
  1351. {
  1352. m_bStabilizedInitialLayout = true;
  1353. }
  1354. }
  1355. //-----------------------------------------------------------------------------
  1356. // Purpose: Check to see if we need to hound the player about unclaimed items.
  1357. //-----------------------------------------------------------------------------
  1358. void CHudMainMenuOverride::CheckUnclaimedItems()
  1359. {
  1360. // Only do this if we don't have a notification about unclaimed items already.
  1361. for ( int i=0; i<NotificationQueue_GetNumNotifications(); i++ )
  1362. {
  1363. CEconNotification* pNotification = NotificationQueue_Get( i );
  1364. if ( pNotification )
  1365. {
  1366. if ( !Q_strcmp( pNotification->GetUnlocalizedText(), "TF_HasNewItems") )
  1367. {
  1368. return;
  1369. }
  1370. }
  1371. }
  1372. // Only provide a notification if there are items to pick up.
  1373. if ( TFInventoryManager()->GetNumItemPickedUpItems() == 0 )
  1374. return;
  1375. TFInventoryManager()->GetLocalTFInventory()->NotifyHasNewItems();
  1376. }
  1377. //-----------------------------------------------------------------------------
  1378. // Purpose:
  1379. //-----------------------------------------------------------------------------
  1380. void CHudMainMenuOverride::OnConfirm( KeyValues *pParams )
  1381. {
  1382. if ( pParams->GetBool( "confirmed" ) )
  1383. {
  1384. engine->ClientCmd_Unrestricted( "disconnect" );
  1385. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine training_showdlg" );
  1386. }
  1387. }
  1388. //-----------------------------------------------------------------------------
  1389. // Purpose:
  1390. //-----------------------------------------------------------------------------
  1391. void CHudMainMenuOverride::UpdateMOTD( bool bNewMOTDs )
  1392. {
  1393. if ( m_bInitMOTD == false )
  1394. {
  1395. m_pMOTDPanel->InvalidateLayout( true, true );
  1396. m_bInitMOTD = true;
  1397. }
  1398. if ( bNewMOTDs )
  1399. {
  1400. m_bHaveNewMOTDs = true;
  1401. m_iCurrentMOTD = -1;
  1402. }
  1403. int iCount = GetMOTDManager().GetNumMOTDs();
  1404. if ( !iCount || m_iCurrentMOTD < 0 )
  1405. {
  1406. m_iCurrentMOTD = (iCount-1);
  1407. }
  1408. // If we don't have an MOTD selected, show the most recent one
  1409. CMOTDEntryDefinition *pMOTD = GetMOTDManager().GetMOTDByIndex( m_iCurrentMOTD );
  1410. if ( pMOTD )
  1411. {
  1412. char uilanguage[ 64 ];
  1413. uilanguage[0] = 0;
  1414. engine->GetUILanguage( uilanguage, sizeof( uilanguage ) );
  1415. ELanguage nCurLang = PchLanguageToELanguage( uilanguage );
  1416. RTime32 nTime = pMOTD->GetPostTime();
  1417. wchar_t wzDate[64];
  1418. char rgchDateBuf[ 128 ];
  1419. BGetLocalFormattedDate( nTime, rgchDateBuf, sizeof( rgchDateBuf ) );
  1420. // Start with the day ("Aug 21")
  1421. CRTime cTime( nTime );
  1422. g_pVGuiLocalize->ConvertANSIToUnicode( rgchDateBuf, wzDate, sizeof( wzDate ) );
  1423. m_pMOTDPanel->SetDialogVariable( "motddate", wzDate );
  1424. // Header Color and text
  1425. if ( m_pMOTDHeaderLabel )
  1426. {
  1427. m_pMOTDHeaderLabel->SetText( pMOTD->GetHeaderTitle(nCurLang) );
  1428. int iHeaderType = pMOTD->GetHeaderType();
  1429. switch ( iHeaderType )
  1430. {
  1431. case 0:
  1432. m_pMOTDHeaderLabel->SetBgColor( Color ( 183, 108, 58, 255 ) );
  1433. break;
  1434. case 1:
  1435. m_pMOTDHeaderLabel->SetBgColor( Color ( 141, 178, 61, 255 ) );
  1436. break;
  1437. default:
  1438. m_pMOTDHeaderLabel->SetBgColor( Color ( 183, 108, 58, 255 ) );
  1439. break;
  1440. }
  1441. }
  1442. if ( m_pMOTDHeaderIcon )
  1443. {
  1444. // Header Class icon
  1445. if ( pMOTD->GetHeaderIcon() == NULL || Q_strcmp( pMOTD->GetHeaderIcon(), "" ) == 0)
  1446. {
  1447. m_pMOTDHeaderIcon->SetVisible(false);
  1448. }
  1449. else
  1450. {
  1451. m_pMOTDHeaderIcon->SetVisible(true);
  1452. m_pMOTDHeaderIcon->SetImage( pMOTD->GetHeaderIcon() );
  1453. }
  1454. }
  1455. // Set the Title and change font until it fits
  1456. // title
  1457. int iTitleWide = 0;
  1458. int iTitleTall = 0;
  1459. int iLabelWide = 0;
  1460. int iLabelTall = 0;
  1461. wchar_t wszText[512];
  1462. g_pVGuiLocalize->ConvertANSIToUnicode( pMOTD->GetTitle(nCurLang), wszText, sizeof( wszText ) );
  1463. if ( m_hTitleLabelFont != vgui::INVALID_FONT )
  1464. {
  1465. surface()->GetTextSize( m_hTitleLabelFont, wszText, iTitleWide, iTitleTall );
  1466. }
  1467. if ( m_pMOTDTitleLabel )
  1468. {
  1469. m_pMOTDTitleLabel->GetSize( iLabelWide, iLabelTall );
  1470. if ( iTitleWide > iLabelWide )
  1471. {
  1472. IScheme *pScheme = scheme()->GetIScheme( m_pMOTDTitleLabel->GetScheme() );
  1473. int hMediumBoldFont = pScheme->GetFont( "HudFontMediumBold" );
  1474. surface()->GetTextSize( hMediumBoldFont, wszText, iTitleWide, iTitleTall );
  1475. if ( iTitleWide > iLabelWide )
  1476. {
  1477. m_pMOTDTitleLabel->SetFont( pScheme->GetFont( "HudFontMediumSmallBold" ) );
  1478. }
  1479. else
  1480. {
  1481. m_pMOTDTitleLabel->SetFont( hMediumBoldFont );
  1482. }
  1483. }
  1484. else
  1485. {
  1486. if ( m_hTitleLabelFont != vgui::INVALID_FONT )
  1487. {
  1488. m_pMOTDTitleLabel->SetFont( m_hTitleLabelFont );
  1489. }
  1490. }
  1491. }
  1492. m_pMOTDPanel->SetDialogVariable( "motdtitle", pMOTD->GetTitle(nCurLang) );
  1493. // Body Text
  1494. m_pMOTDTextPanel->SetDialogVariable( "motdtext", pMOTD->GetText(nCurLang) );
  1495. // Image
  1496. const char* pszImage = pMOTD->GetImage();
  1497. if ( m_pMOTDTitleImage )
  1498. {
  1499. m_pMOTDTitleImage->SetShouldScaleImage( false );
  1500. if ( pszImage == NULL || Q_strcmp( pszImage, "" ) == 0 || Q_strcmp( pszImage, "class_icons/filter_all_on") == 0 )
  1501. {
  1502. m_pMOTDTitleImage->SetImage( "../logo/new_tf2_logo" );
  1503. }
  1504. else
  1505. {
  1506. m_pMOTDTitleImage->SetImage( pszImage );
  1507. }
  1508. IImage *pImage = m_pMOTDTitleImage->GetImage();
  1509. int iContentWide = 0;
  1510. int iContentTall = 0;
  1511. if ( m_pMOTDTitleImageContainer )
  1512. {
  1513. m_pMOTDTitleImageContainer->GetSize( iContentWide, iContentTall );
  1514. }
  1515. int iImgWide;
  1516. int iImgTall;
  1517. pImage->GetSize( iImgWide, iImgTall );
  1518. // get the size of the content
  1519. // perform a uniform scale along the horizontal
  1520. float fImageScale = MIN( (float)iContentWide / (float)iImgWide, 1.0f );
  1521. float fScaledTall = iImgTall * fImageScale;
  1522. float fScaledWide = iImgWide * fImageScale;
  1523. pImage->SetSize( fScaledWide, fScaledTall );
  1524. // reposition the image so that its centered
  1525. m_pMOTDTitleImage->SetPos( (iContentWide - fScaledWide) / 2, (iContentTall - fScaledTall) / 2 );
  1526. }
  1527. // We need to resize our text label to fit all the text
  1528. if ( m_pMOTDTextLabel )
  1529. {
  1530. m_pMOTDTextLabel->InvalidateLayout( true );
  1531. int wide, tall;
  1532. m_pMOTDTextLabel->GetContentSize(wide, tall);
  1533. m_pMOTDTextLabel->SetSize( m_pMOTDTextPanel->GetWide(), tall );
  1534. m_pMOTDTextPanel->SetSize( m_pMOTDTextPanel->GetWide(), m_pMOTDTextLabel->GetTall() );
  1535. }
  1536. if ( m_pMOTDURLButton )
  1537. {
  1538. const char *pszURL = pMOTD->GetURL();
  1539. m_pMOTDURLButton->SetVisible( (pszURL && pszURL[0]) );
  1540. }
  1541. if ( m_pMOTDPrevButton )
  1542. {
  1543. m_pMOTDPrevButton->SetEnabled( m_iCurrentMOTD > 0 );
  1544. m_pMOTDPrevButton->SetSubImage( m_iCurrentMOTD > 0 ? "blog_back" : "blog_back_disabled" );
  1545. }
  1546. if ( m_pMOTDNextButton )
  1547. {
  1548. m_pMOTDNextButton->SetEnabled( m_iCurrentMOTD < (iCount-1) );
  1549. m_pMOTDNextButton->SetSubImage( m_iCurrentMOTD < (iCount-1) ? "blog_forward" : "blog_forward_disabled" );
  1550. }
  1551. // Move our scrollbar to the top.
  1552. m_pMOTDTextScroller->InvalidateLayout();
  1553. m_pMOTDTextScroller->Repaint();
  1554. m_pMOTDTextScroller->GetScrollbar()->SetValue( 0 );
  1555. m_pMOTDTextScroller->GetScrollbar()->SetVisible( m_pMOTDTextPanel->GetTall() > m_pMOTDTextScroller->GetScrollbar()->GetTall() );
  1556. m_pMOTDTextScroller->GetScrollbar()->InvalidateLayout();
  1557. m_pMOTDTextScroller->GetScrollbar()->Repaint();
  1558. }
  1559. else
  1560. {
  1561. // Hide the MOTD, and the button to show it.
  1562. SetMOTDVisible( false );
  1563. if ( m_pMOTDShowPanel )
  1564. {
  1565. m_pMOTDShowPanel->SetVisible( false );
  1566. }
  1567. }
  1568. }
  1569. //-----------------------------------------------------------------------------
  1570. // Purpose:
  1571. //-----------------------------------------------------------------------------
  1572. void CHudMainMenuOverride::SetMOTDButtonVisible( bool bVisible )
  1573. {
  1574. if ( bVisible && m_pMOTDPanel && m_pMOTDPanel->IsVisible() )
  1575. return;
  1576. if ( m_pMOTDShowPanel )
  1577. {
  1578. // Show the notifications show panel button if we have new notifications.
  1579. m_pMOTDShowPanel->SetVisible( bVisible );
  1580. if ( bVisible && m_bHaveNewMOTDs )
  1581. {
  1582. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pMOTDShowPanel, "HasMOTDBlink" );
  1583. }
  1584. else
  1585. {
  1586. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pMOTDShowPanel, "HasMOTDBlinkStop" );
  1587. }
  1588. }
  1589. }
  1590. //-----------------------------------------------------------------------------
  1591. // Purpose:
  1592. //-----------------------------------------------------------------------------
  1593. void CHudMainMenuOverride::SetMOTDVisible( bool bVisible )
  1594. {
  1595. m_pMOTDPanel->SetVisible( bVisible );
  1596. if ( bVisible )
  1597. {
  1598. // Ensure the text is correct.
  1599. UpdateMOTD( false );
  1600. // Clear MOTD button.
  1601. SetMOTDButtonVisible( true );
  1602. SetNotificationsPanelVisible( false );
  1603. SetQuestLogVisible( false );
  1604. SetWatchStreamVisible( false );
  1605. //SetNotificationsButtonVisible( false );
  1606. // Consider new MOTDs as having been viewed.
  1607. m_bHaveNewMOTDs = false;
  1608. }
  1609. else
  1610. {
  1611. SetMOTDButtonVisible( true );
  1612. UpdateNotifications();
  1613. }
  1614. }
  1615. //-----------------------------------------------------------------------------
  1616. // Purpose:
  1617. //-----------------------------------------------------------------------------
  1618. void CHudMainMenuOverride::SetQuestLogVisible( bool bVisible )
  1619. {
  1620. GetQuestLog()->ShowPanel( bVisible );
  1621. if ( bVisible )
  1622. {
  1623. SetMOTDVisible( false );
  1624. SetNotificationsPanelVisible( false );
  1625. SetWatchStreamVisible( false );
  1626. }
  1627. }
  1628. //-----------------------------------------------------------------------------
  1629. // Purpose:
  1630. //-----------------------------------------------------------------------------
  1631. void CHudMainMenuOverride::SetWatchStreamVisible( bool bVisible )
  1632. {
  1633. m_pWatchStreamsPanel->SetVisible( bVisible );
  1634. if ( bVisible )
  1635. {
  1636. SetMOTDVisible( false );
  1637. SetNotificationsPanelVisible( false );
  1638. SetQuestLogVisible( false );
  1639. }
  1640. }
  1641. bool CHudMainMenuOverride::CheckAndWarnForPREC( void )
  1642. {
  1643. enum check_state
  1644. {
  1645. INVALID,
  1646. FOUND,
  1647. NOT_FOUND,
  1648. };
  1649. static check_state s_state = INVALID;
  1650. if ( s_state == INVALID )
  1651. {
  1652. s_state = NOT_FOUND;
  1653. ICvar::Iterator iter( g_pCVar );
  1654. for ( iter.SetFirst() ; iter.IsValid() ; iter.Next() )
  1655. {
  1656. ConCommandBase *cmd = iter.Get();
  1657. if ( cmd )
  1658. {
  1659. if ( !Q_strncmp( cmd->GetName(), "prec_", 5 ) )
  1660. {
  1661. s_state = FOUND;
  1662. break;
  1663. }
  1664. }
  1665. }
  1666. }
  1667. if ( s_state == FOUND )
  1668. {
  1669. ShowMessageBox( "#TF_Incompatible_AddOn", "#TF_PREC_Loaded" );
  1670. }
  1671. return ( s_state == FOUND );
  1672. }
  1673. void CHudMainMenuOverride::OpenMvMMMPanel()
  1674. {
  1675. if ( CheckAndWarnForPREC() )
  1676. return;
  1677. GetMvMLobbyPanel()->ShowPanel( true );
  1678. }
  1679. void CHudMainMenuOverride::OpenCompMMPanel()
  1680. {
  1681. if ( CheckAndWarnForPREC() )
  1682. return;
  1683. GetCompLobbyPanel()->ShowPanel( true );
  1684. }
  1685. void CHudMainMenuOverride::OpenCasualMMPanel()
  1686. {
  1687. if ( CheckAndWarnForPREC() )
  1688. return;
  1689. GetCasualLobbyPanel()->ShowPanel( true );
  1690. }
  1691. CLobbyContainerFrame_Comp* CHudMainMenuOverride::GetCompLobbyPanel()
  1692. {
  1693. static CLobbyContainerFrame_Comp* pCompPanel = NULL;
  1694. if ( pCompPanel == NULL )
  1695. {
  1696. pCompPanel = SETUP_PANEL( new CLobbyContainerFrame_Comp() );
  1697. }
  1698. return pCompPanel;
  1699. }
  1700. CLobbyContainerFrame_MvM* CHudMainMenuOverride::GetMvMLobbyPanel()
  1701. {
  1702. static CLobbyContainerFrame_MvM* pMvMPanel = NULL;
  1703. if ( pMvMPanel == NULL )
  1704. {
  1705. pMvMPanel = SETUP_PANEL( new CLobbyContainerFrame_MvM() );
  1706. }
  1707. return pMvMPanel;
  1708. }
  1709. CLobbyContainerFrame_Casual* CHudMainMenuOverride::GetCasualLobbyPanel()
  1710. {
  1711. static CLobbyContainerFrame_Casual* pCasualPanel = NULL;
  1712. if ( pCasualPanel == NULL )
  1713. {
  1714. pCasualPanel = SETUP_PANEL( new CLobbyContainerFrame_Casual() );
  1715. }
  1716. return pCasualPanel;
  1717. }
  1718. void CHudMainMenuOverride::ReloadMMPanels()
  1719. {
  1720. if ( GetCasualLobbyPanel()->IsVisible() )
  1721. {
  1722. GetCasualLobbyPanel()->InvalidateLayout( true, true );
  1723. GetCasualLobbyPanel()->ShowPanel( true );
  1724. }
  1725. if ( GetCompLobbyPanel()->IsVisible() )
  1726. {
  1727. GetCompLobbyPanel()->InvalidateLayout( true, true );
  1728. GetCompLobbyPanel()->ShowPanel( true );
  1729. }
  1730. if ( GetMvMLobbyPanel()->IsVisible() )
  1731. {
  1732. GetMvMLobbyPanel()->InvalidateLayout( true, true );
  1733. GetMvMLobbyPanel()->ShowPanel( true );
  1734. }
  1735. }
  1736. //-----------------------------------------------------------------------------
  1737. // Purpose:
  1738. //-----------------------------------------------------------------------------
  1739. void CHudMainMenuOverride::UpdateNotifications()
  1740. {
  1741. int iNumNotifications = NotificationQueue_GetNumNotifications();
  1742. wchar_t wszNumber[16]=L"";
  1743. V_swprintf_safe( wszNumber, L"%i", iNumNotifications );
  1744. wchar_t wszText[1024]=L"";
  1745. g_pVGuiLocalize->ConstructString_safe( wszText, g_pVGuiLocalize->Find( "#MMenu_Notifications_Show" ), 1, wszNumber );
  1746. m_pNotificationsPanel->SetDialogVariable( "notititle", wszText );
  1747. bool bHasNotifications = iNumNotifications != 0;
  1748. if ( m_pNotificationsShowPanel )
  1749. {
  1750. SetNotificationsButtonVisible( bHasNotifications );
  1751. bool bBlinkNotifications = bHasNotifications && m_pNotificationsShowPanel->IsVisible();
  1752. if ( bBlinkNotifications )
  1753. {
  1754. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pNotificationsShowPanel, "HasNotificationsBlink" );
  1755. }
  1756. else
  1757. {
  1758. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( m_pNotificationsShowPanel, "HasNotificationsBlinkStop" );
  1759. }
  1760. }
  1761. if ( !bHasNotifications )
  1762. {
  1763. SetNotificationsButtonVisible( false );
  1764. SetNotificationsPanelVisible( false );
  1765. }
  1766. AdjustNotificationsPanelHeight();
  1767. }
  1768. //-----------------------------------------------------------------------------
  1769. // Purpose:
  1770. //-----------------------------------------------------------------------------
  1771. void CHudMainMenuOverride::SetNotificationsButtonVisible( bool bVisible )
  1772. {
  1773. if ( bVisible && ( m_pNotificationsPanel && m_pNotificationsPanel->IsVisible() ) )
  1774. return;
  1775. if ( m_pNotificationsShowPanel )
  1776. {
  1777. // Show the notifications show panel button if we have new notifications.
  1778. m_pNotificationsShowPanel->SetVisible( bVisible );
  1779. // Set the notification count variable.
  1780. if ( m_pNotificationsShowPanel )
  1781. {
  1782. m_pNotificationsShowPanel->SetDialogVariable( "noticount", NotificationQueue_GetNumNotifications() );
  1783. }
  1784. }
  1785. }
  1786. //-----------------------------------------------------------------------------
  1787. // Purpose:
  1788. //-----------------------------------------------------------------------------
  1789. void CHudMainMenuOverride::SetNotificationsPanelVisible( bool bVisible )
  1790. {
  1791. if ( m_pNotificationsPanel )
  1792. {
  1793. bool bHasNotifications = NotificationQueue_GetNumNotifications() != 0;
  1794. if ( bHasNotifications )
  1795. {
  1796. UpdateNotifications();
  1797. }
  1798. m_pNotificationsPanel->SetVisible( bVisible );
  1799. if ( bVisible )
  1800. {
  1801. m_pNotificationsScroller->InvalidateLayout();
  1802. m_pNotificationsScroller->GetScrollbar()->InvalidateLayout();
  1803. m_pNotificationsScroller->GetScrollbar()->SetValue( 0 );
  1804. SetMOTDVisible( false );
  1805. SetQuestLogVisible( false );
  1806. SetWatchStreamVisible( false );
  1807. m_pNotificationsShowPanel->SetVisible( false );
  1808. m_pNotificationsControl->OnTick();
  1809. m_pNotificationsControl->PerformLayout();
  1810. AdjustNotificationsPanelHeight();
  1811. // Faster updating while open.
  1812. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1813. vgui::ivgui()->AddTickSignal( GetVPanel(), 5 );
  1814. }
  1815. else
  1816. {
  1817. // Clear all notifications.
  1818. if ( bHasNotifications )
  1819. {
  1820. SetNotificationsButtonVisible( true );
  1821. }
  1822. // Slower updating while closed.
  1823. vgui::ivgui()->RemoveTickSignal( GetVPanel() );
  1824. vgui::ivgui()->AddTickSignal( GetVPanel(), 250 );
  1825. }
  1826. }
  1827. }
  1828. //-----------------------------------------------------------------------------
  1829. // Purpose:
  1830. //-----------------------------------------------------------------------------
  1831. void CHudMainMenuOverride::AdjustNotificationsPanelHeight()
  1832. {
  1833. // Fit to our contents, which may change without notifying us.
  1834. int iNotiTall = m_pNotificationsControl->GetTall();
  1835. if ( iNotiTall > m_pNotificationsScroller->GetTall() )
  1836. iNotiTall = m_pNotificationsScroller->GetTall();
  1837. int iTargetTall = YRES(40) + iNotiTall;
  1838. if ( m_pNotificationsPanel->GetTall() != iTargetTall )
  1839. m_pNotificationsPanel->SetTall( iTargetTall );
  1840. // Adjust visibility of the slider buttons and our width, as contents change.
  1841. if ( m_pNotificationsScroller )
  1842. {
  1843. if ( m_pNotificationsScroller->GetScrollbar()->GetSlider() &&
  1844. m_pNotificationsScroller->GetScrollbar()->GetSlider()->IsSliderVisible() )
  1845. {
  1846. m_pNotificationsPanel->SetWide( m_iNotiPanelWide + m_pNotificationsScroller->GetScrollbar()->GetSlider()->GetWide() );
  1847. m_pNotificationsScroller->GetScrollbar()->SetScrollbarButtonsVisible( true );
  1848. }
  1849. else
  1850. {
  1851. m_pNotificationsPanel->SetWide( m_iNotiPanelWide );
  1852. m_pNotificationsScroller->GetScrollbar()->SetScrollbarButtonsVisible( false );
  1853. }
  1854. }
  1855. }
  1856. //-----------------------------------------------------------------------------
  1857. // Purpose:
  1858. //-----------------------------------------------------------------------------
  1859. void CHudMainMenuOverride::UpdatePromotionalCodes( void )
  1860. {
  1861. // should we show the promo codes button?
  1862. vgui::Panel *pPromoCodesButton = FindChildByName( "ShowPromoCodesButton" );
  1863. if ( pPromoCodesButton )
  1864. {
  1865. bool bShouldBeVisible = false;
  1866. if ( steamapicontext && steamapicontext->SteamUser() )
  1867. {
  1868. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  1869. GCSDK::CGCClientSharedObjectCache *pSOCache = GCClientSystem()->GetSOCache( steamID );
  1870. if ( pSOCache )
  1871. {
  1872. GCSDK::CGCClientSharedObjectTypeCache *pTypeCache = pSOCache->FindTypeCache( k_EEconTypeClaimCode );
  1873. bShouldBeVisible = pTypeCache != NULL && pTypeCache->GetCount() != 0;
  1874. }
  1875. }
  1876. // The promo code button collides with the VR mode button. Turn off the promo code button
  1877. // in that case since the people who deliberately enabled VR are much more likely to want that
  1878. // than to claim their Well Spun Hat in Rift.
  1879. bool bShowVR = materials->GetCurrentConfigForVideoCard().m_nVRModeAdapter == materials->GetCurrentAdapter();
  1880. if( bShowVR )
  1881. {
  1882. bShouldBeVisible = false;
  1883. }
  1884. // has the player turned off this button?
  1885. if ( !cl_promotional_codes_button_show.GetBool() )
  1886. {
  1887. bShouldBeVisible = false;
  1888. }
  1889. if ( pPromoCodesButton->IsVisible() != bShouldBeVisible )
  1890. {
  1891. pPromoCodesButton->SetVisible( bShouldBeVisible );
  1892. }
  1893. if ( m_pVRModeBackground )
  1894. {
  1895. m_pVRModeBackground->SetVisible( bShouldBeVisible || bShowVR );
  1896. }
  1897. }
  1898. }
  1899. //-----------------------------------------------------------------------------
  1900. // Purpose:
  1901. //-----------------------------------------------------------------------------
  1902. bool CHudMainMenuOverride::IsVisible( void )
  1903. {
  1904. /*
  1905. // Only draw whenever the main menu is visible
  1906. if ( GetClientModeTFNormal()->GameUI() && steamapicontext && steamapicontext->SteamFriends() )
  1907. return GetClientModeTFNormal()->GameUI()->IsMainMenuVisible();
  1908. return BaseClass::IsVisible();
  1909. */
  1910. return true;
  1911. }
  1912. //-----------------------------------------------------------------------------
  1913. // Purpose:
  1914. //-----------------------------------------------------------------------------
  1915. void CHudMainMenuOverride::StartHighlightAnimation( mm_highlight_anims iAnim )
  1916. {
  1917. vgui::surface()->PlaySound( "ui/hint.wav" );
  1918. if ( m_pHighlightAnims[ iAnim ] )
  1919. {
  1920. m_pHighlightAnims[ iAnim ]->Popup();
  1921. }
  1922. }
  1923. //-----------------------------------------------------------------------------
  1924. // Purpose:
  1925. //-----------------------------------------------------------------------------
  1926. void CHudMainMenuOverride::HideHighlight( mm_highlight_anims iAnim )
  1927. {
  1928. if ( m_pHighlightAnims[ iAnim ] )
  1929. {
  1930. m_pHighlightAnims[ iAnim ]->Hide( 0 );
  1931. }
  1932. }
  1933. //-----------------------------------------------------------------------------
  1934. // Purpose:
  1935. //-----------------------------------------------------------------------------
  1936. void CHudMainMenuOverride::TogglePlayListMenu( void )
  1937. {
  1938. if ( m_bPlayListExpanded )
  1939. {
  1940. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "MMenu_PlayList_Collapse", false );
  1941. }
  1942. else
  1943. {
  1944. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( this, "MMenu_PlayList_Expand", false );
  1945. UpdatePlaylistEntries();
  1946. }
  1947. // These all rely on the playlist being in a specific state. If we're
  1948. // toggling, then there's no guarantees anything is where we think it is anymore
  1949. HideHighlight( MMHA_TUTORIAL );
  1950. HideHighlight( MMHA_PRACTICE );
  1951. HideHighlight( MMHA_LOADOUT );
  1952. HideHighlight( MMHA_STORE );
  1953. HideHighlight( MMHA_WAR );
  1954. m_bPlayListExpanded = !m_bPlayListExpanded;
  1955. CheckTrainingStatus();
  1956. }
  1957. void PromptOrFireCommand( const char* pszCommand )
  1958. {
  1959. if ( engine->IsInGame() )
  1960. {
  1961. CTFDisconnectConfirmDialog *pDialog = BuildDisconnectConfirmDialog();
  1962. if ( pDialog )
  1963. {
  1964. pDialog->Show();
  1965. pDialog->AddConfirmCommand( pszCommand );
  1966. }
  1967. }
  1968. else
  1969. {
  1970. engine->ClientCmd_Unrestricted( pszCommand );
  1971. }
  1972. }
  1973. //-----------------------------------------------------------------------------
  1974. // Purpose: Make the glows behind the update buttons stop pulsing
  1975. //-----------------------------------------------------------------------------
  1976. void CHudMainMenuOverride::StopUpdateGlow()
  1977. {
  1978. // Dont ever glow again
  1979. if ( cl_mainmenu_updateglow.GetInt() )
  1980. {
  1981. cl_mainmenu_updateglow.SetValue( 0 );
  1982. engine->ClientCmd_Unrestricted( "host_writeconfig" );
  1983. }
  1984. if ( m_pEventPromoContainer )
  1985. {
  1986. EditablePanel* pUpdateBackground = m_pEventPromoContainer->FindControl< EditablePanel >( "Background", true );
  1987. if ( pUpdateBackground )
  1988. {
  1989. g_pClientMode->GetViewportAnimationController()->StopAnimationSequence( pUpdateBackground, "MMenu_UpdateButton_StartGlow" );
  1990. pUpdateBackground->SetControlVisible( "ViewDetailsGlow", false, true );
  1991. pUpdateBackground->SetControlVisible( "ViewWarButtonGlow", false, true );
  1992. }
  1993. }
  1994. }
  1995. //-----------------------------------------------------------------------------
  1996. // Purpose:
  1997. //-----------------------------------------------------------------------------
  1998. void CHudMainMenuOverride::OnCommand( const char *command )
  1999. {
  2000. C_CTFGameStats::ImmediateWriteInterfaceEvent( "on_command(main_menu_override)", command );
  2001. if ( FStrEq( "toggle_play_menu", command ) )
  2002. {
  2003. TogglePlayListMenu();
  2004. return;
  2005. }
  2006. else if ( FStrEq( "play_competitive", command ) )
  2007. {
  2008. // Defaulting to 6v6
  2009. GTFGCClientSystem()->SetLadderType( k_nMatchGroup_Ladder_6v6 );
  2010. PromptOrFireCommand( "OpenMatchmakingLobby ladder" );
  2011. return;
  2012. }
  2013. else if ( FStrEq( "play_casual", command ) )
  2014. {
  2015. // Defaulting to 12v12
  2016. GTFGCClientSystem()->SetLadderType( k_nMatchGroup_Casual_12v12 );
  2017. PromptOrFireCommand( "OpenMatchmakingLobby casual" );
  2018. return;
  2019. }
  2020. else if ( FStrEq( "play_mvm", command ) )
  2021. {
  2022. PromptOrFireCommand( "OpenMatchmakingLobby mvm" );
  2023. return;
  2024. }
  2025. else if ( FStrEq( "play_quickplay", command ) )
  2026. {
  2027. PromptOrFireCommand( "OpenQuickplayDialog" );
  2028. return;
  2029. }
  2030. else if ( FStrEq( "play_training", command ) )
  2031. {
  2032. HideHighlight( MMHA_TUTORIAL );
  2033. if ( engine->IsInGame() )
  2034. {
  2035. const char *pText = "#TF_Training_Prompt";
  2036. const char *pTitle = "#TF_Training_Prompt_Title";
  2037. if ( TFGameRules() && TFGameRules()->IsInTraining() )
  2038. {
  2039. pTitle = "#TF_Training_Restart_Title";
  2040. pText = "#TF_Training_Restart_Text";
  2041. }
  2042. CTFConfirmTrainingDialog *pConfirm = vgui::SETUP_PANEL( new CTFConfirmTrainingDialog( pText, pTitle, this ) );
  2043. if ( pConfirm )
  2044. {
  2045. pConfirm->Show();
  2046. }
  2047. }
  2048. else
  2049. {
  2050. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine training_showdlg" );
  2051. }
  2052. }
  2053. else if ( Q_strnicmp( command, "soundentry", 10 ) == 0 )
  2054. {
  2055. PlaySoundEntry( command + 11 );
  2056. return;
  2057. }
  2058. else if ( !Q_stricmp( command, "motd_viewurl" ) )
  2059. {
  2060. CMOTDEntryDefinition *pMOTD = GetMOTDManager().GetMOTDByIndex( m_iCurrentMOTD );
  2061. if ( pMOTD )
  2062. {
  2063. const char *pszURL = pMOTD->GetURL();
  2064. if ( pszURL && pszURL[0] )
  2065. {
  2066. if ( steamapicontext && steamapicontext->SteamFriends() )
  2067. {
  2068. steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( pszURL );
  2069. }
  2070. }
  2071. }
  2072. return;
  2073. }
  2074. else if ( !Q_stricmp( command, "view_newuser_forums" ) )
  2075. {
  2076. HideHighlight( MMHA_NEWUSERFORUM );
  2077. if ( steamapicontext && steamapicontext->SteamFriends() )
  2078. {
  2079. steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://forums.steampowered.com/forums/forumdisplay.php?f=906" );
  2080. }
  2081. return;
  2082. }
  2083. else if ( !Q_stricmp( command, "opentf2options" ) )
  2084. {
  2085. HideHighlight( MMHA_OPTIONS );
  2086. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine opentf2options" );
  2087. }
  2088. else if ( !Q_stricmp( command, "motd_prev" ) )
  2089. {
  2090. if ( m_iCurrentMOTD > 0 )
  2091. {
  2092. m_iCurrentMOTD--;
  2093. UpdateMOTD( false );
  2094. }
  2095. return;
  2096. }
  2097. else if ( !Q_stricmp( command, "motd_next" ) )
  2098. {
  2099. if ( m_iCurrentMOTD < (GetMOTDManager().GetNumMOTDs()-1) )
  2100. {
  2101. m_iCurrentMOTD++;
  2102. UpdateMOTD( false );
  2103. }
  2104. return;
  2105. }
  2106. else if ( !Q_stricmp( command, "motd_show" ) )
  2107. {
  2108. SetMOTDVisible( !m_pMOTDPanel->IsVisible() );
  2109. }
  2110. else if ( !Q_stricmp( command, "motd_hide" ) )
  2111. {
  2112. SetMOTDVisible( false );
  2113. }
  2114. else if ( !Q_stricmp( command, "noti_show" ) )
  2115. {
  2116. SetNotificationsPanelVisible( true );
  2117. }
  2118. else if ( !Q_stricmp( command, "noti_hide" ) )
  2119. {
  2120. SetNotificationsPanelVisible( false );
  2121. }
  2122. else if ( !Q_stricmp( command, "notifications_update" ) )
  2123. {
  2124. // force visible if
  2125. if ( NotificationQueue_GetNumNotifications() != 0 )
  2126. {
  2127. SetNotificationsButtonVisible( true );
  2128. }
  2129. else
  2130. {
  2131. UpdateNotifications();
  2132. }
  2133. }
  2134. else if ( !Q_stricmp( command, "test_anim" ) )
  2135. {
  2136. InvalidateLayout( true, true );
  2137. StartHighlightAnimation( MMHA_TUTORIAL );
  2138. StartHighlightAnimation( MMHA_PRACTICE );
  2139. StartHighlightAnimation( MMHA_NEWUSERFORUM );
  2140. StartHighlightAnimation( MMHA_OPTIONS );
  2141. StartHighlightAnimation( MMHA_STORE );
  2142. StartHighlightAnimation( MMHA_LOADOUT );
  2143. StartHighlightAnimation( MMHA_WAR );
  2144. }
  2145. else if ( !Q_stricmp( command, "offlinepractice" ) )
  2146. {
  2147. HideHighlight( MMHA_PRACTICE );
  2148. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine training_showdlg" );
  2149. }
  2150. else if ( !Q_stricmp( command, "buyfeatured" ) )
  2151. {
  2152. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( VarArgs("engine open_store %d 1", m_pFeaturedItemPanel ? m_pFeaturedItemPanel->GetItem()->GetItemDefIndex() : 0 ) );
  2153. }
  2154. else if ( !Q_stricmp( command, "armory_open" ) )
  2155. {
  2156. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine open_charinfo_armory" );
  2157. }
  2158. else if ( !Q_stricmp( command, "engine disconnect" ) && engine->IsInGame() && TFGameRules() && ( TFGameRules()->IsMannVsMachineMode() || TFGameRules()->IsCompetitiveMode() ) )
  2159. {
  2160. // If we're playing MvM, "New Game" should take us back to MvM matchmaking
  2161. CTFDisconnectConfirmDialog *pDialog = BuildDisconnectConfirmDialog();
  2162. if ( pDialog )
  2163. {
  2164. pDialog->Show();
  2165. }
  2166. return;
  2167. }
  2168. else if ( !Q_stricmp( command, "callvote" ) )
  2169. {
  2170. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "engine callvote" );
  2171. if ( GetClientModeTFNormal()->GameUI() )
  2172. {
  2173. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( "ResumeGame" );
  2174. }
  2175. return;
  2176. }
  2177. else if ( !Q_stricmp( command, "showpromocodes" ) )
  2178. {
  2179. if ( steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() )
  2180. {
  2181. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  2182. switch ( GetUniverse() )
  2183. {
  2184. case k_EUniversePublic: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStr1024( "http://steamcommunity.com/profiles/%llu/promocodes/tf2", steamID.ConvertToUint64() ) ); break;
  2185. case k_EUniverseBeta: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStr1024( "http://beta.steamcommunity.com/profiles/%llu/promocodes/tf2", steamID.ConvertToUint64() ) ); break;
  2186. case k_EUniverseDev: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( CFmtStr1024( "http://localhost/community/profiles/%llu/promocodes/tf2", steamID.ConvertToUint64() ) ); break;
  2187. }
  2188. }
  2189. }
  2190. else if ( !Q_stricmp( command, "exitreplayeditor" ) )
  2191. {
  2192. #if defined( REPLAY_ENABLED )
  2193. CReplayPerformanceEditorPanel *pEditor = ReplayUI_GetPerformanceEditor();
  2194. if ( !pEditor )
  2195. return;
  2196. pEditor->Exit_ShowDialogs();
  2197. #endif // REPLAY_ENABLED
  2198. }
  2199. else if ( FStrEq( "showcomic", command ) )
  2200. {
  2201. if ( m_pWarLandingPage )
  2202. {
  2203. m_pWarLandingPage->InvalidateLayout( true, true );
  2204. m_pWarLandingPage->SetVisible( true );
  2205. }
  2206. }
  2207. else if ( FStrEq( "questlog", command ) )
  2208. {
  2209. SetQuestLogVisible( !GetQuestLog()->IsVisible() );
  2210. }
  2211. else if ( FStrEq( "watch_stream", command ) )
  2212. {
  2213. SetWatchStreamVisible( !m_pWatchStreamsPanel->IsVisible() );
  2214. }
  2215. else if ( FStrEq( "view_update_page", command ) )
  2216. {
  2217. StopUpdateGlow();
  2218. if ( steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() && steamapicontext->SteamUtils()->IsOverlayEnabled() )
  2219. {
  2220. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  2221. switch ( GetUniverse() )
  2222. {
  2223. case k_EUniversePublic: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://www.teamfortress.com/meetyourmatch" ); break;
  2224. case k_EUniverseBeta: // Fall through
  2225. case k_EUniverseDev: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://csham.valvesoftware.com/tf.com/meetyourmatch" ); break;
  2226. }
  2227. }
  2228. else
  2229. {
  2230. OpenStoreStatusDialog( NULL, "#MMenu_OverlayRequired", true, false );
  2231. }
  2232. return;
  2233. }
  2234. else if ( FStrEq( "view_update_comic", command ) )
  2235. {
  2236. if ( steamapicontext && steamapicontext->SteamFriends() && steamapicontext->SteamUtils() && steamapicontext->SteamUtils()->IsOverlayEnabled() )
  2237. {
  2238. CSteamID steamID = steamapicontext->SteamUser()->GetSteamID();
  2239. switch ( GetUniverse() )
  2240. {
  2241. case k_EUniversePublic: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://www.teamfortress.com/gargoyles_and_gravel" ); break;
  2242. case k_EUniverseBeta: // Fall through
  2243. case k_EUniverseDev: steamapicontext->SteamFriends()->ActivateGameOverlayToWebPage( "http://www.teamfortress.com/gargoyles_and_gravel" ); break;
  2244. }
  2245. }
  2246. else
  2247. {
  2248. OpenStoreStatusDialog( NULL, "#MMenu_OverlayRequired", true, false );
  2249. }
  2250. return;
  2251. }
  2252. else if ( FStrEq( "view_war", command ) )
  2253. {
  2254. HideHighlight( MMHA_WAR );
  2255. StopUpdateGlow();
  2256. m_pWarLandingPage->InvalidateLayout( true, true );
  2257. m_pWarLandingPage->SetVisible( true );
  2258. return;
  2259. }
  2260. else if ( FStrEq( "comp_access_info", command ) )
  2261. {
  2262. if ( m_pCompetitiveAccessInfo )
  2263. {
  2264. m_pCompetitiveAccessInfo->SetVisible( true );
  2265. }
  2266. }
  2267. else if ( FStrEq( "OpenReportPlayerDialog", command ) )
  2268. {
  2269. if ( !m_hReportPlayerDialog.Get() )
  2270. {
  2271. m_hReportPlayerDialog = vgui::SETUP_PANEL( new CReportPlayerDialog( this ) );
  2272. int x, y, ww, wt, wide, tall;
  2273. vgui::surface()->GetWorkspaceBounds( x, y, ww, wt );
  2274. m_hReportPlayerDialog->GetSize(wide, tall);
  2275. // Center it, keeping requested size
  2276. m_hReportPlayerDialog->SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2));
  2277. }
  2278. m_hReportPlayerDialog->Activate();
  2279. }
  2280. else
  2281. {
  2282. // Pass it on to GameUI main menu
  2283. if ( GetClientModeTFNormal()->GameUI() )
  2284. {
  2285. GetClientModeTFNormal()->GameUI()->SendMainMenuCommand( command );
  2286. return;
  2287. }
  2288. }
  2289. BaseClass::OnCommand( command );
  2290. }
  2291. void CHudMainMenuOverride::OnKeyCodePressed( KeyCode code )
  2292. {
  2293. if ( code == KEY_XBUTTON_B && engine->IsInGame() )
  2294. {
  2295. OnCommand( "ResumeGame" );
  2296. }
  2297. else
  2298. {
  2299. BaseClass::OnKeyCodePressed(code);
  2300. }
  2301. }
  2302. //-----------------------------------------------------------------------------
  2303. // Purpose:
  2304. //-----------------------------------------------------------------------------
  2305. void CHudMainMenuOverride::CheckTrainingStatus( void )
  2306. {
  2307. bool bNeedsTraining = tf_training_has_prompted_for_training.GetInt() <= 0;
  2308. bool bNeedsPractice = tf_training_has_prompted_for_offline_practice.GetInt() <= 0;
  2309. bool bShowForum = tf_training_has_prompted_for_forums.GetInt() <= 0;
  2310. bool bShowOptions = tf_training_has_prompted_for_options.GetInt() <= 0;
  2311. bool bWasInTraining = m_bWasInTraining;
  2312. m_bWasInTraining = false;
  2313. bool bShowLoadout = false;
  2314. if ( tf_training_has_prompted_for_loadout.GetInt() <= 0 )
  2315. {
  2316. // See if we have any items in our inventory.
  2317. int iNumItems = TFInventoryManager()->GetLocalTFInventory()->GetItemCount();
  2318. if ( iNumItems > 0 )
  2319. {
  2320. bShowLoadout = true;
  2321. }
  2322. }
  2323. if ( bShowLoadout && !m_bPlayListExpanded )
  2324. {
  2325. tf_training_has_prompted_for_loadout.SetValue( 1 );
  2326. StartHighlightAnimation( MMHA_LOADOUT );
  2327. }
  2328. else if ( bNeedsTraining && m_bPlayListExpanded )
  2329. {
  2330. tf_training_has_prompted_for_training.SetValue( 1 );
  2331. if ( m_pHighlightAnims[ MMHA_TUTORIAL ] )
  2332. {
  2333. if ( UTIL_HasLoadedAnyMap() )
  2334. {
  2335. m_pHighlightAnims[ MMHA_TUTORIAL ]->SetDialogVariable( "highlighttext", g_pVGuiLocalize->Find( "#MMenu_TutorialHighlight_Title2" ) );
  2336. }
  2337. else
  2338. {
  2339. m_pHighlightAnims[ MMHA_TUTORIAL ]->SetDialogVariable( "highlighttext", g_pVGuiLocalize->Find( "#MMenu_TutorialHighlight_Title" ) );
  2340. }
  2341. }
  2342. StartHighlightAnimation( MMHA_TUTORIAL );
  2343. }
  2344. else if ( bWasInTraining && Training_IsComplete() == false && tf_training_has_prompted_for_training.GetInt() < 2 && m_bPlayListExpanded)
  2345. {
  2346. tf_training_has_prompted_for_training.SetValue( 2 );
  2347. if ( m_pHighlightAnims[ MMHA_TUTORIAL ] )
  2348. {
  2349. m_pHighlightAnims[ MMHA_TUTORIAL ]->SetDialogVariable( "highlighttext", g_pVGuiLocalize->Find( "#MMenu_TutorialHighlight_Title3" ) );
  2350. }
  2351. StartHighlightAnimation( MMHA_TUTORIAL );
  2352. }
  2353. else if ( bNeedsPractice && m_bPlayListExpanded )
  2354. {
  2355. tf_training_has_prompted_for_offline_practice.SetValue( 1 );
  2356. StartHighlightAnimation( MMHA_PRACTICE );
  2357. }
  2358. else if ( bShowForum )
  2359. {
  2360. tf_training_has_prompted_for_forums.SetValue( 1 );
  2361. StartHighlightAnimation( MMHA_NEWUSERFORUM );
  2362. }
  2363. else if ( bShowOptions )
  2364. {
  2365. tf_training_has_prompted_for_options.SetValue( 1 );
  2366. StartHighlightAnimation( MMHA_OPTIONS );
  2367. }
  2368. }
  2369. void CHudMainMenuOverride::CheckForNewQuests( void )
  2370. {
  2371. CUtlVector< CEconItemView * > questItems;
  2372. TFInventoryManager()->GetAllQuestItems( &questItems );
  2373. ImagePanel *pImage = m_pQuestLogButton->FindControl< ImagePanel >( "SubImage", true );
  2374. if ( pImage )
  2375. {
  2376. if ( questItems.Count() > 0 )
  2377. {
  2378. pImage->SetImage( "button_quests" );
  2379. }
  2380. else
  2381. {
  2382. pImage->SetImage( "button_quests_disabled" );
  2383. }
  2384. }
  2385. EditablePanel *pNotiPanel = m_pQuestLogButton->FindControl< EditablePanel >( "NotificationsContainer", true );
  2386. if ( pNotiPanel )
  2387. {
  2388. // how many quests are unidentified?
  2389. int iUnidentified = 0;
  2390. FOR_EACH_VEC( questItems, i )
  2391. {
  2392. if ( IsQuestItemUnidentified( questItems[i]->GetSOCData() ) )
  2393. {
  2394. iUnidentified++;
  2395. }
  2396. }
  2397. pNotiPanel->SetDialogVariable( "noticount", iUnidentified );
  2398. pNotiPanel->SetVisible( iUnidentified > 0 );
  2399. }
  2400. }
  2401. void CHudMainMenuOverride::UpdatePlaylistEntries( void )
  2402. {
  2403. CMainMenuPlayListEntry::EDisabledStates_t eDisabledState = CMainMenuPlayListEntry::NOT_DISABLED;
  2404. CTFParty* pParty = GTFGCClientSystem()->GetParty();
  2405. if ( ( pParty && pParty->BOffline() ) || !GTFGCClientSystem()->BConnectedtoGC() || GTFGCClientSystem()->BHasOutstandingMatchmakingPartyMessage() )
  2406. {
  2407. eDisabledState = CMainMenuPlayListEntry::DISABLED_NO_GC;
  2408. }
  2409. // If we have a live match, and a we're not in it, but we should be in,
  2410. // dont let the user click the MM UI buttons. GTFGCClientSystem::Update() will nag them
  2411. // to rejoin their match or abandon.
  2412. if ( pParty && pParty->GetState() == CSOTFParty_State_IN_MATCH )
  2413. {
  2414. eDisabledState = CMainMenuPlayListEntry::DISABLED_MATCH_RUNNING;
  2415. }
  2416. CMainMenuPlayListEntry* pEntry = FindControl< CMainMenuPlayListEntry >( "CasualEntry", true );
  2417. if ( pEntry )
  2418. {
  2419. pEntry->SetDisabledReason( eDisabledState );
  2420. }
  2421. pEntry = FindControl< CMainMenuPlayListEntry >( "MvMEntry", true );
  2422. if ( pEntry )
  2423. {
  2424. pEntry->SetDisabledReason( eDisabledState );
  2425. }
  2426. pEntry = FindControl< CMainMenuPlayListEntry >( "CompetitiveEntry", true );
  2427. if ( pEntry )
  2428. {
  2429. // Only check competitive access last
  2430. if ( eDisabledState == CMainMenuPlayListEntry::NOT_DISABLED )
  2431. {
  2432. eDisabledState = !GTFGCClientSystem()->BHasCompetitiveAccess() ? CMainMenuPlayListEntry::DISABLED_NO_COMP_ACCESS : eDisabledState;
  2433. }
  2434. pEntry->SetDisabledReason( eDisabledState );
  2435. }
  2436. }
  2437. void CHudMainMenuOverride::SOEvent( const CSharedObject* pObject )
  2438. {
  2439. if ( pObject->GetTypeID() == CEconGameAccountClient::k_nTypeID )
  2440. {
  2441. UpdatePlaylistEntries();
  2442. }
  2443. if ( pObject->GetTypeID() != CEconItem::k_nTypeID )
  2444. return;
  2445. CEconItem *pEconItem = (CEconItem *)pObject;
  2446. // If the item is a competitive pass - update the main menu lock
  2447. // From _items_main.txt
  2448. const item_definition_index_t kCompetitivePassID = 1167;
  2449. if ( pEconItem->GetItemDefIndex() == kCompetitivePassID )
  2450. {
  2451. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName(PANEL_MAINMENUOVERRIDE);
  2452. if (pMMPanel)
  2453. {
  2454. pMMPanel->UpdatePlaylistEntries();
  2455. }
  2456. }
  2457. }
  2458. #define REMAP_COMMAND( oldCommand, newCommand ) \
  2459. const char *pszKey##oldCommand = engine->Key_LookupBindingExact(#oldCommand); \
  2460. const char *pszNewKey##oldCommand = engine->Key_LookupBindingExact(#newCommand); \
  2461. if ( pszKey##oldCommand && !pszNewKey##oldCommand ) \
  2462. { \
  2463. Msg( "Rebinding key %s to new command " #newCommand ".\n", pszKey##oldCommand ); \
  2464. engine->ClientCmd_Unrestricted( VarArgs( "bind \"%s\" \"" #newCommand "\"\n", pszKey##oldCommand ) ); \
  2465. }
  2466. //-----------------------------------------------------------------------------
  2467. // Purpose: Rebinds any binds for old commands to their new commands.
  2468. //-----------------------------------------------------------------------------
  2469. void CHudMainMenuOverride::PerformKeyRebindings( void )
  2470. {
  2471. REMAP_COMMAND( inspect, +inspect );
  2472. REMAP_COMMAND( taunt, +taunt );
  2473. REMAP_COMMAND( use_action_slot_item, +use_action_slot_item );
  2474. REMAP_COMMAND( use_action_slot_item_server, +use_action_slot_item_server );
  2475. }
  2476. //-----------------------------------------------------------------------------
  2477. // Purpose: GC Msg handler to receive the MOTD request response
  2478. //-----------------------------------------------------------------------------
  2479. class CGCMOTDRequestResponse : public GCSDK::CGCClientJob
  2480. {
  2481. public:
  2482. CGCMOTDRequestResponse( GCSDK::CGCClient *pClient ) : GCSDK::CGCClientJob( pClient ) {}
  2483. virtual bool BYieldingRunGCJob( GCSDK::IMsgNetPacket *pNetPacket )
  2484. {
  2485. GCSDK::CGCMsg<MsgGCMOTDRequestResponse_t> msg( pNetPacket );
  2486. // No new entries?
  2487. if ( !msg.Body().m_nEntries )
  2488. return true;
  2489. // No main menu panel?
  2490. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE );
  2491. if ( !pMMPanel )
  2492. return true;
  2493. // Get our local language
  2494. char uilanguage[ 64 ];
  2495. uilanguage[0] = 0;
  2496. engine->GetUILanguage( uilanguage, sizeof( uilanguage ) );
  2497. //V_strcpy_safe( uilanguage, "german" );
  2498. KeyValues *pEntriesKV = new KeyValues( "motd_entries");
  2499. // Try and load the cache file. If we fail, we'll just create a new one.
  2500. if ( !pMMPanel->ReloadedAllMOTDs() )
  2501. {
  2502. pEntriesKV->LoadFromFile( g_pFullFileSystem, GC_MOTD_CACHE_FILE );
  2503. }
  2504. bool bNewMOTDs = false;
  2505. // Store the time & language we last checked.
  2506. char rtime_buf[k_RTimeRenderBufferSize];
  2507. pEntriesKV->SetString( "last_request_time", CRTime::RTime32ToString( pMMPanel->GetLastMOTDRequestTime(), rtime_buf ) );
  2508. pEntriesKV->SetString( "last_request_language", GetLanguageShortName( pMMPanel->GetLastMOTDRequestLanguage() ) );
  2509. // Read in the entries one by one, and insert them into our keyvalues structure.
  2510. for ( int i = 0; i < msg.Body().m_nEntries; i++ )
  2511. {
  2512. char pchMsgString[2048];
  2513. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2514. return false;
  2515. // If there's already an entry with this index, overwrite the data
  2516. KeyValues *pNewEntry = pEntriesKV->FindKey( pchMsgString );
  2517. if ( !pNewEntry )
  2518. {
  2519. pNewEntry = new KeyValues( pchMsgString );
  2520. pEntriesKV->AddSubKey( pNewEntry );
  2521. }
  2522. pNewEntry->SetName( pchMsgString );
  2523. RTime32 iTime;
  2524. if ( !msg.BReadUintData( &iTime ) )
  2525. return false;
  2526. pNewEntry->SetString( "post_time", CRTime::RTime32ToString(iTime, rtime_buf) );
  2527. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2528. return false;
  2529. pNewEntry->SetString( VarArgs("title_%s", uilanguage), pchMsgString );
  2530. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2531. return false;
  2532. pNewEntry->SetString( VarArgs("text_%s", uilanguage), pchMsgString );
  2533. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2534. return false;
  2535. pNewEntry->SetString( "url", pchMsgString );
  2536. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2537. return false;
  2538. pNewEntry->SetString( "image", pchMsgString );
  2539. int iHeadertype;
  2540. if ( !msg.BReadIntData( &iHeadertype ) )
  2541. return false;
  2542. pNewEntry->SetString( "header_type", CFmtStr( "%d", iHeadertype ).Access() );
  2543. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2544. return false;
  2545. pNewEntry->SetString( VarArgs("header_%s", uilanguage), pchMsgString );
  2546. if ( !msg.BReadStr( pchMsgString, Q_ARRAYSIZE( pchMsgString ) ) )
  2547. return false;
  2548. pNewEntry->SetString( "header_icon", pchMsgString );
  2549. bNewMOTDs = true;
  2550. }
  2551. // Tell the schema to reload its MOTD block
  2552. CUtlVector< CUtlString > vecErrors;
  2553. pMMPanel->GetMOTDManager().BInitMOTDEntries( pEntriesKV, &vecErrors );
  2554. pMMPanel->GetMOTDManager().PurgeUnusedMOTDEntries( pEntriesKV );
  2555. // Save out our cache
  2556. pEntriesKV->SaveToFile( g_pFullFileSystem, GC_MOTD_CACHE_FILE );
  2557. // And tell the main menu to refresh the MOTD.
  2558. //pMMPanel->SetMOTDVisible( bNewMOTDs ); HACK! Temporarily turn this off!
  2559. pMMPanel->UpdateMOTD( bNewMOTDs );
  2560. return true;
  2561. }
  2562. };
  2563. GC_REG_JOB( GCSDK::CGCClient, CGCMOTDRequestResponse, "CGCMOTDRequestResponse", k_EMsgGCMOTDRequestResponse, GCSDK::k_EServerTypeGCClient );
  2564. //-----------------------------------------------------------------------------
  2565. // Purpose:
  2566. //-----------------------------------------------------------------------------
  2567. void CMainMenuToolTip::PerformLayout()
  2568. {
  2569. if ( !ShouldLayout() )
  2570. return;
  2571. _isDirty = false;
  2572. // Resize our text labels to fit.
  2573. int iW = 0;
  2574. int iH = 0;
  2575. for (int i = 0; i < m_pEmbeddedPanel->GetChildCount(); i++)
  2576. {
  2577. vgui::Label *pLabel = dynamic_cast<vgui::Label*>( m_pEmbeddedPanel->GetChild(i) );
  2578. if ( !pLabel )
  2579. continue;
  2580. // Only checking to see if we have any text
  2581. char szTmp[2];
  2582. pLabel->GetText( szTmp, sizeof(szTmp) );
  2583. if ( !szTmp[0] )
  2584. continue;
  2585. pLabel->InvalidateLayout(true);
  2586. int iX, iY;
  2587. pLabel->GetPos( iX, iY );
  2588. iW = MAX( iW, ( pLabel->GetWide() + (iX * 2) ) );
  2589. if ( iH == 0 )
  2590. {
  2591. iH += MAX( iH, pLabel->GetTall() + (iY * 2) );
  2592. }
  2593. else
  2594. {
  2595. iH += MAX( iH, pLabel->GetTall() );
  2596. }
  2597. }
  2598. m_pEmbeddedPanel->SetSize( iW, iH );
  2599. m_pEmbeddedPanel->SetVisible(true);
  2600. PositionWindow( m_pEmbeddedPanel );
  2601. }
  2602. //-----------------------------------------------------------------------------
  2603. // Purpose:
  2604. //-----------------------------------------------------------------------------
  2605. void CMainMenuToolTip::HideTooltip()
  2606. {
  2607. if ( m_pEmbeddedPanel )
  2608. {
  2609. m_pEmbeddedPanel->SetVisible(false);
  2610. }
  2611. BaseTooltip::HideTooltip();
  2612. }
  2613. //-----------------------------------------------------------------------------
  2614. // Purpose:
  2615. //-----------------------------------------------------------------------------
  2616. void CMainMenuToolTip::SetText(const char *pszText)
  2617. {
  2618. if ( m_pEmbeddedPanel )
  2619. {
  2620. _isDirty = true;
  2621. if ( pszText && pszText[0] == '#' )
  2622. {
  2623. m_pEmbeddedPanel->SetDialogVariable( "tiptext", g_pVGuiLocalize->Find( pszText ) );
  2624. }
  2625. else
  2626. {
  2627. m_pEmbeddedPanel->SetDialogVariable( "tiptext", pszText );
  2628. }
  2629. m_pEmbeddedPanel->SetDialogVariable( "tipsubtext", "" );
  2630. }
  2631. }
  2632. //-----------------------------------------------------------------------------
  2633. // Purpose: Reload the .res file
  2634. //-----------------------------------------------------------------------------
  2635. #if defined( STAGING_ONLY )
  2636. ConVar tf_icon_festive( "tf_icon_festive", 0 );
  2637. CON_COMMAND( mainmenu_refresh, "" )
  2638. {
  2639. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE );
  2640. if ( !pMMPanel )
  2641. return;
  2642. pMMPanel->InvalidateLayout( true, true );
  2643. }
  2644. CON_COMMAND( create_icons, "Generate 512 x 512 Paint Kit Item Icons for SteamMarket, Specify min and max itemdef ranges if desired" )
  2645. {
  2646. tf_icon_festive.SetValue( false );
  2647. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE );
  2648. if ( !pMMPanel )
  2649. return;
  2650. int min = args.ArgC() > 1 ? atoi( args[1] ) : -1;
  2651. int max = args.ArgC() > 2 ? atoi( args[2] ) : -1;
  2652. pMMPanel->GenerateIcons( false, min, max );
  2653. }
  2654. CON_COMMAND( create_icons_large, "Generate 1024 x 1024 Paint Kit Item Icons for Testing, Specify min and max itemdef ranges if desired" )
  2655. {
  2656. tf_icon_festive.SetValue( false );
  2657. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE );
  2658. if ( !pMMPanel )
  2659. return;
  2660. int min = args.ArgC() > 1 ? atoi( args[1] ) : -1;
  2661. int max = args.ArgC() > 2 ? atoi( args[2] ) : -1;;
  2662. pMMPanel->GenerateIcons( true, min, max );
  2663. }
  2664. CON_COMMAND( create_icons_festive, "" )
  2665. {
  2666. tf_icon_festive.SetValue( true );
  2667. CHudMainMenuOverride *pMMPanel = (CHudMainMenuOverride*)gViewPortInterface->FindPanelByName( PANEL_MAINMENUOVERRIDE );
  2668. if ( !pMMPanel )
  2669. return;
  2670. int min = args.ArgC() > 1 ? atoi( args[1] ) : -1;
  2671. int max = args.ArgC() > 2 ? atoi( args[2] ) : -1;
  2672. pMMPanel->GenerateIcons( false, min, max );
  2673. }
  2674. //-----------------------------------------------------------------------------
  2675. void BuildPaintkitItemInventoryImagePath( char *pchOutfile, int nMaxPath, const CTFItemDefinition *pItemDef, int iWear, bool bLargeTestIcons )
  2676. {
  2677. // CUtlString strDefName( pItemDef->GetDefinitionName() );
  2678. //strDefName = strDefName.Replace( ' ', '_' );
  2679. //strDefName.ToLower();
  2680. // const char *pchDefName = strDefName;
  2681. bool bIsPaintkitItem = pItemDef->GetCustomPainkKitDefinition() != NULL;
  2682. const char *pchOutputFolder;
  2683. if ( bIsPaintkitItem )
  2684. {
  2685. pchOutputFolder = bLargeTestIcons ? "resource/econ/generated_icons/LargeTest/" : "scripts/items/unencrypted/icons/generated_paintkit_icons/";
  2686. }
  2687. else
  2688. {
  2689. pchOutputFolder = "scripts/items/unencrypted/icons/generated_item_icons/";
  2690. }
  2691. // const char *pWear = bIsPaintkitItem ? CFmtStr( "_wear%d", iWear ) : "";
  2692. char fname[ MAX_PATH ];
  2693. V_FileBase( pItemDef->GetInventoryImage(), fname, sizeof(fname) );
  2694. if ( tf_icon_festive.GetBool() == true )
  2695. {
  2696. V_snprintf( pchOutfile, nMaxPath, "%s%s_festive.png",
  2697. pchOutputFolder,
  2698. fname
  2699. );
  2700. }
  2701. else
  2702. {
  2703. V_snprintf( pchOutfile, nMaxPath, "%s%s.png",
  2704. pchOutputFolder,
  2705. fname
  2706. );
  2707. }
  2708. }
  2709. //-----------------------------------------------------------------------------
  2710. bool SaveImageIconAsPng( CEconItemView *pItem, ITexture *pInputTexture, const char *pszFilePath )
  2711. {
  2712. bool bRet = false;
  2713. ITexture *pTexture = materials->FindTexture( "_rt_FullFrameFB1", TEXTURE_GROUP_RENDER_TARGET );
  2714. if ( !pTexture )
  2715. return bRet;
  2716. // If this is 3 4, we're only generating the actual composite texture for SFM
  2717. ConVarRef r_texcomp_dump( "r_texcomp_dump" );
  2718. if ( r_texcomp_dump.GetInt() == 4 )
  2719. {
  2720. return true;
  2721. }
  2722. if ( pTexture->GetImageFormat() == IMAGE_FORMAT_RGBA8888 ||
  2723. pTexture->GetImageFormat() == IMAGE_FORMAT_ABGR8888 ||
  2724. pTexture->GetImageFormat() == IMAGE_FORMAT_ARGB8888 ||
  2725. pTexture->GetImageFormat() == IMAGE_FORMAT_BGRA8888 ||
  2726. pTexture->GetImageFormat() == IMAGE_FORMAT_BGRX8888 )
  2727. {
  2728. int width = Min( pInputTexture->GetActualWidth(), pTexture->GetActualWidth() );
  2729. int height = Min( pInputTexture->GetActualHeight(), pTexture->GetActualHeight() );
  2730. Rect_t SrcRect = { 0, 0, width, height };
  2731. Rect_t DstRect = SrcRect;
  2732. if ( ( width > 0 ) && ( height > 0 ) )
  2733. {
  2734. void *pixelValue = malloc( width * height * sizeof( RGBA8888_t ) );
  2735. if ( pixelValue )
  2736. {
  2737. CMatRenderContextPtr pRenderContext( materials );
  2738. pRenderContext->PushRenderTargetAndViewport( pTexture, 0, 0, width, height );
  2739. pRenderContext->CopyTextureToRenderTargetEx( 0, pInputTexture, &SrcRect, &DstRect );
  2740. pRenderContext->ReadPixels( 0, 0, width, height, (unsigned char *)pixelValue, pInputTexture->GetImageFormat() );
  2741. CUtlBuffer outBuffer;
  2742. ImgUtl_WriteRGBAAsPNGToBuffer( reinterpret_cast<const unsigned char *>( pixelValue ), width, height, outBuffer );
  2743. FileHandle_t hFileOut = g_pFullFileSystem->Open( pszFilePath, "wb" );
  2744. if ( hFileOut != FILESYSTEM_INVALID_HANDLE )
  2745. {
  2746. Msg( "Saved.. %s\n", pszFilePath );
  2747. g_pFullFileSystem->Write( outBuffer.Base(), outBuffer.TellPut(), hFileOut );
  2748. g_pFullFileSystem->Close( hFileOut );
  2749. bRet = true;
  2750. }
  2751. // restore our previous state
  2752. pRenderContext->PopRenderTargetAndViewport();
  2753. free( pixelValue );
  2754. }
  2755. }
  2756. }
  2757. return bRet;
  2758. }
  2759. //-----------------------------------------------------------------------------
  2760. extern ConVar tf_paint_kit_force_wear;
  2761. ConVar tf_paint_kit_icon_generating_index( "tf_paint_kit_icon_generating_index", 0 );
  2762. void StartNextImage( CEconItemView *pItemData, CEmbeddedItemModelPanel *pItemModelPanel, const CUtlVector< item_definition_index_t > &vecItemDef, float flCurrentWear )
  2763. {
  2764. // Init the item
  2765. item_definition_index_t iDefIndex = vecItemDef[ tf_paint_kit_icon_generating_index.GetInt() ];
  2766. pItemData->Init( iDefIndex, AE_PAINTKITWEAPON, AE_USE_SCRIPT_VALUE, true );
  2767. pItemData->SetWeaponSkinBase( NULL );
  2768. pItemData->SetWeaponSkinBaseCompositor( NULL );
  2769. bool bIsPaintkitItem = pItemData->GetCustomPainkKitDefinition() != NULL;
  2770. if ( bIsPaintkitItem )
  2771. {
  2772. // Set up the wear
  2773. static CSchemaAttributeDefHandle pAttrDef_TextureWear( "set_item_texture_wear" );
  2774. pItemData->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_TextureWear, flCurrentWear );
  2775. Msg( "Force Setting PaintKit Wear for Icon Generation : Wear Level %d", tf_paint_kit_force_wear.GetInt() );
  2776. }
  2777. else
  2778. {
  2779. // force use_model_cache_icon
  2780. static CSchemaAttributeDefHandle pAttrDef_UseModelCacheIcon( "use_model_cache_icon" );
  2781. uint32 unUseModelCacheIcon = 1;
  2782. pItemData->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_UseModelCacheIcon, unUseModelCacheIcon );
  2783. }
  2784. // Add festive attr if enabled
  2785. if ( tf_icon_festive.GetBool() == true )
  2786. {
  2787. static CSchemaAttributeDefHandle pAttrDef_IsFestivized( "is_festivized" );
  2788. pItemData->GetAttributeList()->SetRuntimeAttributeValue( pAttrDef_IsFestivized, 1 );
  2789. }
  2790. //int iWear = EconWear_ToIntCategory( flCurrentWear );
  2791. // Force set convar for wear
  2792. //tf_paint_kit_force_wear.SetValue( iWear );
  2793. // force image generation to use high res
  2794. pItemData->SetWeaponSkinUseHighRes( true );
  2795. pItemModelPanel->SetItem( pItemData );
  2796. pItemModelPanel->InvalidateLayout( true, true );
  2797. }
  2798. extern ConVar tf_paint_kit_generating_icons;
  2799. void CHudMainMenuOverride::GenerateIconsThink()
  2800. {
  2801. CEmbeddedItemModelPanel *pItemModelPanel = dynamic_cast<CEmbeddedItemModelPanel *>( FindChildByName( "icon_generator" ) );
  2802. if ( !pItemModelPanel )
  2803. return;
  2804. ITexture *pIcon = pItemModelPanel->GetCachedGeneratedIcon();
  2805. if ( !pIcon )
  2806. return;
  2807. Msg( "Saving.. [%d] - %s\n", m_pIconData->GetItemDefIndex(), m_pIconData->GetItemDefinition()->GetDefinitionName() );
  2808. // Generate filepath
  2809. char outfile[ MAX_PATH ];
  2810. BuildPaintkitItemInventoryImagePath( outfile, sizeof(outfile), m_pIconData->GetItemDefinition(), tf_paint_kit_force_wear.GetInt(), m_bGeneratingLargeTestIcons );
  2811. SaveImageIconAsPng( m_pIconData, pIcon, outfile );
  2812. // Generate next step
  2813. while ( true )
  2814. {
  2815. int iIndex = tf_paint_kit_icon_generating_index.GetInt();
  2816. iIndex++;
  2817. // Increment Index, if index is greater, increment wear
  2818. if ( iIndex >= m_vecIconDefs.Count() )
  2819. {
  2820. iIndex = 0;
  2821. if ( tf_paint_kit_force_wear.GetInt() == 5 )
  2822. {
  2823. // reset bg color
  2824. SetBgColor( Color( 0, 0, 0, 0 ) );
  2825. m_bGeneratingIcons = false;
  2826. Msg( "Icon Generating Completed" );
  2827. tf_paint_kit_generating_icons.SetValue( 0 );
  2828. tf_paint_kit_icon_generating_index.SetValue( 0 );
  2829. return;
  2830. }
  2831. else
  2832. {
  2833. tf_paint_kit_force_wear.SetValue( tf_paint_kit_force_wear.GetInt() + 1 );
  2834. }
  2835. }
  2836. tf_paint_kit_icon_generating_index.SetValue( iIndex );
  2837. // only render non-paintkit item one time
  2838. if ( tf_paint_kit_force_wear.GetInt() > 0 )
  2839. {
  2840. // search for the next paintkit item to draw
  2841. item_definition_index_t iDefIndex = m_vecIconDefs[ tf_paint_kit_icon_generating_index.GetInt() ];
  2842. CEconItemView temp;
  2843. temp.Init( iDefIndex, AE_PAINTKITWEAPON, AE_USE_SCRIPT_VALUE, true );
  2844. if ( temp.GetCustomPainkKitDefinition() )
  2845. {
  2846. // draw this one
  2847. break;
  2848. }
  2849. }
  2850. }
  2851. // start next item, other wise increment wear and go again
  2852. delete m_pIconData;
  2853. m_pIconData = new CEconItemView;
  2854. StartNextImage( m_pIconData, pItemModelPanel, m_vecIconDefs, 0.2f );
  2855. }
  2856. ConVar tf_icon_bgcolor_override( "tf_icon_bgcolor_override", "" );
  2857. ConVar tf_icon_allow_all_items( "tf_icon_allow_all_items", "0" );
  2858. void CHudMainMenuOverride::GenerateIcons( bool bLarge, int min /*= -1*/, int max /*= -1*/ )
  2859. {
  2860. CEmbeddedItemModelPanel *pItemModelPanel = dynamic_cast<CEmbeddedItemModelPanel *>( FindChildByName("icon_generator") );
  2861. if ( !pItemModelPanel )
  2862. return;
  2863. const char *pszBGColor = tf_icon_bgcolor_override.GetString();
  2864. if ( pszBGColor && *pszBGColor )
  2865. {
  2866. color32 bgcolor;
  2867. UTIL_StringToColor32( &bgcolor, pszBGColor );
  2868. SetBgColor( Color( bgcolor.r, bgcolor.g, bgcolor.b, 255 ) );
  2869. }
  2870. const char *pchOutputFolder = bLarge ? "resource/econ/generated_icons/LargeTest/" : "scripts/items/unencrypted/icons/generated_paintkit_icons";
  2871. g_pFullFileSystem->CreateDirHierarchy( pchOutputFolder, NULL );
  2872. pItemModelPanel->SetTall( 1024 );
  2873. pItemModelPanel->SetWide( 1024 );
  2874. //pItemModelPanel->SetZPos( 1000 );
  2875. pItemModelPanel->SetInventoryImageType( CEmbeddedItemModelPanel::IMAGETYPE_LARGE );
  2876. pItemModelPanel->SetVisible( true );
  2877. pItemModelPanel->m_bOfflineIconGeneration = true;
  2878. int rtSize = bLarge ? 1024 : 512;
  2879. // Create a larger render target
  2880. materials->OverrideRenderTargetAllocation( true );
  2881. materials->CreateNamedRenderTargetTextureEx2(
  2882. "offline_icon_generation",
  2883. rtSize, rtSize,
  2884. RT_SIZE_DEFAULT,
  2885. materials->GetBackBufferFormat(),
  2886. MATERIAL_RT_DEPTH_SHARED,
  2887. TEXTUREFLAGS_CLAMPS | TEXTUREFLAGS_CLAMPT,
  2888. 0 );
  2889. materials->OverrideRenderTargetAllocation( false );
  2890. // Populate list of item icons
  2891. m_vecIconDefs.RemoveAll();
  2892. const CEconItemSchema::SortedItemDefinitionMap_t &mapItems = GetItemSchema()->GetSortedItemDefinitionMap();
  2893. int nPaintkitItems = 0;
  2894. int nNormalItems = 0;
  2895. FOR_EACH_MAP( mapItems, idxItem )
  2896. {
  2897. CEconItemDefinition *pItem = mapItems[idxItem];
  2898. CTFItemDefinition *pTFDef = (CTFItemDefinition *)pItem;
  2899. item_definition_index_t iDefIndex = pTFDef->GetDefinitionIndex();
  2900. // skip numbers below min
  2901. if ( min != -1 && iDefIndex < min )
  2902. continue;
  2903. // skip numbers if above. do not 'break;' since mapItems may NOT be in defindex order
  2904. if ( max != -1 && iDefIndex > max )
  2905. continue;
  2906. if ( pTFDef->GetCustomPainkKitDefinition() )
  2907. {
  2908. m_vecIconDefs.AddToTail( iDefIndex );
  2909. nPaintkitItems++;
  2910. }
  2911. else if ( tf_icon_allow_all_items.GetBool() )
  2912. {
  2913. m_vecIconDefs.AddToTail( iDefIndex );
  2914. nNormalItems++;
  2915. }
  2916. }
  2917. if ( !m_vecIconDefs.Count() )
  2918. {
  2919. Msg( "Didn't find any valid itemdefs to generate icons for" );
  2920. return;
  2921. }
  2922. Msg( "Found %d Valid Item defs. %d normal items and %d paintkit items\n", m_vecIconDefs.Count(), nNormalItems, nPaintkitItems );
  2923. int nNumGeneratingIcons = nNormalItems + nPaintkitItems * 5;
  2924. Msg( "Generating Icons for %d Items and 5 Wear Levels for each paintkit items (%d icons total)\n", m_vecIconDefs.Count(), nNumGeneratingIcons );
  2925. // Starting conditions
  2926. tf_paint_kit_force_wear.SetValue( 1 );
  2927. tf_paint_kit_generating_icons.SetValue( 1 );
  2928. // Create a dummy item
  2929. m_pIconData = new CEconItemView;
  2930. StartNextImage( m_pIconData, pItemModelPanel, m_vecIconDefs, 0.2 );
  2931. m_bGeneratingIcons = true;
  2932. m_bGeneratingLargeTestIcons = bLarge;
  2933. }
  2934. #endif