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.

1243 lines
36 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "charinfo_loadout_subpanel.h"
  8. #include "vgui/ISurface.h"
  9. #include "vgui/IInput.h"
  10. #include "vgui/ILocalize.h"
  11. #include "c_tf_freeaccount.h"
  12. #include "c_tf_player.h"
  13. #include "confirm_dialog.h"
  14. #include "gamestringpool.h"
  15. #include "c_tf_objective_resource.h"
  16. #include "tf_gamerules.h"
  17. #include "tf_item_inventory.h"
  18. #include "trading_start_dialog.h"
  19. #include "gc_clientsystem.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include <tier0/memdbgon.h>
  22. DECLARE_BUILD_FACTORY( CImageButton );
  23. ConVar tf_explanations_charinfopanel( "tf_explanations_charinfopanel", "0", FCVAR_ARCHIVE, "Whether the user has seen explanations for this panel." );
  24. //-----------------------------------------------------------------------------
  25. // Purpose:
  26. //-----------------------------------------------------------------------------
  27. CImageButton::CImageButton( vgui::Panel *parent, const char *panelName ) : BaseClass( parent, panelName, "" )
  28. {
  29. m_pszActiveImageName = NULL;
  30. m_pszInactiveImageName = NULL;
  31. m_pActiveImage = NULL;
  32. m_pInactiveImage = NULL;
  33. m_ActiveDrawColor = Color(255,255,255,255);
  34. m_InactiveDrawColor = Color(255,255,255,255);
  35. }
  36. //-----------------------------------------------------------------------------
  37. // Purpose:
  38. //-----------------------------------------------------------------------------
  39. void CImageButton::ApplySettings( KeyValues *inResourceData )
  40. {
  41. m_bScaleImage = inResourceData->GetInt( "scaleImage", 0 );
  42. // Active Image
  43. delete [] m_pszActiveImageName;
  44. m_pszActiveImageName = NULL;
  45. const char *activeImageName = inResourceData->GetString( "activeimage", "" );
  46. if ( *activeImageName )
  47. {
  48. SetActiveImage( activeImageName );
  49. }
  50. // Inactive Image
  51. delete [] m_pszInactiveImageName;
  52. m_pszInactiveImageName = NULL;
  53. const char *inactiveImageName = inResourceData->GetString( "inactiveimage", "" );
  54. if ( *inactiveImageName )
  55. {
  56. SetInactiveImage( inactiveImageName );
  57. }
  58. const char *pszDrawColor = inResourceData->GetString("activedrawcolor", "");
  59. if (*pszDrawColor)
  60. {
  61. int r = 0, g = 0, b = 0, a = 255;
  62. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  63. {
  64. m_ActiveDrawColor = Color(r, g, b, a);
  65. }
  66. else
  67. {
  68. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  69. m_ActiveDrawColor = pScheme->GetColor(pszDrawColor, Color(0, 0, 0, 0));
  70. }
  71. }
  72. pszDrawColor = inResourceData->GetString("inactivedrawcolor", "");
  73. if (*pszDrawColor)
  74. {
  75. int r = 0, g = 0, b = 0, a = 255;
  76. if (sscanf(pszDrawColor, "%d %d %d %d", &r, &g, &b, &a) >= 3)
  77. {
  78. m_InactiveDrawColor = Color(r, g, b, a);
  79. }
  80. else
  81. {
  82. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  83. m_InactiveDrawColor = pScheme->GetColor(pszDrawColor, Color(0, 0, 0, 0));
  84. }
  85. }
  86. BaseClass::ApplySettings( inResourceData );
  87. }
  88. //-----------------------------------------------------------------------------
  89. // Purpose:
  90. //-----------------------------------------------------------------------------
  91. void CImageButton::ApplySchemeSettings( vgui::IScheme *pScheme )
  92. {
  93. BaseClass::ApplySchemeSettings( pScheme );
  94. if ( m_pszActiveImageName && strlen( m_pszActiveImageName ) > 0 )
  95. {
  96. SetActiveImage(vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) );
  97. }
  98. if ( m_pszInactiveImageName && strlen( m_pszInactiveImageName ) > 0 )
  99. {
  100. SetInactiveImage(vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) );
  101. }
  102. vgui::IBorder *pBorder = pScheme->GetBorder( "NoBorder" );
  103. SetDefaultBorder( pBorder);
  104. SetDepressedBorder( pBorder );
  105. SetKeyFocusBorder( pBorder );
  106. Color defaultFgColor = GetSchemeColor( "Button.TextColor", Color(255, 255, 255, 255), pScheme );
  107. Color armedFgColor = GetSchemeColor( "Button.ArmedTextColor", Color(255, 255, 255, 255), pScheme );
  108. Color depressedFgColor = GetSchemeColor( "Button.DepressedTextColor", Color(255, 255, 255, 255), pScheme );
  109. Color blank(0,0,0,0);
  110. SetDefaultColor( defaultFgColor, blank );
  111. SetArmedColor( armedFgColor, blank );
  112. SetDepressedColor( depressedFgColor, blank );
  113. }
  114. //-----------------------------------------------------------------------------
  115. // Purpose:
  116. //-----------------------------------------------------------------------------
  117. void CImageButton::SetActiveImage( const char *imagename )
  118. {
  119. int len = Q_strlen( imagename ) + 1;
  120. m_pszActiveImageName = new char[ len ];
  121. Q_strncpy( m_pszActiveImageName, imagename, len );
  122. SetActiveImage(vgui::scheme()->GetImage( m_pszActiveImageName, m_bScaleImage ) );
  123. }
  124. //-----------------------------------------------------------------------------
  125. // Purpose:
  126. //-----------------------------------------------------------------------------
  127. void CImageButton::SetInactiveImage( const char *imagename )
  128. {
  129. int len = Q_strlen( imagename ) + 1;
  130. m_pszInactiveImageName = new char[ len ];
  131. Q_strncpy( m_pszInactiveImageName, imagename, len );
  132. SetInactiveImage(vgui::scheme()->GetImage( m_pszInactiveImageName, m_bScaleImage ) );
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. //-----------------------------------------------------------------------------
  137. void CImageButton::SetActiveImage( vgui::IImage *image )
  138. {
  139. m_pActiveImage = image;
  140. if ( m_pActiveImage )
  141. {
  142. int wide, tall;
  143. if ( m_bScaleImage )
  144. {
  145. // scaling, force the image size to be our size
  146. GetSize( wide, tall );
  147. m_pActiveImage->SetSize( wide, tall );
  148. }
  149. else
  150. {
  151. // not scaling, so set our size to the image size
  152. m_pActiveImage->GetSize( wide, tall );
  153. SetSize( wide, tall );
  154. }
  155. }
  156. Repaint();
  157. }
  158. //-----------------------------------------------------------------------------
  159. // Purpose:
  160. //-----------------------------------------------------------------------------
  161. void CImageButton::SetInactiveImage( vgui::IImage *image )
  162. {
  163. m_pInactiveImage = image;
  164. if ( m_pInactiveImage )
  165. {
  166. int wide, tall;
  167. if ( m_bScaleImage)
  168. {
  169. // scaling, force the image size to be our size
  170. GetSize( wide, tall );
  171. m_pInactiveImage->SetSize( wide, tall );
  172. }
  173. else
  174. {
  175. // not scaling, so set our size to the image size
  176. m_pInactiveImage->GetSize( wide, tall );
  177. SetSize( wide, tall );
  178. }
  179. }
  180. Repaint();
  181. }
  182. //-----------------------------------------------------------------------------
  183. // Purpose:
  184. //-----------------------------------------------------------------------------
  185. void CImageButton::OnSizeChanged( int newWide, int newTall )
  186. {
  187. if ( m_bScaleImage )
  188. {
  189. // scaling, force the image size to be our size
  190. if ( m_pActiveImage )
  191. m_pActiveImage->SetSize( newWide, newTall );
  192. if ( m_pInactiveImage )
  193. m_pInactiveImage->SetSize( newWide, newTall );
  194. }
  195. BaseClass::OnSizeChanged( newWide, newTall );
  196. }
  197. //-----------------------------------------------------------------------------
  198. // Purpose:
  199. //-----------------------------------------------------------------------------
  200. void CImageButton::Paint()
  201. {
  202. if ( IsArmed() || _buttonFlags.IsFlagSet( FORCE_DEPRESSED ) )
  203. {
  204. // draw the active image
  205. if ( m_pActiveImage )
  206. {
  207. m_pActiveImage->SetColor( m_ActiveDrawColor );
  208. m_pActiveImage->SetPos( 0, 0 );
  209. m_pActiveImage->Paint();
  210. }
  211. }
  212. else
  213. {
  214. // draw the inactive image
  215. if ( m_pInactiveImage )
  216. {
  217. m_pActiveImage->SetColor( m_InactiveDrawColor );
  218. m_pInactiveImage->SetPos( 0, 0 );
  219. m_pInactiveImage->Paint();
  220. }
  221. }
  222. BaseClass::Paint();
  223. }
  224. const char *g_pszSubButtonNames[CHSB_NUM_BUTTONS] =
  225. {
  226. "ShowBackpackButton", // CHSB_BACKPACK,
  227. "ShowCraftingButton", // CHSB_CRAFTING,
  228. "ShowArmoryButton", // CHSB_ARMORY,
  229. "ShowTradeButton", // CHSB_TRADING,
  230. };
  231. const char *g_pszSubButtonLabelNames[CHSB_NUM_BUTTONS] =
  232. {
  233. "ShowBackpackLabel", // CHSB_BACKPACK,
  234. "ShowCraftingLabel", // CHSB_CRAFTING,
  235. "ShowArmoryLabel", // CHSB_ARMORY,
  236. "ShowTradeLabel", // CHSB_TRADING,
  237. };
  238. int g_nLoadoutClassOrder[] =
  239. {
  240. TF_CLASS_SCOUT,
  241. TF_CLASS_SOLDIER,
  242. TF_CLASS_PYRO,
  243. TF_CLASS_DEMOMAN,
  244. TF_CLASS_HEAVYWEAPONS,
  245. TF_CLASS_ENGINEER,
  246. TF_CLASS_MEDIC,
  247. TF_CLASS_SNIPER,
  248. TF_CLASS_SPY
  249. };
  250. //-----------------------------------------------------------------------------
  251. // Purpose:
  252. //-----------------------------------------------------------------------------
  253. CCharInfoLoadoutSubPanel::CCharInfoLoadoutSubPanel(Panel *parent) : vgui::PropertyPage(parent, "CharInfoLoadoutSubPanel")
  254. {
  255. m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
  256. m_iCurrentTeamIndex = TF_TEAM_RED;
  257. m_iShowingPanel = CHAP_LOADOUT;
  258. m_iPrevShowingPanel = CHAP_LOADOUT;
  259. memset( m_pClassButtons, 0, sizeof( m_pClassButtons ) );
  260. m_pClassButtons[ TF_CLASS_SCOUT ] = new CImageButton( this, "scout" );
  261. m_pClassButtons[ TF_CLASS_SOLDIER ] = new CImageButton( this, "soldier" );
  262. m_pClassButtons[ TF_CLASS_PYRO ] = new CImageButton( this, "pyro" );
  263. m_pClassButtons[ TF_CLASS_DEMOMAN ] = new CImageButton( this, "demoman" );
  264. m_pClassButtons[ TF_CLASS_HEAVYWEAPONS ] = new CImageButton( this, "heavyweapons" );
  265. m_pClassButtons[ TF_CLASS_ENGINEER ] = new CImageButton( this, "engineer" );
  266. m_pClassButtons[ TF_CLASS_MEDIC ] = new CImageButton( this, "medic" );
  267. m_pClassButtons[ TF_CLASS_SNIPER ] = new CImageButton( this, "sniper" );
  268. m_pClassButtons[ TF_CLASS_SPY ] = new CImageButton( this, "spy" );
  269. for( int i = 0; i < Q_ARRAYSIZE( m_pClassButtons ); i++ )
  270. {
  271. if( m_pClassButtons[ i ] )
  272. m_pClassButtons[ i ]->SetParentNeedsCursorMoveEvents( true );
  273. }
  274. for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
  275. {
  276. m_pSubButtons[i] = new CImageButton( this, g_pszSubButtonNames[i] );
  277. m_pButtonLabels[i] = new CExLabel( this, g_pszSubButtonLabelNames[i], "" );
  278. }
  279. m_iOverSubButton = -1;
  280. m_pClassLoadoutPanel = new CClassLoadoutPanel( this );
  281. m_pBackpackPanel = new CBackpackPanel( this, "backpack_panel" );
  282. m_pCraftingPanel = new CCraftingPanel( this, "crafting_panel" );
  283. m_pArmoryPanel = new CArmoryPanel( this, "armory_panel" );
  284. m_pArmoryPanel->AllowGotoStore();
  285. m_pSelectLabel = NULL;
  286. m_pLoadoutChangesLabel = NULL;
  287. m_pNoSteamLabel = NULL;
  288. m_pNoGCLabel = NULL;
  289. m_pClassLabel = NULL;
  290. m_pItemsLabel = NULL;
  291. m_bSnapClassLayout = false;
  292. m_bClassLayoutDirty = false;
  293. m_bRequestingInventoryRefresh = false;
  294. m_flStartExplanationsAt = 0;
  295. vgui::ivgui()->AddTickSignal( GetVPanel() );
  296. REGISTER_COLOR_AS_OVERRIDABLE( m_ItemColorNone, "itemcountcolor_noitems" );
  297. REGISTER_COLOR_AS_OVERRIDABLE( m_ItemColor, "itemcountcolor" );
  298. }
  299. //-----------------------------------------------------------------------------
  300. // Purpose:
  301. //-----------------------------------------------------------------------------
  302. CCharInfoLoadoutSubPanel::~CCharInfoLoadoutSubPanel()
  303. {
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose:
  307. //-----------------------------------------------------------------------------
  308. void CCharInfoLoadoutSubPanel::ApplySchemeSettings( vgui::IScheme *pScheme )
  309. {
  310. BaseClass::ApplySchemeSettings( pScheme );
  311. LoadControlSettings( "Resource/UI/CharInfoLoadoutSubPanel.res" );
  312. m_pSelectLabel = dynamic_cast<vgui::Label*>( FindChildByName("SelectLabel") );
  313. m_pLoadoutChangesLabel = dynamic_cast<vgui::Label*>( FindChildByName("LoadoutChangesLabel") );
  314. m_pNoSteamLabel = dynamic_cast<vgui::Label*>( FindChildByName("NoSteamLabel") );
  315. m_pNoGCLabel = dynamic_cast<vgui::Label*>( FindChildByName("NoGCLabel") );
  316. m_pClassLabel = dynamic_cast<vgui::Label*>( FindChildByName("ClassLabel") );
  317. int ignored;
  318. if ( m_pClassLabel )
  319. {
  320. m_pClassLabel->GetPos( ignored, m_iClassLabelYPos );
  321. }
  322. m_pItemsLabel = dynamic_cast<CExLabel*>( FindChildByName("ItemsLabel") );
  323. if ( m_pItemsLabel )
  324. {
  325. m_pItemsLabel->GetPos( ignored, m_iItemLabelYPos );
  326. }
  327. // Start classes sized as if the mouse is in the middle of the screen
  328. m_iMouseXPos = -1;
  329. m_bSnapClassLayout = true;
  330. RecalculateTargetClassLayout();
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose:
  334. //-----------------------------------------------------------------------------
  335. void CCharInfoLoadoutSubPanel::OnPageShow( void )
  336. {
  337. SetVisible( true );
  338. BaseClass::OnPageShow();
  339. if( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
  340. {
  341. m_pClassButtons[ m_iCurrentClassIndex ]->GetPos( m_iMouseXPos, m_iMouseYPos );
  342. m_bClassLayoutDirty = true;
  343. InvalidateLayout();
  344. }
  345. // If this is the first time we've opened the loadout, start the loadout explanations
  346. if ( !tf_explanations_charinfopanel.GetBool() && ShouldShowExplanations() )
  347. {
  348. m_flStartExplanationsAt = engine->Time() + 0.5;
  349. }
  350. }
  351. //-----------------------------------------------------------------------------
  352. // Purpose:
  353. //-----------------------------------------------------------------------------
  354. void CCharInfoLoadoutSubPanel::OnSelectionStarted( void )
  355. {
  356. PostActionSignal( new KeyValues("SelectionUpdate", "open", 1 ) );
  357. }
  358. //-----------------------------------------------------------------------------
  359. // Purpose:
  360. //-----------------------------------------------------------------------------
  361. void CCharInfoLoadoutSubPanel::OnSelectionEnded( void )
  362. {
  363. PostActionSignal( new KeyValues("SelectionUpdate", "open", 0 ) );
  364. }
  365. //-----------------------------------------------------------------------------
  366. // Purpose:
  367. //-----------------------------------------------------------------------------
  368. void CCharInfoLoadoutSubPanel::OnCancelSelection( void )
  369. {
  370. PostMessage( m_pClassLoadoutPanel, new KeyValues("CancelSelection") );
  371. PostMessage( m_pBackpackPanel, new KeyValues("CancelSelection") );
  372. PostMessage( m_pCraftingPanel, new KeyValues("CancelSelection") );
  373. PostMessage( m_pArmoryPanel, new KeyValues("CancelSelection") );
  374. RequestFocus();
  375. }
  376. //-----------------------------------------------------------------------------
  377. // Purpose:
  378. //-----------------------------------------------------------------------------
  379. void CCharInfoLoadoutSubPanel::OnCharInfoClosing( void )
  380. {
  381. switch ( m_iShowingPanel )
  382. {
  383. case CHAP_CRAFTING:
  384. PostMessage( m_pCraftingPanel, new KeyValues("Closing") );
  385. break;
  386. case CHAP_BACKPACK:
  387. break;
  388. case CHAP_ARMORY:
  389. PostMessage( m_pArmoryPanel, new KeyValues("Closing") );
  390. break;
  391. case CHAP_LOADOUT:
  392. PostMessage( m_pClassLoadoutPanel, new KeyValues("Closing") );
  393. break;
  394. default: // Class loadout.
  395. break;
  396. }
  397. }
  398. //-----------------------------------------------------------------------------
  399. // Purpose:
  400. //-----------------------------------------------------------------------------
  401. void CCharInfoLoadoutSubPanel::OnOpenCrafting( void )
  402. {
  403. OpenToCrafting();
  404. }
  405. //-----------------------------------------------------------------------------
  406. // Purpose:
  407. //-----------------------------------------------------------------------------
  408. void CCharInfoLoadoutSubPanel::OnCraftingClosed( void )
  409. {
  410. PostMessage( m_pCraftingPanel, new KeyValues("Closing") );
  411. m_iShowingPanel = CHAP_LOADOUT;
  412. m_iPrevShowingPanel = CHAP_CRAFTING;
  413. m_flStartExplanationsAt = 0;
  414. m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
  415. UpdateModelPanels();
  416. RequestFocus();
  417. }
  418. //-----------------------------------------------------------------------------
  419. // Purpose:
  420. //-----------------------------------------------------------------------------
  421. void CCharInfoLoadoutSubPanel::OnArmoryClosed( void )
  422. {
  423. // Return to whatever we were on before opening the armory
  424. PostMessage( m_pArmoryPanel, new KeyValues("Closing") );
  425. m_iShowingPanel = m_iPrevShowingPanel;
  426. m_iPrevShowingPanel = CHAP_ARMORY;
  427. m_flStartExplanationsAt = 0;
  428. m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
  429. UpdateModelPanels();
  430. RequestFocus();
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Purpose:
  434. //-----------------------------------------------------------------------------
  435. void CCharInfoLoadoutSubPanel::OnCommand( const char *command )
  436. {
  437. if ( !Q_strnicmp( command, "loadout ", 8 ) )
  438. {
  439. // Ignore selection while we don't have a steam connection
  440. if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
  441. return;
  442. m_flStartExplanationsAt = 0;
  443. const char *pszClass = command+8;
  444. if ( pszClass[0] != '\0' )
  445. {
  446. int nClassIndex = GetClassIndexFromString( pszClass, NUM_CLASSES_IN_LOADOUT_PANEL );
  447. if ( nClassIndex != TF_CLASS_UNDEFINED && m_iCurrentClassIndex != nClassIndex )
  448. {
  449. SetClassIndex( nClassIndex, true );
  450. return;
  451. }
  452. }
  453. }
  454. else if ( !Q_strnicmp( command, "backpack", 8 ) )
  455. {
  456. OpenToBackpack();
  457. }
  458. else if ( !Q_strnicmp( command, "crafting", 8 ) )
  459. {
  460. OpenToCrafting();
  461. }
  462. else if ( !Q_strnicmp( command, "armory", 6 ) )
  463. {
  464. OpenToArmory();
  465. }
  466. else if ( !Q_strnicmp( command, "trading", 7 ) )
  467. {
  468. OpenTradingStartDialog( this );
  469. }
  470. else if ( !Q_stricmp( command, "show_explanations" ) )
  471. {
  472. if ( !m_flStartExplanationsAt )
  473. {
  474. m_flStartExplanationsAt = engine->Time();
  475. }
  476. RequestFocus();
  477. }
  478. else
  479. {
  480. engine->ClientCmd( const_cast<char *>( command ) );
  481. }
  482. BaseClass::OnCommand( command );
  483. }
  484. //-----------------------------------------------------------------------------
  485. // Purpose:
  486. //-----------------------------------------------------------------------------
  487. void CCharInfoLoadoutSubPanel::RequestInventoryRefresh()
  488. {
  489. m_bRequestingInventoryRefresh = false;
  490. // Don't respond to the mouse if we don't have items
  491. if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
  492. {
  493. ShowWaitingDialog( new CGenericWaitingDialog(this), "#NoSteamNoItems_Refresh", true, true, 30.0f );
  494. if ( !m_bRequestingInventoryRefresh )
  495. {
  496. // make sure the local inventory is added as a listener
  497. TFInventoryManager()->UpdateLocalInventory();
  498. m_bRequestingInventoryRefresh = true;
  499. // ask GC for refresh
  500. GCSDK::CProtoBufMsg< CMsgRequestInventoryRefresh > msg( k_EMsgGCRequestInventoryRefresh );
  501. GCClientSystem()->BSendMessage( msg );
  502. }
  503. }
  504. }
  505. //-----------------------------------------------------------------------------
  506. // Purpose:
  507. //-----------------------------------------------------------------------------
  508. void CCharInfoLoadoutSubPanel::SetClassIndex( int iClassIndex, bool bOpenClassLoadout )
  509. {
  510. Assert(iClassIndex >= TF_CLASS_UNDEFINED && iClassIndex <= NUM_CLASSES_IN_LOADOUT_PANEL);
  511. m_iCurrentClassIndex = iClassIndex;
  512. m_iShowingPanel = CHAP_LOADOUT;
  513. UpdateModelPanels( bOpenClassLoadout );
  514. RequestInventoryRefresh();
  515. }
  516. //-----------------------------------------------------------------------------
  517. // Purpose:
  518. //-----------------------------------------------------------------------------
  519. void CCharInfoLoadoutSubPanel::SetTeamIndex( int iTeam )
  520. {
  521. Assert( IsValidTFTeam( iTeam ) );
  522. m_iCurrentTeamIndex = iTeam;
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Purpose:
  526. //-----------------------------------------------------------------------------
  527. void CCharInfoLoadoutSubPanel::OpenSubPanel( charinfo_activepanels_t iPanel )
  528. {
  529. m_flStartExplanationsAt = 0;
  530. m_iCurrentClassIndex = TF_CLASS_UNDEFINED;
  531. m_iPrevShowingPanel = m_iShowingPanel;
  532. m_iShowingPanel = iPanel;
  533. UpdateModelPanels();
  534. RequestInventoryRefresh();
  535. }
  536. //-----------------------------------------------------------------------------
  537. // Purpose:
  538. //-----------------------------------------------------------------------------
  539. void CCharInfoLoadoutSubPanel::UpdateModelPanels( bool bOpenClassLoadout )
  540. {
  541. int iLabelClassToSet = -1;
  542. int iClassIndexToSet = 0;
  543. if ( m_iShowingPanel == CHAP_CRAFTING )
  544. {
  545. m_pClassLoadoutPanel->SetVisible( false );
  546. m_pBackpackPanel->SetVisible( false );
  547. m_pArmoryPanel->SetVisible( false );
  548. m_pCraftingPanel->ShowPanel( m_iCurrentClassIndex, true, (m_iPrevShowingPanel == CHAP_ARMORY) );
  549. }
  550. else if ( m_iShowingPanel == CHAP_BACKPACK )
  551. {
  552. m_pClassLoadoutPanel->SetVisible( false );
  553. m_pCraftingPanel->SetVisible( false );
  554. m_pArmoryPanel->SetVisible( false );
  555. m_pBackpackPanel->ShowPanel( m_iCurrentClassIndex, true, (m_iPrevShowingPanel == CHAP_ARMORY) );
  556. }
  557. else if ( m_iShowingPanel == CHAP_ARMORY )
  558. {
  559. m_pClassLoadoutPanel->SetVisible( false );
  560. m_pCraftingPanel->SetVisible( false );
  561. m_pBackpackPanel->SetVisible( false );
  562. m_pArmoryPanel->ShowPanel( m_iArmoryItemDef );
  563. }
  564. else
  565. {
  566. iClassIndexToSet = bOpenClassLoadout ? m_iCurrentClassIndex : TF_CLASS_UNDEFINED;
  567. m_pArmoryPanel->SetVisible( false );
  568. m_pBackpackPanel->SetVisible( false );
  569. m_pCraftingPanel->SetVisible( false );
  570. m_pClassLoadoutPanel->SetTeam( m_iCurrentTeamIndex );
  571. m_pClassLoadoutPanel->SetClass( iClassIndexToSet );
  572. m_pClassLoadoutPanel->ShowPanel( iClassIndexToSet, false, (m_iPrevShowingPanel == CHAP_ARMORY) );
  573. iLabelClassToSet = m_iCurrentClassIndex;
  574. }
  575. m_iCurrentClassIndex = iClassIndexToSet;
  576. if( bOpenClassLoadout )
  577. {
  578. PostActionSignal( new KeyValues("ClassSelected", "class", m_iCurrentClassIndex ) );
  579. }
  580. else
  581. {
  582. m_iLabelSetToClass = iLabelClassToSet;
  583. m_bClassLayoutDirty = true;
  584. InvalidateLayout();
  585. }
  586. }
  587. //-----------------------------------------------------------------------------
  588. // Purpose:
  589. //-----------------------------------------------------------------------------
  590. void CCharInfoLoadoutSubPanel::PerformLayout( void )
  591. {
  592. BaseClass::PerformLayout();
  593. // Show our changes label if we're alive, and hence won't get the changes immediately
  594. bool bChangesLabel = false;
  595. if ( engine->IsInGame() )
  596. {
  597. C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer();
  598. if ( pLocalPlayer && pLocalPlayer->IsAlive() && pLocalPlayer->GetObserverMode() == OBS_MODE_NONE )
  599. {
  600. bChangesLabel = true;
  601. }
  602. }
  603. if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
  604. {
  605. bool bLoggedIntoSteam = steamapicontext && steamapicontext->SteamUser() && steamapicontext->SteamUser()->BLoggedOn();
  606. if ( m_pItemsLabel )
  607. m_pNoGCLabel->SetVisible( bLoggedIntoSteam );
  608. if ( m_pNoSteamLabel )
  609. m_pNoSteamLabel->SetVisible( !bLoggedIntoSteam );
  610. if ( m_pSelectLabel )
  611. m_pSelectLabel->SetVisible( false );
  612. if ( m_pLoadoutChangesLabel)
  613. m_pLoadoutChangesLabel->SetVisible( false );
  614. for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
  615. {
  616. m_pSubButtons[i]->SetVisible( false );
  617. m_pButtonLabels[i]->SetVisible( false );
  618. }
  619. }
  620. else
  621. {
  622. if ( m_pNoSteamLabel )
  623. m_pNoSteamLabel->SetVisible( false );
  624. if ( m_pNoGCLabel )
  625. m_pNoGCLabel->SetVisible( false );
  626. if ( m_pSelectLabel )
  627. m_pSelectLabel->SetVisible( true );
  628. for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
  629. {
  630. m_pSubButtons[i]->SetVisible( true );
  631. m_pButtonLabels[i]->SetVisible( true );
  632. }
  633. if ( !bChangesLabel )
  634. {
  635. if ( m_pSelectLabel )
  636. m_pSelectLabel->SetPos( 0, m_iSelectLabelY );
  637. if ( m_pLoadoutChangesLabel )
  638. m_pLoadoutChangesLabel->SetVisible( false );
  639. }
  640. else
  641. {
  642. if ( m_pSelectLabel )
  643. m_pSelectLabel->SetPos( 0, m_iSelectLabelOnChangesY );
  644. if ( m_pLoadoutChangesLabel )
  645. m_pLoadoutChangesLabel->SetVisible( true );
  646. }
  647. }
  648. m_iOverSubButton = -1;
  649. if ( m_pSelectLabel )
  650. m_pClassLabel->SetVisible( false );
  651. if ( m_pItemsLabel )
  652. m_pItemsLabel->SetVisible( false );
  653. m_bClassLayoutDirty = false;
  654. // Now Layout the class images.
  655. for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
  656. {
  657. int i = g_nLoadoutClassOrder[iPanel];
  658. int iX = m_iClassLayout[i][0];
  659. int iY = m_iClassLayout[i][1];
  660. int iWide = m_iClassLayout[i][2];
  661. int iTall = m_iClassLayout[i][3];
  662. if ( m_bSnapClassLayout )
  663. {
  664. m_pClassButtons[i]->SetBounds( iX, iY, iWide, iTall );
  665. }
  666. else
  667. {
  668. // Lerp towards the target
  669. int iCurX, iCurY, iCurWide, iCurTall;
  670. m_pClassButtons[i]->GetBounds( iCurX, iCurY, iCurWide, iCurTall );
  671. int iNewX = Lerp( 0.2, iCurX, iX );
  672. int iNewY = Lerp( 0.2, iCurY, iY );
  673. int iNewWide = Lerp( 0.2, iCurWide, iWide );
  674. int iNewTall = Lerp( 0.2, iCurTall, iTall );
  675. m_pClassButtons[i]->SetBounds( iNewX, iNewY, iNewWide, iNewTall );
  676. if ( abs(iNewX-iX) > 5 || abs(iNewY-iY) > 5 || abs(iNewWide-iWide) > 5 || abs(iNewTall-iTall) > 5 )
  677. {
  678. m_bClassLayoutDirty = true;
  679. }
  680. }
  681. }
  682. // We need to do our own management of cursor arming in the buttons, because the curserentered/exited code can't
  683. // deal with the way we resize the buttons without the cursor moving.
  684. int iBestButton = -1;
  685. int iBestZ = 0;
  686. int x = m_iMouseXPos, y = m_iMouseYPos;
  687. // only get the actual cursor pos if we don't have a cached cursor pos. THe
  688. // cached pos might have come from the keyboard.
  689. if( x < 0 )
  690. vgui::input()->GetCursorPos(x, y);
  691. for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
  692. {
  693. int i = g_nLoadoutClassOrder[iPanel];
  694. m_pClassButtons[i]->SetArmed( false );
  695. m_pClassButtons[i]->SetEnabled( TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() );
  696. if ( m_pClassButtons[i]->IsWithin( x,y ) && iBestZ < m_pClassButtons[i]->GetZPos() )
  697. {
  698. iBestButton = i;
  699. iBestZ = m_pClassButtons[i]->GetZPos();
  700. }
  701. }
  702. if ( iBestButton >= 0 && iBestButton < ARRAYSIZE( m_pClassButtons ) )
  703. {
  704. m_pClassButtons[iBestButton]->SetArmed( true );
  705. if ( m_iLabelSetToClass != iBestButton )
  706. {
  707. m_iLabelSetToClass = iBestButton;
  708. }
  709. UpdateLabelFromClass( m_iLabelSetToClass );
  710. }
  711. m_bSnapClassLayout = false;
  712. }
  713. void CCharInfoLoadoutSubPanel::UpdateLabelFromClass( int nClass )
  714. {
  715. if ( nClass < 0 )
  716. return;
  717. const wchar_t *wszClassName = g_pVGuiLocalize->Find( g_aPlayerClassNames[nClass] );
  718. if ( m_pClassLabel )
  719. {
  720. m_pClassLabel->SetText( wszClassName );
  721. m_pClassLabel->SetVisible( true );
  722. }
  723. if ( m_pItemsLabel )
  724. {
  725. m_pItemsLabel->SetVisible( true );
  726. }
  727. CUtlVector<CEconItemView*> pList;
  728. int iNumItems = TFInventoryManager()->GetAllUsableItemsForSlot( nClass, -1, &pList );
  729. if ( !iNumItems )
  730. {
  731. const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#NoItemsFoundShort" );
  732. m_pItemsLabel->SetText( wszItemsName );
  733. m_pItemsLabel->SetColorStr( m_ItemColorNone );
  734. }
  735. else if ( iNumItems == 1 )
  736. {
  737. const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#ItemsFoundShortOne" );
  738. m_pItemsLabel->SetText( wszItemsName );
  739. m_pItemsLabel->SetColorStr( m_ItemColor );
  740. }
  741. else
  742. {
  743. wchar_t wzCount[10];
  744. _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iNumItems );
  745. wchar_t wTemp[32];
  746. g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("ItemsFoundShort"), 1, wzCount );
  747. m_pItemsLabel->SetText( wTemp );
  748. m_pItemsLabel->SetColorStr( m_ItemColor );
  749. }
  750. int iPos = 0;
  751. for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
  752. {
  753. if ( iRemapIndexToClass[i] == nClass )
  754. {
  755. iPos = i;
  756. break;
  757. }
  758. }
  759. Assert(iPos != 0 );
  760. int iXLeft = (GetWide() - ((m_iClassWideMin * NUM_CLASSES_IN_LOADOUT_PANEL) + (m_iClassXDelta * (NUM_CLASSES_IN_LOADOUT_PANEL-1)))) * 0.5;
  761. int iBaseX = iXLeft + ((m_iClassWideMin + m_iClassXDelta) * (iPos-1));
  762. int iCenterX = iBaseX + (m_iClassWideMin * 0.5);
  763. m_pClassLabel->SetVisible( true );
  764. m_pClassLabel->SetPos( iCenterX - (m_pClassLabel->GetWide() * 0.5), m_iClassLabelYPos );
  765. m_pItemsLabel->SetVisible( true );
  766. m_pItemsLabel->SetPos( iCenterX - (m_pItemsLabel->GetWide() * 0.5), m_iItemLabelYPos );
  767. }
  768. void CCharInfoLoadoutSubPanel::UpdateLabelFromSubButton( int nButton )
  769. {
  770. if( nButton < 0 )
  771. nButton = CHSB_NUM_BUTTONS - 1;
  772. else if( nButton >= CHSB_NUM_BUTTONS )
  773. nButton = 0;
  774. if ( m_iOverSubButton == nButton )
  775. return;
  776. m_iOverSubButton = nButton;
  777. switch ( nButton )
  778. {
  779. default:
  780. case CHSB_BACKPACK:
  781. {
  782. int iNumItems = TFInventoryManager()->GetLocalTFInventory()->GetItemCount();
  783. if ( iNumItems == 1 )
  784. {
  785. const wchar_t *wszItemsName = g_pVGuiLocalize->Find( "#Loadout_OpenBackpackDesc1" );
  786. m_pItemsLabel->SetText( wszItemsName );
  787. }
  788. else
  789. {
  790. wchar_t wzCount[10];
  791. _snwprintf( wzCount, ARRAYSIZE( wzCount ), L"%d", iNumItems );
  792. wchar_t wTemp[32];
  793. g_pVGuiLocalize->ConstructString_safe( wTemp, g_pVGuiLocalize->Find("Loadout_OpenBackpackDesc"), 1, wzCount );
  794. m_pItemsLabel->SetText( wTemp );
  795. }
  796. }
  797. break;
  798. case CHSB_CRAFTING:
  799. m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenCraftingDesc" ) );
  800. break;
  801. case CHSB_ARMORY:
  802. m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenArmoryDesc" ) );
  803. break;
  804. case CHSB_TRADING:
  805. m_pItemsLabel->SetText( g_pVGuiLocalize->Find( "Loadout_OpenTradingDesc" ) );
  806. break;
  807. }
  808. int iX, iY;
  809. m_pSubButtons[nButton]->GetPos( iX, iY );
  810. iX += (m_pSubButtons[nButton]->GetWide() * 0.5);
  811. iY += m_pSubButtons[nButton]->GetTall() + YRES(5);
  812. m_pItemsLabel->SetVisible( true );
  813. m_pItemsLabel->SetPos( iX - (m_pItemsLabel->GetWide() * 0.5), iY + (m_iItemLabelYPos - m_iClassLabelYPos) );
  814. m_pItemsLabel->SetColorStr( m_ItemColor );
  815. for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
  816. {
  817. m_pSubButtons[i]->SetArmed( false );
  818. }
  819. m_pSubButtons[nButton]->SetArmed( true );
  820. m_pSubButtons[nButton]->RequestFocus();
  821. }
  822. //-----------------------------------------------------------------------------
  823. // Purpose:
  824. //-----------------------------------------------------------------------------
  825. void CCharInfoLoadoutSubPanel::OnTick( void )
  826. {
  827. if ( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
  828. return;
  829. if ( !IsVisible() )
  830. return;
  831. if ( m_bRequestingInventoryRefresh && TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
  832. {
  833. m_bRequestingInventoryRefresh = false;
  834. CloseWaitingDialog();
  835. return;
  836. }
  837. // if the class layout is dirty, invalidate our layout so that
  838. // we'll animate the class buttons.
  839. if ( m_bClassLayoutDirty )
  840. {
  841. InvalidateLayout();
  842. }
  843. if ( !HasFocus() )
  844. return;
  845. // Don't respond to the mouse if we don't have items
  846. if ( !TFInventoryManager()->GetLocalTFInventory()->RetrievedInventoryFromSteam() )
  847. return;
  848. if ( m_flStartExplanationsAt && m_flStartExplanationsAt < engine->Time() )
  849. {
  850. m_flStartExplanationsAt = 0;
  851. if ( ShouldShowExplanations() )
  852. {
  853. tf_explanations_charinfopanel.SetValue( 1 );
  854. CExplanationPopup *pPopup = dynamic_cast<CExplanationPopup*>( FindChildByName("StartExplanation") );
  855. if ( pPopup )
  856. {
  857. pPopup->Popup();
  858. }
  859. }
  860. }
  861. }
  862. //-----------------------------------------------------------------------------
  863. // Purpose: Handles mousing over classes
  864. //-----------------------------------------------------------------------------
  865. void CCharInfoLoadoutSubPanel::OnCursorMoved( int x, int y )
  866. {
  867. RecalculateTargetClassLayoutAtPos( x, y );
  868. }
  869. //-----------------------------------------------------------------------------
  870. // Purpose: Handles setting the highlighted class for both mouse and keyboard
  871. //-----------------------------------------------------------------------------
  872. void CCharInfoLoadoutSubPanel::RecalculateTargetClassLayoutAtPos( int x, int y )
  873. {
  874. // Ignore mouse movement outside the buttons
  875. bool bWithin = false;
  876. for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
  877. {
  878. if ( m_pClassButtons[i]->IsWithin(x,y) )
  879. {
  880. bWithin = true;
  881. break;
  882. }
  883. }
  884. if ( bWithin )
  885. {
  886. m_iMouseXPos = x;
  887. m_iMouseYPos = y;
  888. RecalculateTargetClassLayout();
  889. m_bClassLayoutDirty = true;
  890. }
  891. else
  892. {
  893. // See if we're over a sub button
  894. bool bOverSubButton = false;
  895. for ( int i = 0; i < CHSB_NUM_BUTTONS; i++ )
  896. {
  897. if ( m_pSubButtons[i]->IsWithin(x,y) )
  898. {
  899. bOverSubButton = true;
  900. UpdateLabelFromSubButton( i );
  901. }
  902. }
  903. if ( !bOverSubButton && m_pClassLabel->IsVisible() )
  904. {
  905. // Hide the class label
  906. if ( m_iMouseXPos != -1 )
  907. {
  908. m_iMouseXPos = -1;
  909. RecalculateTargetClassLayout();
  910. m_bClassLayoutDirty = true;
  911. }
  912. m_iOverSubButton = -1;
  913. m_iLabelSetToClass = -1;
  914. m_pClassLabel->SetVisible( false );
  915. m_pItemsLabel->SetVisible( false );
  916. }
  917. }
  918. }
  919. //-----------------------------------------------------------------------------
  920. // Purpose:
  921. //-----------------------------------------------------------------------------
  922. void CCharInfoLoadoutSubPanel::RecalculateTargetClassLayout( void )
  923. {
  924. // Now Layout the class images.
  925. for ( int i = TF_FIRST_NORMAL_CLASS; i <= NUM_CLASSES_IN_LOADOUT_PANEL; i++ )
  926. {
  927. int iIndex = GetRemappedMenuIndexForClass(i);
  928. // Figure out where we'd be unscaled
  929. int iXLeft = (GetWide() - ((m_iClassWideMin * NUM_CLASSES_IN_LOADOUT_PANEL) + (m_iClassXDelta * (NUM_CLASSES_IN_LOADOUT_PANEL-1)))) * 0.5;
  930. int iBaseX = iXLeft + ((m_iClassWideMin + m_iClassXDelta) * (iIndex-1));
  931. // Scale based on distance from the mouse cursor.
  932. int iCenterX = iBaseX + (m_iClassWideMin * 0.5);
  933. float flScale = 0.0;
  934. if ( m_iMouseXPos >= 0 )
  935. {
  936. flScale = RemapValClamped( abs(m_iMouseXPos - iCenterX), m_iClassDistanceMin, m_iClassDistanceMax, 1.0, 0.0 );
  937. }
  938. float iWide = RemapValClamped( flScale, 0.0, 1.0, m_iClassWideMin, m_iClassWideMax );
  939. float iTall = RemapValClamped( flScale, 0.0, 1.0, m_iClassTallMin, m_iClassTallMax );
  940. int iY = m_iClassYPos - ((iTall - m_iClassTallMin) * 0.5);
  941. int iX = iBaseX - ((iWide - m_iClassWideMin) * 0.5);
  942. m_pClassButtons[i]->SetZPos( flScale * 100 );
  943. // Cache off the target bounds for this class button
  944. m_iClassLayout[i][0] = iX;
  945. m_iClassLayout[i][1] = iY;
  946. m_iClassLayout[i][2] = iWide;
  947. m_iClassLayout[i][3] = iTall;
  948. }
  949. }
  950. void CCharInfoLoadoutSubPanel::MoveCharacterSelection( int nDirection )
  951. {
  952. int nCurrent = 0;
  953. if ( m_iLabelSetToClass != -1 )
  954. {
  955. for ( int i = 0; i < ARRAYSIZE( g_nLoadoutClassOrder ); i++ )
  956. {
  957. if ( m_iLabelSetToClass == g_nLoadoutClassOrder[ i ] )
  958. {
  959. nCurrent = i;
  960. break;
  961. }
  962. }
  963. nCurrent += nDirection;
  964. if ( nCurrent < 0 )
  965. {
  966. nCurrent = ARRAYSIZE( g_nLoadoutClassOrder ) - 1;
  967. }
  968. else if ( nCurrent >= ARRAYSIZE( g_nLoadoutClassOrder ) )
  969. {
  970. nCurrent = 0;
  971. }
  972. }
  973. for ( int i = 0; i < ARRAYSIZE( g_nLoadoutClassOrder ); i++ )
  974. {
  975. m_pClassButtons[ g_nLoadoutClassOrder[ i ] ]->SetArmed( false );
  976. }
  977. // animate the class buttons
  978. CImageButton *pButton = m_pClassButtons[ g_nLoadoutClassOrder[ nCurrent ] ];
  979. int x, y, wide, tall;
  980. pButton->GetBounds( x, y, wide, tall );
  981. RecalculateTargetClassLayoutAtPos( x + wide/2, y + tall/2 );
  982. pButton->RequestFocus();
  983. }
  984. void CCharInfoLoadoutSubPanel::OnKeyCodeTyped(vgui::KeyCode code)
  985. {
  986. // turn off key handling in this panel when we're showing a loadout
  987. // for one class
  988. if ( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
  989. {
  990. // let escape and B (aka "go back") through so we
  991. // can actually get out of the loadout screen
  992. if ( code == KEY_ESCAPE )
  993. {
  994. BaseClass::OnKeyCodePressed( code );
  995. }
  996. return;
  997. }
  998. BaseClass::OnKeyCodeTyped( code );
  999. }
  1000. void CCharInfoLoadoutSubPanel::OnKeyCodePressed(vgui::KeyCode code)
  1001. {
  1002. ButtonCode_t nButtonCode = GetBaseButtonCode( code );
  1003. // turn off key handling in this panel when we're showing a loadout
  1004. // for one class
  1005. if( m_iCurrentClassIndex != TF_CLASS_UNDEFINED )
  1006. {
  1007. // let escape and B (aka "go back") through so we
  1008. // can actually get out of the loadout screen
  1009. if ( nButtonCode == KEY_XBUTTON_B )
  1010. {
  1011. BaseClass::OnKeyCodePressed( code );
  1012. }
  1013. return;
  1014. }
  1015. if ( nButtonCode == KEY_XBUTTON_LEFT ||
  1016. nButtonCode == KEY_XSTICK1_LEFT ||
  1017. nButtonCode == KEY_XSTICK2_LEFT ||
  1018. nButtonCode == STEAMCONTROLLER_DPAD_LEFT ||
  1019. code == KEY_LEFT )
  1020. {
  1021. if ( m_iLabelSetToClass != -1 )
  1022. {
  1023. MoveCharacterSelection( -1 );
  1024. }
  1025. else
  1026. {
  1027. UpdateLabelFromSubButton( m_iOverSubButton - 1 );
  1028. }
  1029. return;
  1030. }
  1031. else if ( nButtonCode == KEY_XBUTTON_RIGHT ||
  1032. nButtonCode == KEY_XSTICK1_RIGHT ||
  1033. nButtonCode == KEY_XSTICK2_RIGHT ||
  1034. nButtonCode == STEAMCONTROLLER_DPAD_RIGHT ||
  1035. code == KEY_RIGHT )
  1036. {
  1037. if ( m_iLabelSetToClass != -1 )
  1038. {
  1039. MoveCharacterSelection( 1 );
  1040. }
  1041. else
  1042. {
  1043. UpdateLabelFromSubButton( m_iOverSubButton + 1 );
  1044. }
  1045. return;
  1046. }
  1047. else if ( nButtonCode == KEY_XBUTTON_UP ||
  1048. nButtonCode == KEY_XSTICK1_UP ||
  1049. nButtonCode == KEY_XSTICK2_UP ||
  1050. nButtonCode == STEAMCONTROLLER_DPAD_UP ||
  1051. code == KEY_UP )
  1052. {
  1053. if ( m_iLabelSetToClass == -1 )
  1054. {
  1055. m_iLabelSetToClass = g_nLoadoutClassOrder[ 0 ];
  1056. CImageButton *pButton = m_pClassButtons[ m_iLabelSetToClass ];
  1057. UpdateLabelFromClass( m_iLabelSetToClass );
  1058. int x, y, wide, tall;
  1059. pButton->GetBounds( x, y, wide, tall );
  1060. RecalculateTargetClassLayoutAtPos( x + wide/2, y + tall/2 );
  1061. pButton->RequestFocus();
  1062. }
  1063. return;
  1064. }
  1065. else if ( nButtonCode == KEY_XBUTTON_DOWN ||
  1066. nButtonCode == KEY_XSTICK1_DOWN ||
  1067. nButtonCode == KEY_XSTICK2_DOWN ||
  1068. nButtonCode == STEAMCONTROLLER_DPAD_DOWN ||
  1069. code == KEY_DOWN )
  1070. {
  1071. if ( m_iLabelSetToClass != -1 )
  1072. {
  1073. m_iLabelSetToClass = -1;
  1074. m_pClassLabel->SetVisible( false );
  1075. m_pItemsLabel->SetVisible( false );
  1076. for ( int iPanel = 0; iPanel < ARRAYSIZE( g_nLoadoutClassOrder ); iPanel++ )
  1077. {
  1078. int i = g_nLoadoutClassOrder[iPanel];
  1079. m_pClassButtons[i]->SetArmed( false );
  1080. }
  1081. UpdateLabelFromSubButton( 0 );
  1082. }
  1083. return;
  1084. }
  1085. BaseClass::OnKeyCodePressed( code );
  1086. }