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.

1497 lines
42 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================
  6. #include "cbase.h"
  7. #include "weapon_selection.h"
  8. #include "iclientmode.h"
  9. #include "history_resource.h"
  10. #include "hud_macros.h"
  11. #include <KeyValues.h>
  12. #include <vgui/IScheme.h>
  13. #include <vgui/ISurface.h>
  14. #include <vgui/ISystem.h>
  15. #include <vgui_controls/AnimationController.h>
  16. #include <vgui_controls/Panel.h>
  17. #include <vgui_controls/Label.h>
  18. #include <vgui_controls/TextImage.h>
  19. #include <vgui_controls/EditablePanel.h>
  20. #include "vgui/ILocalize.h"
  21. #include <string.h>
  22. #include "baseobject_shared.h"
  23. #include "tf_imagepanel.h"
  24. #include "item_model_panel.h"
  25. #include "c_tf_player.h"
  26. #include "c_tf_weapon_builder.h"
  27. #include "tf_spectatorgui.h"
  28. #include "tf_gamerules.h"
  29. #include "tf_logic_halloween_2014.h"
  30. #include "inputsystem/iinputsystem.h"
  31. #ifndef WIN32
  32. #define _cdecl
  33. #endif
  34. #define SELECTION_TIMEOUT_THRESHOLD 2.5f // Seconds
  35. #define SELECTION_FADEOUT_TIME 3.0f
  36. #define FASTSWITCH_DISPLAY_TIMEOUT 0.5f
  37. #define FASTSWITCH_FADEOUT_TIME 0.5f
  38. ConVar tf_weapon_select_demo_start_delay( "tf_weapon_select_demo_start_delay", "1.0", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Delay after spawning to start the weapon bucket demo." );
  39. ConVar tf_weapon_select_demo_time( "tf_weapon_select_demo_time", "0.5", FCVAR_CLIENTDLL | FCVAR_ARCHIVE, "Time to pulse each weapon bucket upon spawning as a new class. 0 to turn off." );
  40. //-----------------------------------------------------------------------------
  41. // Purpose: tf weapon selection hud element
  42. //-----------------------------------------------------------------------------
  43. class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::EditablePanel
  44. {
  45. DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel );
  46. public:
  47. CHudWeaponSelection( const char *pElementName );
  48. virtual ~CHudWeaponSelection( void );
  49. virtual bool ShouldDraw();
  50. virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon );
  51. virtual void SwitchToLastWeapon( void ) OVERRIDE;
  52. virtual void CycleToNextWeapon( void );
  53. virtual void CycleToPrevWeapon( void );
  54. virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
  55. virtual void SelectWeaponSlot( int iSlot );
  56. virtual C_BaseCombatWeapon *GetSelectedWeapon( void );
  57. virtual void OpenSelection( void );
  58. virtual void HideSelection( void );
  59. virtual void Init();
  60. virtual void LevelInit();
  61. virtual void LevelShutdown( void );
  62. virtual void FireGameEvent( IGameEvent *event );
  63. virtual void Reset(void)
  64. {
  65. CBaseHudWeaponSelection::Reset();
  66. // selection time is a little farther back so we don't show it when we spawn
  67. m_flSelectionTime = gpGlobals->curtime - ( FASTSWITCH_DISPLAY_TIMEOUT + FASTSWITCH_FADEOUT_TIME + 0.1 );
  68. }
  69. virtual void SelectSlot( int iSlot );
  70. void _cdecl UserCmd_Slot11( void );
  71. void _cdecl UserCmd_Slot12( void );
  72. protected:
  73. struct SlotLayout_t
  74. {
  75. float x, y;
  76. float wide, tall;
  77. };
  78. void ComputeSlotLayout( SlotLayout_t *rSlot, int nActiveSlot, int nSelectionMode );
  79. virtual void OnThink();
  80. virtual void PerformLayout( void );
  81. virtual void PostChildPaint();
  82. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  83. void DrawSelection( C_BaseCombatWeapon *pSelectedWeapon );
  84. virtual bool IsWeaponSelectable()
  85. {
  86. if (IsInSelectionMode())
  87. return true;
  88. return false;
  89. }
  90. private:
  91. C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  92. C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  93. void FastWeaponSwitch( int iWeaponSlot );
  94. void PlusTypeFastWeaponSwitch( int iWeaponSlot, bool *pbPlaySwitchSound );
  95. int GetNumVisibleSlots();
  96. bool ShouldDrawInternal();
  97. virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon )
  98. {
  99. m_hSelectedWeapon = pWeapon;
  100. }
  101. virtual void SetSelectedSlot( int slot )
  102. {
  103. m_iSelectedSlot = slot;
  104. }
  105. void DrawString( wchar_t *text, int xpos, int ypos, Color col, bool bCenter = false );
  106. void DrawWeaponTexture( C_TFPlayer *pPlayer, C_BaseCombatWeapon *pWeapon, int xpos, int ypos, float flLargeBoxWide, float flLargeBoxTall );
  107. CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionText" );
  108. CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" );
  109. CPanelAnimationVarAliasType( float, m_flSmallBoxWide, "SmallBoxWide", "32", "proportional_float" );
  110. CPanelAnimationVarAliasType( float, m_flSmallBoxTall, "SmallBoxTall", "21", "proportional_float" );
  111. CPanelAnimationVarAliasType( float, m_flPlusStyleBoxWide, "PlusStyleBoxWide", "120", "proportional_float" );
  112. CPanelAnimationVarAliasType( float, m_flPlusStyleBoxTall, "PlusStyleBoxTall", "84", "proportional_float" );
  113. CPanelAnimationVar( float, m_flPlusStyleExpandPercent, "PlusStyleExpandSelected", "0.3" )
  114. CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" );
  115. CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" );
  116. CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "12", "proportional_float" );
  117. CPanelAnimationVarAliasType( float, m_flRightMargin, "RightMargin", "0", "proportional_float" );
  118. CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" );
  119. CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" );
  120. CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "16", "proportional_float" );
  121. CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "8", "proportional_float" );
  122. CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" );
  123. CPanelAnimationVarAliasType( float, m_flErrorYPos, "ErrorYPos", "60", "proportional_float" );
  124. CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" );
  125. CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255" );
  126. CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" );
  127. CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" );
  128. CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" );
  129. CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" );
  130. CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxClor", "SelectionSelectedBoxBg" );
  131. CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" );
  132. CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" );
  133. CPanelAnimationVar( int, m_iMaxSlots, "MaxSlots", "6" );
  134. CPanelAnimationVar( bool, m_bPlaySelectionSounds, "PlaySelectSounds", "1" );
  135. CTFImagePanel *m_pActiveWeaponBG;
  136. CItemModelPanel *m_pModelPanels[MAX_WEAPON_SLOTS];
  137. float m_flDemoStartTime;
  138. float m_flDemoModeChangeTime;
  139. int m_iDemoModeSlot;
  140. // HUDTYPE_PLUS weapon display
  141. int m_iSelectedBoxPosition; // in HUDTYPE_PLUS, the position within a slot
  142. int m_iSelectedSlot; // in HUDTYPE_PLUS, the slot we're currently moving in
  143. CPanelAnimationVar( float, m_flHorizWeaponSelectOffsetPoint, "WeaponBoxOffset", "0" );
  144. int m_iActiveSlot; // used to store the active slot to refresh the layout when using hud_fastswitch
  145. };
  146. DECLARE_HUDELEMENT( CHudWeaponSelection );
  147. DECLARE_HUD_COMMAND_NAME( CHudWeaponSelection, Slot11, "CHudWeaponSelection");
  148. DECLARE_HUD_COMMAND_NAME( CHudWeaponSelection, Slot12, "CHudWeaponSelection");
  149. HOOK_COMMAND( slot11, Slot11 );
  150. HOOK_COMMAND( slot12, Slot12 );
  151. void CHudWeaponSelection::UserCmd_Slot11(void)
  152. {
  153. SelectSlot( 11 );
  154. }
  155. void CHudWeaponSelection::UserCmd_Slot12(void)
  156. {
  157. SelectSlot( 12 );
  158. }
  159. using namespace vgui;
  160. //-----------------------------------------------------------------------------
  161. // Purpose: Constructor
  162. //-----------------------------------------------------------------------------
  163. CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection( pElementName ), EditablePanel( NULL, "HudWeaponSelection" )
  164. {
  165. vgui::Panel *pParent = g_pClientMode->GetViewport();
  166. SetParent( pParent );
  167. SetPostChildPaintEnabled( true );
  168. m_flDemoStartTime = -1;
  169. m_flDemoModeChangeTime = 0;
  170. m_iDemoModeSlot = -1;
  171. m_iActiveSlot = -1;
  172. ListenForGameEvent( "localplayer_changeclass" );
  173. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  174. {
  175. m_pModelPanels[i] = new CItemModelPanel( this, VarArgs( "modelpanel%d", i ) );
  176. }
  177. }
  178. CHudWeaponSelection::~CHudWeaponSelection( void )
  179. {
  180. }
  181. //-----------------------------------------------------------------------------
  182. // Purpose: sets up display for showing weapon pickup
  183. //-----------------------------------------------------------------------------
  184. void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
  185. {
  186. // add to pickup history
  187. CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
  188. if ( pHudHR )
  189. {
  190. pHudHR->AddToHistory( pWeapon );
  191. }
  192. }
  193. //-----------------------------------------------------------------------------
  194. // Purpose: updates animation status
  195. //-----------------------------------------------------------------------------
  196. void CHudWeaponSelection::OnThink()
  197. {
  198. float flSelectionTimeout = SELECTION_TIMEOUT_THRESHOLD;
  199. float flSelectionFadeoutTime = SELECTION_FADEOUT_TIME;
  200. if ( hud_fastswitch.GetBool() || (::input->IsSteamControllerActive()) )
  201. {
  202. flSelectionTimeout = FASTSWITCH_DISPLAY_TIMEOUT;
  203. flSelectionFadeoutTime = FASTSWITCH_FADEOUT_TIME;
  204. }
  205. // Time out after awhile of inactivity
  206. if ( ( gpGlobals->curtime - m_flSelectionTime ) > flSelectionTimeout )
  207. {
  208. // close
  209. if ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout + flSelectionFadeoutTime )
  210. {
  211. HideSelection();
  212. }
  213. }
  214. }
  215. //-----------------------------------------------------------------------------
  216. // Purpose: returns true if the panel should draw
  217. //-----------------------------------------------------------------------------
  218. bool CHudWeaponSelection::ShouldDraw()
  219. {
  220. bool bShouldDraw = ShouldDrawInternal();
  221. if ( !bShouldDraw && m_pActiveWeaponBG && m_pActiveWeaponBG->IsVisible() )
  222. {
  223. m_pActiveWeaponBG->SetVisible( false );
  224. }
  225. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  226. if ( pPlayer && pPlayer->m_Shared.InCond( TF_COND_HALLOWEEN_GHOST_MODE ) )
  227. {
  228. bShouldDraw = false;
  229. }
  230. if ( TFGameRules() && TFGameRules()->ShowMatchSummary() )
  231. {
  232. bShouldDraw = false;
  233. }
  234. if ( CTFMinigameLogic::GetMinigameLogic() && CTFMinigameLogic::GetMinigameLogic()->GetActiveMinigame() )
  235. {
  236. bShouldDraw = false;
  237. }
  238. return bShouldDraw;
  239. }
  240. //-----------------------------------------------------------------------------
  241. // Purpose:
  242. //-----------------------------------------------------------------------------
  243. bool CHudWeaponSelection::ShouldDrawInternal()
  244. {
  245. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  246. if ( !pPlayer )
  247. {
  248. if ( IsInSelectionMode() )
  249. {
  250. HideSelection();
  251. }
  252. return false;
  253. }
  254. // Make sure the player's allowed to switch weapons
  255. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  256. return false;
  257. if ( pPlayer->IsAlive() == false )
  258. return false;
  259. // we only show demo mode in hud_fastswitch 0
  260. if ( hud_fastswitch.GetInt() == 0 && !::input->IsSteamControllerActive() && ( m_iDemoModeSlot >= 0 || m_flDemoStartTime > 0 ) )
  261. {
  262. return true;
  263. }
  264. bool bret = CBaseHudWeaponSelection::ShouldDraw();
  265. if ( !bret )
  266. return false;
  267. // draw weapon selection a little longer if in fastswitch so we can see what we've selected
  268. if ( (hud_fastswitch.GetBool() || ::input->IsSteamControllerActive()) && ( gpGlobals->curtime - m_flSelectionTime ) < (FASTSWITCH_DISPLAY_TIMEOUT + FASTSWITCH_FADEOUT_TIME) )
  269. return true;
  270. return ( m_bSelectionVisible ) ? true : false;
  271. }
  272. //-----------------------------------------------------------------------------
  273. // Purpose:
  274. //-----------------------------------------------------------------------------
  275. void CHudWeaponSelection::Init()
  276. {
  277. CHudElement::Init();
  278. }
  279. //-----------------------------------------------------------------------------
  280. // Purpose:
  281. //-----------------------------------------------------------------------------
  282. void CHudWeaponSelection::LevelInit()
  283. {
  284. CHudElement::LevelInit();
  285. m_iMaxSlots = clamp( m_iMaxSlots, 0, MAX_WEAPON_SLOTS );
  286. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  287. {
  288. m_pModelPanels[i]->SetVisible( false );
  289. }
  290. InvalidateLayout( false, true );
  291. }
  292. //-----------------------------------------------------------------------------
  293. // Purpose:
  294. //-----------------------------------------------------------------------------
  295. void CHudWeaponSelection::LevelShutdown( void )
  296. {
  297. CHudElement::LevelShutdown();
  298. // Clear out our weaponry on level change
  299. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  300. {
  301. if ( m_pModelPanels[i] )
  302. {
  303. m_pModelPanels[i]->SetItem( NULL );
  304. }
  305. }
  306. }
  307. //-------------------------------------------------------------------------
  308. // Purpose: Calculates how many weapons slots need to be displayed
  309. //-------------------------------------------------------------------------
  310. int CHudWeaponSelection::GetNumVisibleSlots()
  311. {
  312. int nCount = 0;
  313. // iterate over all the weapon slots
  314. for ( int i = 0; i < m_iMaxSlots; i++ )
  315. {
  316. if ( GetFirstPos( i ) )
  317. {
  318. nCount++;
  319. }
  320. }
  321. return nCount;
  322. }
  323. //-----------------------------------------------------------------------------
  324. // Purpose: Figure out where to put the item model panels for this weapon
  325. // selection slot layout
  326. //-----------------------------------------------------------------------------
  327. void CHudWeaponSelection::ComputeSlotLayout( SlotLayout_t *rSlot, int nActiveSlot, int nSelectionMode )
  328. {
  329. int nNumSlots = GetNumVisibleSlots();
  330. if ( nNumSlots <= 0 )
  331. return;
  332. switch( nSelectionMode )
  333. {
  334. case HUDTYPE_CAROUSEL:
  335. case HUDTYPE_BUCKETS:
  336. case HUDTYPE_FASTSWITCH:
  337. {
  338. // calculate where to start drawing
  339. int nTotalHeight = ( nNumSlots - 1 ) * ( m_flSmallBoxTall + m_flBoxGap ) + m_flLargeBoxTall;
  340. int xStartPos = GetWide() - m_flBoxGap - m_flRightMargin;
  341. int ypos = ( GetTall() - nTotalHeight ) / 2;
  342. // iterate over all the weapon slots
  343. for ( int i = 0; i < m_iMaxSlots; i++ )
  344. {
  345. if ( i == nActiveSlot )
  346. {
  347. rSlot[i].wide = m_flLargeBoxWide;
  348. rSlot[i].tall = m_flLargeBoxTall;
  349. }
  350. else
  351. {
  352. rSlot[i].wide = m_flSmallBoxWide;
  353. rSlot[i].tall = m_flSmallBoxTall;
  354. }
  355. rSlot[i].x = xStartPos - ( rSlot[i].wide + m_flBoxGap );
  356. rSlot[i].y = ypos;
  357. ypos += ( rSlot[i].tall + m_flBoxGap );
  358. }
  359. }
  360. break;
  361. case HUDTYPE_PLUS:
  362. {
  363. // bucket style
  364. int screenCenterX = GetWide() / 2;
  365. int screenCenterY = GetTall() / 2; // Height isn't quite screen height, so adjust for center alignement
  366. // Modifiers for the four directions. Used to change the x and y offsets
  367. // of each box based on which bucket we're drawing. Bucket directions are
  368. // 0 = UP, 1 = RIGHT, 2 = DOWN, 3 = LEFT
  369. int xModifiers[] = { 0, 1, 0, -1, -1, 1 };
  370. int yModifiers[] = { -1, 0, 1, 0, 1, 1 };
  371. int boxWide = m_flPlusStyleBoxWide;
  372. int boxTall = m_flPlusStyleBoxTall;
  373. int boxWideSelected = m_flPlusStyleBoxWide * ( 1.f + m_flPlusStyleExpandPercent );
  374. int boxTallSelected = m_flPlusStyleBoxTall * ( 1.f + m_flPlusStyleExpandPercent );
  375. // Draw the four buckets
  376. for ( int i = 0; i < m_iMaxSlots; ++i )
  377. {
  378. if( i == nActiveSlot )
  379. {
  380. rSlot[i].wide = boxWideSelected;
  381. rSlot[i].tall = boxTallSelected;
  382. }
  383. else
  384. {
  385. rSlot[i].wide = boxWide;
  386. rSlot[i].tall = boxTall;
  387. }
  388. // Set the top left corner so the first box would be centered in the screen.
  389. int xPos = screenCenterX -( rSlot[i].wide / 2 );
  390. int yPos = screenCenterY -( rSlot[i].tall / 2 );
  391. // Offset the box position
  392. rSlot[ i ].x = xPos + ( rSlot[i].wide + 5 ) * xModifiers[ i ];
  393. rSlot[ i ].y = yPos + ( rSlot[i].tall + 5 ) * yModifiers[ i ];
  394. }
  395. }
  396. break;
  397. }
  398. }
  399. //-----------------------------------------------------------------------------
  400. // Purpose:
  401. //-----------------------------------------------------------------------------
  402. void CHudWeaponSelection::PerformLayout( void )
  403. {
  404. BaseClass::PerformLayout();
  405. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  406. if ( !pPlayer )
  407. return;
  408. int nNumSlots = GetNumVisibleSlots();
  409. if ( nNumSlots <= 0 )
  410. return;
  411. // find and display our current selection
  412. C_BaseCombatWeapon *pSelectedWeapon = NULL;
  413. int fastswitch = hud_fastswitch.GetInt();
  414. if ( ::input->IsSteamControllerActive() )
  415. {
  416. fastswitch = HUDTYPE_FASTSWITCH;
  417. }
  418. switch ( fastswitch )
  419. {
  420. case HUDTYPE_FASTSWITCH:
  421. pSelectedWeapon = pPlayer->GetActiveWeapon();
  422. break;
  423. default:
  424. pSelectedWeapon = GetSelectedWeapon();
  425. break;
  426. }
  427. if ( !pSelectedWeapon )
  428. return;
  429. // calculate where to start drawing
  430. int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1);
  431. SlotLayout_t rSlot[ MAX_WEAPON_SLOTS ];
  432. ComputeSlotLayout( rSlot, iActiveSlot, fastswitch );
  433. // iterate over all the weapon slots
  434. for ( int i = 0; i < m_iMaxSlots; i++ )
  435. {
  436. m_pModelPanels[i]->SetVisible( false );
  437. if ( i == iActiveSlot )
  438. {
  439. for ( int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++ )
  440. {
  441. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot(i, slotpos);
  442. if ( !pWeapon )
  443. continue;
  444. if ( !pWeapon->VisibleInWeaponSelection() )
  445. continue;
  446. m_pModelPanels[i]->SetItem( pWeapon->GetAttributeContainer()->GetItem() );
  447. m_pModelPanels[i]->SetSize( rSlot[i].wide, rSlot[ i ].tall );
  448. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  449. if ( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  450. {
  451. m_pModelPanels[i]->SetBorder( pScheme->GetBorder("TFFatLineBorderBlueBG") );
  452. }
  453. else
  454. {
  455. m_pModelPanels[i]->SetBorder( pScheme->GetBorder("TFFatLineBorderRedBG") );
  456. }
  457. m_pModelPanels[i]->SetPos( rSlot[i].x, rSlot[ i ].y );
  458. m_pModelPanels[i]->SetVisible( true );
  459. }
  460. }
  461. else
  462. {
  463. // check to see if there is a weapons in this bucket
  464. if ( GetFirstPos( i ) )
  465. {
  466. C_BaseCombatWeapon *pWeapon = GetFirstPos( i );
  467. if ( !pWeapon )
  468. continue;
  469. m_pModelPanels[i]->SetItem( pWeapon->GetAttributeContainer()->GetItem() );
  470. m_pModelPanels[i]->SetSize( rSlot[i].wide, rSlot[ i ].tall );
  471. vgui::IScheme *pScheme = vgui::scheme()->GetIScheme( GetScheme() );
  472. m_pModelPanels[i]->SetBorder( pScheme->GetBorder("TFFatLineBorder") );
  473. m_pModelPanels[i]->SetVisible( true );
  474. m_pModelPanels[i]->SetPos( rSlot[i].x, rSlot[ i ].y );
  475. }
  476. }
  477. }
  478. }
  479. //-------------------------------------------------------------------------
  480. // Purpose: draws the selection area
  481. //-------------------------------------------------------------------------
  482. void CHudWeaponSelection::PostChildPaint()
  483. {
  484. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  485. if ( !pPlayer )
  486. return;
  487. int fastswitch = hud_fastswitch.GetInt();
  488. if ( ::input->IsSteamControllerActive() )
  489. {
  490. fastswitch = HUDTYPE_FASTSWITCH;
  491. }
  492. if ( fastswitch == 0 )
  493. {
  494. // See if we should start the bucket demo
  495. if ( m_flDemoStartTime > 0 && m_flDemoStartTime < gpGlobals->curtime )
  496. {
  497. float flDemoTime = tf_weapon_select_demo_time.GetFloat();
  498. if ( flDemoTime > 0 )
  499. {
  500. m_iDemoModeSlot = 0;
  501. m_flDemoModeChangeTime = gpGlobals->curtime + flDemoTime;
  502. gHUD.LockRenderGroup( gHUD.LookupRenderGroupIndexByName( "weapon_selection" ) );
  503. }
  504. m_flDemoStartTime = -1;
  505. m_iSelectedSlot = m_iDemoModeSlot;
  506. InvalidateLayout();
  507. }
  508. // scroll through the slots for demo mode
  509. if ( m_iDemoModeSlot >= 0 && m_flDemoModeChangeTime < gpGlobals->curtime )
  510. {
  511. // Keep iterating until we find a slot that has a weapon in it
  512. while ( !GetFirstPos( ++m_iDemoModeSlot ) && m_iDemoModeSlot < m_iMaxSlots )
  513. {
  514. // blank
  515. }
  516. m_flDemoModeChangeTime = gpGlobals->curtime + tf_weapon_select_demo_time.GetFloat();
  517. InvalidateLayout();
  518. }
  519. if ( m_iDemoModeSlot >= m_iMaxSlots )
  520. {
  521. m_iDemoModeSlot = -1;
  522. gHUD.UnlockRenderGroup( gHUD.LookupRenderGroupIndexByName( "weapon_selection" ) );
  523. }
  524. }
  525. // find and display our current selection
  526. C_BaseCombatWeapon *pSelectedWeapon = NULL;
  527. switch ( fastswitch )
  528. {
  529. case HUDTYPE_FASTSWITCH:
  530. pSelectedWeapon = pPlayer->GetActiveWeapon();
  531. break;
  532. default:
  533. pSelectedWeapon = GetSelectedWeapon();
  534. break;
  535. }
  536. if ( !pSelectedWeapon )
  537. return;
  538. if ( fastswitch == 0 )
  539. {
  540. if ( m_iDemoModeSlot > -1 )
  541. {
  542. pSelectedWeapon = GetWeaponInSlot( m_iDemoModeSlot, 0 );
  543. m_iSelectedSlot = m_iDemoModeSlot;
  544. m_iSelectedBoxPosition = 0;
  545. }
  546. }
  547. if ( m_pActiveWeaponBG )
  548. {
  549. m_pActiveWeaponBG->SetVisible( fastswitch != HUDTYPE_PLUS && pSelectedWeapon != NULL );
  550. }
  551. int nNumSlots = GetNumVisibleSlots();
  552. if ( nNumSlots <= 0 )
  553. return;
  554. DrawSelection( pSelectedWeapon );
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose: Draws the vertical style weapon selection buckets, for PC/mousewheel controls
  558. //-----------------------------------------------------------------------------
  559. void CHudWeaponSelection::DrawSelection( C_BaseCombatWeapon *pSelectedWeapon )
  560. {
  561. // if we're not supposed to draw the selection, the don't draw the selection
  562. if( !m_bSelectionVisible )
  563. return;
  564. C_TFPlayer *pPlayer = C_TFPlayer::GetLocalTFPlayer();
  565. if ( !pPlayer )
  566. return;
  567. int nNumSlots = GetNumVisibleSlots();
  568. if ( nNumSlots <= 0 )
  569. return;
  570. // calculate where to start drawing
  571. int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1);
  572. int nFastswitchMode = hud_fastswitch.GetInt();
  573. if ( ::input->IsSteamControllerActive() )
  574. {
  575. nFastswitchMode = HUDTYPE_FASTSWITCH;
  576. }
  577. if ( nFastswitchMode == HUDTYPE_FASTSWITCH )
  578. {
  579. if ( m_iActiveSlot != iActiveSlot )
  580. {
  581. m_iActiveSlot = iActiveSlot;
  582. InvalidateLayout( true );
  583. }
  584. }
  585. // draw the bucket set
  586. // iterate over all the weapon slots
  587. for ( int i = 0; i < m_iMaxSlots; i++ )
  588. {
  589. int xpos, ypos;
  590. m_pModelPanels[i]->GetPos( xpos, ypos );
  591. int wide, tall;
  592. m_pModelPanels[i]->GetSize( wide, tall );
  593. if ( i == iActiveSlot )
  594. {
  595. bool bFirstItem = true;
  596. for ( int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++ )
  597. {
  598. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot(i, slotpos);
  599. if ( !pWeapon )
  600. continue;
  601. if ( !pWeapon->VisibleInWeaponSelection() )
  602. continue;
  603. if ( !pWeapon->CanBeSelected() )
  604. {
  605. int msgX = xpos + ( m_flLargeBoxWide * 0.5 );
  606. int msgY = ypos + (int)m_flErrorYPos;
  607. Color ammoColor = Color( 255, 0, 0, 255 );
  608. wchar_t *pText = g_pVGuiLocalize->Find( "#TF_OUT_OF_AMMO" );
  609. DrawString( pText, msgX, msgY, ammoColor, true );
  610. }
  611. if ( pWeapon == pSelectedWeapon || ( m_iDemoModeSlot == i ) )
  612. {
  613. // draw the number
  614. int shortcut = bFirstItem ? i + 1 : -1;
  615. if ( IsPC() && shortcut >= 0 && nFastswitchMode != HUDTYPE_PLUS )
  616. {
  617. Color numberColor = m_NumberColor;
  618. numberColor[3] *= m_flSelectionAlphaOverride / 255.0f;
  619. surface()->DrawSetTextColor(numberColor);
  620. surface()->DrawSetTextFont(m_hNumberFont);
  621. wchar_t wch = '0' + shortcut;
  622. surface()->DrawSetTextPos( xpos + wide - XRES(5) - m_flSelectionNumberXPos, ypos + YRES(5) + m_flSelectionNumberYPos );
  623. surface()->DrawUnicodeChar(wch);
  624. }
  625. }
  626. bFirstItem = false;
  627. }
  628. }
  629. else
  630. {
  631. // check to see if there is a weapons in this bucket
  632. if ( GetFirstPos( i ) )
  633. {
  634. C_BaseCombatWeapon *pWeapon = GetFirstPos( i );
  635. if ( !pWeapon )
  636. continue;
  637. // draw the number
  638. if ( IsPC() && nFastswitchMode != HUDTYPE_PLUS )
  639. {
  640. int x = xpos + XRES(5);
  641. int y = ypos + YRES(5);
  642. Color numberColor = m_NumberColor;
  643. numberColor[3] *= m_flAlphaOverride / 255.0f;
  644. surface()->DrawSetTextColor(numberColor);
  645. surface()->DrawSetTextFont(m_hNumberFont);
  646. wchar_t wch = '0' + i + 1;
  647. surface()->DrawSetTextPos(x + m_flSmallBoxWide - XRES(10) - m_flSelectionNumberXPos, y + m_flSelectionNumberYPos);
  648. surface()->DrawUnicodeChar(wch);
  649. }
  650. }
  651. }
  652. }
  653. }
  654. //-----------------------------------------------------------------------------
  655. // Purpose:
  656. //-----------------------------------------------------------------------------
  657. void CHudWeaponSelection::DrawWeaponTexture( C_TFPlayer *pPlayer, C_BaseCombatWeapon *pWeapon, int xpos, int ypos, float flLargeBoxWide, float flLargeBoxTall )
  658. {
  659. // draw icon
  660. const CHudTexture *pTexture = pWeapon->GetSpriteInactive(); // red team
  661. if ( pPlayer )
  662. {
  663. if ( pPlayer->GetTeamNumber() == TF_TEAM_BLUE )
  664. {
  665. pTexture = pWeapon->GetSpriteActive();
  666. }
  667. }
  668. if ( pTexture )
  669. {
  670. Color col( 255, 255, 255, 255 );
  671. pTexture->DrawSelf( xpos, ypos, flLargeBoxWide, flLargeBoxTall, col );
  672. }
  673. }
  674. //-----------------------------------------------------------------------------
  675. // Purpose:
  676. //-----------------------------------------------------------------------------
  677. void CHudWeaponSelection::DrawString( wchar_t *text, int xpos, int ypos, Color col, bool bCenter )
  678. {
  679. surface()->DrawSetTextColor( col );
  680. surface()->DrawSetTextFont( m_hTextFont );
  681. // count the position
  682. int slen = 0, charCount = 0, maxslen = 0;
  683. {
  684. for (wchar_t *pch = text; *pch != 0; pch++)
  685. {
  686. if (*pch == '\n')
  687. {
  688. // newline character, drop to the next line
  689. if (slen > maxslen)
  690. {
  691. maxslen = slen;
  692. }
  693. slen = 0;
  694. }
  695. else if (*pch == '\r')
  696. {
  697. // do nothing
  698. }
  699. else
  700. {
  701. slen += surface()->GetCharacterWidth( m_hTextFont, *pch );
  702. charCount++;
  703. }
  704. }
  705. }
  706. if (slen > maxslen)
  707. {
  708. maxslen = slen;
  709. }
  710. int x = xpos;
  711. if ( bCenter )
  712. {
  713. x = xpos - slen * 0.5;
  714. }
  715. surface()->DrawSetTextPos( x, ypos );
  716. // adjust the charCount by the scan amount
  717. charCount *= m_flTextScan;
  718. for (wchar_t *pch = text; charCount > 0; pch++)
  719. {
  720. if (*pch == '\n')
  721. {
  722. // newline character, move to the next line
  723. surface()->DrawSetTextPos( x + ((m_flLargeBoxWide - slen) / 2), ypos + (surface()->GetFontTall(m_hTextFont) * 1.1f));
  724. }
  725. else if (*pch == '\r')
  726. {
  727. // do nothing
  728. }
  729. else
  730. {
  731. surface()->DrawUnicodeChar(*pch);
  732. charCount--;
  733. }
  734. }
  735. }
  736. //-----------------------------------------------------------------------------
  737. // Purpose: hud scheme settings
  738. //-----------------------------------------------------------------------------
  739. void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
  740. {
  741. BaseClass::ApplySchemeSettings(pScheme);
  742. SetPaintBackgroundEnabled(false);
  743. // set our size
  744. int screenWide, screenTall;
  745. int x, y;
  746. GetPos(x, y);
  747. GetHudSize(screenWide, screenTall);
  748. SetBounds(0, 0, screenWide, screenTall);
  749. // load control settings...
  750. LoadControlSettings( "resource/UI/HudWeaponSelection.res" );
  751. m_pActiveWeaponBG = dynamic_cast<CTFImagePanel*>( FindChildByName("ActiveWeapon") );
  752. if ( m_pActiveWeaponBG )
  753. {
  754. m_pActiveWeaponBG->SetVisible( false );
  755. }
  756. }
  757. //-----------------------------------------------------------------------------
  758. // Purpose: Opens weapon selection control
  759. //-----------------------------------------------------------------------------
  760. void CHudWeaponSelection::OpenSelection( void )
  761. {
  762. Assert(!IsInSelectionMode());
  763. InvalidateLayout();
  764. CBaseHudWeaponSelection::OpenSelection();
  765. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("OpenWeaponSelectionMenu");
  766. m_iSelectedBoxPosition = 0;
  767. m_iSelectedSlot = -1;
  768. }
  769. //-----------------------------------------------------------------------------
  770. // Purpose: Closes weapon selection control immediately
  771. //-----------------------------------------------------------------------------
  772. void CHudWeaponSelection::HideSelection( void )
  773. {
  774. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  775. {
  776. if ( m_pModelPanels[i] )
  777. {
  778. m_pModelPanels[i]->SetVisible( false );
  779. }
  780. }
  781. m_flSelectionTime = 0;
  782. CBaseHudWeaponSelection::HideSelection();
  783. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("CloseWeaponSelectionMenu");
  784. }
  785. //-----------------------------------------------------------------------------
  786. // Purpose: Returns the next available weapon item in the weapon selection
  787. //-----------------------------------------------------------------------------
  788. C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  789. {
  790. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  791. if ( !pPlayer )
  792. return NULL;
  793. C_BaseCombatWeapon *pNextWeapon = NULL;
  794. // search all the weapons looking for the closest next
  795. int iLowestNextSlot = MAX_WEAPON_SLOTS;
  796. int iLowestNextPosition = MAX_WEAPON_POSITIONS;
  797. for ( int i = 0; i < MAX_WEAPONS; i++ )
  798. {
  799. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  800. if ( !pWeapon )
  801. continue;
  802. if ( pWeapon->VisibleInWeaponSelection() )
  803. {
  804. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  805. // see if this weapon is further ahead in the selection list
  806. if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) )
  807. {
  808. // see if this weapon is closer than the current lowest
  809. if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) )
  810. {
  811. iLowestNextSlot = weaponSlot;
  812. iLowestNextPosition = weaponPosition;
  813. pNextWeapon = pWeapon;
  814. }
  815. }
  816. }
  817. }
  818. return pNextWeapon;
  819. }
  820. //-----------------------------------------------------------------------------
  821. // Purpose: Returns the prior available weapon item in the weapon selection
  822. //-----------------------------------------------------------------------------
  823. C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  824. {
  825. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  826. if ( !pPlayer )
  827. return NULL;
  828. C_BaseCombatWeapon *pPrevWeapon = NULL;
  829. // search all the weapons looking for the closest next
  830. int iLowestPrevSlot = -1;
  831. int iLowestPrevPosition = -1;
  832. for ( int i = 0; i < MAX_WEAPONS; i++ )
  833. {
  834. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  835. if ( !pWeapon )
  836. continue;
  837. if ( pWeapon->VisibleInWeaponSelection() )
  838. {
  839. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  840. // see if this weapon is further ahead in the selection list
  841. if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) )
  842. {
  843. // see if this weapon is closer than the current lowest
  844. if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) )
  845. {
  846. iLowestPrevSlot = weaponSlot;
  847. iLowestPrevPosition = weaponPosition;
  848. pPrevWeapon = pWeapon;
  849. }
  850. }
  851. }
  852. }
  853. return pPrevWeapon;
  854. }
  855. //-----------------------------------------------------------------------------
  856. // Purpose: Moves the selection to the next item in the menu
  857. //-----------------------------------------------------------------------------
  858. void CHudWeaponSelection::CycleToNextWeapon( void )
  859. {
  860. // Get the local player.
  861. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  862. if ( !pPlayer )
  863. return;
  864. if ( pPlayer->IsAlive() == false )
  865. return;
  866. // PASSTIME don't CycleToNextWeapon if it's not allowed
  867. if ( !pPlayer->IsAllowedToSwitchWeapons() )
  868. return;
  869. C_BaseCombatWeapon *pNextWeapon = NULL;
  870. if ( IsInSelectionMode() )
  871. {
  872. // find the next selection spot
  873. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  874. if ( !pWeapon )
  875. return;
  876. pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  877. }
  878. else
  879. {
  880. // open selection at the current place
  881. pNextWeapon = pPlayer->GetActiveWeapon();
  882. if ( pNextWeapon )
  883. {
  884. pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  885. }
  886. }
  887. if ( !pNextWeapon )
  888. {
  889. // wrap around back to start
  890. pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1);
  891. }
  892. if ( pNextWeapon )
  893. {
  894. SetSelectedWeapon( pNextWeapon );
  895. if ( !IsInSelectionMode() )
  896. {
  897. OpenSelection();
  898. }
  899. InvalidateLayout();
  900. // cancel demo mode
  901. m_iDemoModeSlot = -1;
  902. m_flDemoStartTime = -1;
  903. // Play the "cycle to next weapon" sound
  904. if( m_bPlaySelectionSounds )
  905. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  906. }
  907. }
  908. //-----------------------------------------------------------------------------
  909. // Purpose: Moves the selection to the previous item in the menu
  910. //-----------------------------------------------------------------------------
  911. void CHudWeaponSelection::CycleToPrevWeapon( void )
  912. {
  913. // Get the local player.
  914. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  915. if ( !pPlayer )
  916. return;
  917. if ( pPlayer->IsAlive() == false )
  918. return;
  919. // PASSTIME don't CycleToNextWeapon if it's not allowed
  920. if ( !pPlayer->IsAllowedToSwitchWeapons() )
  921. return;
  922. C_BaseCombatWeapon *pNextWeapon = NULL;
  923. if ( IsInSelectionMode() )
  924. {
  925. // find the next selection spot
  926. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  927. if ( !pWeapon )
  928. return;
  929. pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  930. }
  931. else
  932. {
  933. // open selection at the current place
  934. pNextWeapon = pPlayer->GetActiveWeapon();
  935. if ( pNextWeapon )
  936. {
  937. pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  938. }
  939. }
  940. if ( !pNextWeapon )
  941. {
  942. // wrap around back to end of weapon list
  943. pNextWeapon = FindPrevWeaponInWeaponSelection(MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS);
  944. }
  945. if ( pNextWeapon )
  946. {
  947. SetSelectedWeapon( pNextWeapon );
  948. if ( !IsInSelectionMode() )
  949. {
  950. OpenSelection();
  951. }
  952. InvalidateLayout();
  953. // cancel demo mode
  954. m_iDemoModeSlot = -1;
  955. m_flDemoStartTime = -1;
  956. // Play the "cycle to next weapon" sound
  957. if( m_bPlaySelectionSounds )
  958. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  959. }
  960. }
  961. //-----------------------------------------------------------------------------
  962. // Purpose: returns the weapon in the specified slot
  963. //-----------------------------------------------------------------------------
  964. C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
  965. {
  966. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  967. if ( !player )
  968. return NULL;
  969. for ( int i = 0; i < MAX_WEAPONS; i++ )
  970. {
  971. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  972. if ( pWeapon == NULL )
  973. continue;
  974. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos )
  975. return pWeapon;
  976. }
  977. return NULL;
  978. }
  979. C_BaseCombatWeapon *CHudWeaponSelection::GetSelectedWeapon( void )
  980. {
  981. if ( hud_fastswitch.GetInt() == 0 && !::input->IsSteamControllerActive() && m_iDemoModeSlot >= 0 )
  982. {
  983. C_BaseCombatWeapon *pWeapon = GetFirstPos( m_iDemoModeSlot );
  984. return pWeapon;
  985. }
  986. else
  987. {
  988. return m_hSelectedWeapon;
  989. }
  990. }
  991. void CHudWeaponSelection::FireGameEvent( IGameEvent *event )
  992. {
  993. const char * type = event->GetName();
  994. if ( Q_strcmp(type, "localplayer_changeclass") == 0 )
  995. {
  996. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  997. {
  998. if ( m_pModelPanels[i] )
  999. {
  1000. m_pModelPanels[i]->SetVisible( false );
  1001. }
  1002. }
  1003. int nUpdateType = event->GetInt( "updateType" );
  1004. bool bIsCreationUpdate = ( nUpdateType == DATA_UPDATE_CREATED );
  1005. // Don't demo selection in minmode
  1006. ConVarRef cl_hud_minmode( "cl_hud_minmode", true );
  1007. if ( !cl_hud_minmode.IsValid() || cl_hud_minmode.GetBool() == false )
  1008. {
  1009. if ( !bIsCreationUpdate )
  1010. {
  1011. m_flDemoStartTime = gpGlobals->curtime + tf_weapon_select_demo_start_delay.GetFloat();
  1012. }
  1013. }
  1014. }
  1015. else
  1016. {
  1017. CHudElement::FireGameEvent( event );
  1018. }
  1019. }
  1020. //-----------------------------------------------------------------------------
  1021. // Purpose: Opens the next weapon in the slot
  1022. //-----------------------------------------------------------------------------
  1023. void CHudWeaponSelection::FastWeaponSwitch( int iWeaponSlot )
  1024. {
  1025. // get the slot the player's weapon is in
  1026. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1027. if ( !pPlayer )
  1028. return;
  1029. // see where we should start selection
  1030. int iPosition = -1;
  1031. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  1032. if ( pActiveWeapon && pActiveWeapon->GetSlot() == iWeaponSlot )
  1033. {
  1034. // start after this weapon
  1035. iPosition = pActiveWeapon->GetPosition();
  1036. }
  1037. C_BaseCombatWeapon *pNextWeapon = NULL;
  1038. // search for the weapon after the current one
  1039. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, iPosition);
  1040. // make sure it's in the same bucket
  1041. if ( !pNextWeapon || pNextWeapon->GetSlot() != iWeaponSlot )
  1042. {
  1043. // just look for any weapon in this slot
  1044. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, -1);
  1045. }
  1046. // see if we found a weapon that's different from the current and in the selected slot
  1047. if ( pNextWeapon && pNextWeapon != pActiveWeapon && pNextWeapon->GetSlot() == iWeaponSlot )
  1048. {
  1049. // select the new weapon
  1050. ::input->MakeWeaponSelection( pNextWeapon );
  1051. }
  1052. else if ( pNextWeapon != pActiveWeapon )
  1053. {
  1054. // error sound
  1055. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  1056. }
  1057. // kill any fastswitch display
  1058. m_flSelectionTime = 0.0f;
  1059. }
  1060. //-----------------------------------------------------------------------------
  1061. // Purpose: Opens the next weapon in the slot
  1062. //-----------------------------------------------------------------------------
  1063. void CHudWeaponSelection::PlusTypeFastWeaponSwitch( int iWeaponSlot, bool *pbPlaySwitchSound )
  1064. {
  1065. // get the slot the player's weapon is in
  1066. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1067. if ( !pPlayer )
  1068. return;
  1069. int newSlot = m_iSelectedSlot;
  1070. // Changing slot number does not necessarily mean we need to change the slot - the player could be
  1071. // scrolling through the same slot but in the opposite direction. Slot pairs are 0,2 and 1,3 - so
  1072. // compare the 0 bits to see if we're within a pair. Otherwise, reset the box to the zero position.
  1073. if ( -1 == m_iSelectedSlot || ( ( m_iSelectedSlot ^ iWeaponSlot ) & 1 ) )
  1074. {
  1075. // Changing vertical/horizontal direction. Reset the selected box position to zero.
  1076. m_iSelectedBoxPosition = 0;
  1077. m_iSelectedSlot = iWeaponSlot;
  1078. }
  1079. else
  1080. {
  1081. // Still in the same horizontal/vertical direction. Determine which way we're moving in the slot.
  1082. int increment = 1;
  1083. if ( m_iSelectedSlot != iWeaponSlot )
  1084. {
  1085. // Decrementing within the slot. If we're at the zero position in this slot,
  1086. // jump to the zero position of the opposite slot. This also counts as our increment.
  1087. increment = -1;
  1088. if ( 0 == m_iSelectedBoxPosition )
  1089. {
  1090. newSlot = ( m_iSelectedSlot + 2 ) % 4;
  1091. increment = 0;
  1092. }
  1093. }
  1094. // Find out of the box position is at the end of the slot
  1095. int lastSlotPos = -1;
  1096. for ( int slotPos = 0; slotPos < MAX_WEAPON_POSITIONS; ++slotPos )
  1097. {
  1098. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( newSlot, slotPos );
  1099. if ( pWeapon )
  1100. {
  1101. lastSlotPos = slotPos;
  1102. }
  1103. }
  1104. // Increment/Decrement the selected box position
  1105. if ( m_iSelectedBoxPosition + increment <= lastSlotPos )
  1106. {
  1107. m_iSelectedBoxPosition += increment;
  1108. m_iSelectedSlot = newSlot;
  1109. }
  1110. else
  1111. {
  1112. // error sound
  1113. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  1114. *pbPlaySwitchSound = false;
  1115. return;
  1116. }
  1117. }
  1118. // Select the weapon in this position
  1119. bool bWeaponSelected = false;
  1120. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  1121. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_iSelectedSlot, m_iSelectedBoxPosition );
  1122. if ( pWeapon && CanBeSelectedInHUD( pWeapon ) )
  1123. {
  1124. if ( pWeapon != pActiveWeapon )
  1125. {
  1126. // Select the new weapon
  1127. ::input->MakeWeaponSelection( pWeapon );
  1128. SetSelectedWeapon( pWeapon );
  1129. bWeaponSelected = true;
  1130. }
  1131. }
  1132. if ( !bWeaponSelected )
  1133. {
  1134. // Still need to set this to make hud display appear
  1135. SetSelectedWeapon( pPlayer->GetActiveWeapon() );
  1136. }
  1137. }
  1138. //-----------------------------------------------------------------------------
  1139. // Purpose: Moves selection to the specified slot
  1140. //-----------------------------------------------------------------------------
  1141. void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
  1142. {
  1143. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  1144. --iSlot;
  1145. // Get the local player.
  1146. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1147. if ( !pPlayer )
  1148. return;
  1149. // Don't try and read past our possible number of slots
  1150. if ( iSlot >= MAX_WEAPON_SLOTS )
  1151. return;
  1152. // Make sure the player's allowed to switch weapons
  1153. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  1154. return;
  1155. bool bPlaySwitchSound = true;
  1156. int nFastswitchMode = hud_fastswitch.GetInt();
  1157. if ( ::input->IsSteamControllerActive() )
  1158. {
  1159. nFastswitchMode = HUDTYPE_FASTSWITCH;
  1160. }
  1161. switch( nFastswitchMode )
  1162. {
  1163. case HUDTYPE_FASTSWITCH:
  1164. {
  1165. FastWeaponSwitch( iSlot );
  1166. return;
  1167. }
  1168. case HUDTYPE_PLUS:
  1169. PlusTypeFastWeaponSwitch( iSlot, &bPlaySwitchSound );
  1170. // ------------------------------------------------------
  1171. // FALLTHROUGH! Plus and buckets both use the item model
  1172. // panels so fix them up in both cases.
  1173. // ------------------------------------------------------
  1174. case HUDTYPE_BUCKETS:
  1175. {
  1176. int slotPos = 0;
  1177. C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon();
  1178. // start later in the list
  1179. if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot )
  1180. {
  1181. slotPos = pActiveWeapon->GetPosition() + 1;
  1182. }
  1183. // find the weapon in this slot
  1184. pActiveWeapon = GetNextActivePos( iSlot, slotPos );
  1185. if ( !pActiveWeapon )
  1186. {
  1187. pActiveWeapon = GetNextActivePos( iSlot, 0 );
  1188. }
  1189. if ( pActiveWeapon != NULL )
  1190. {
  1191. if ( !IsInSelectionMode() )
  1192. {
  1193. // open the weapon selection
  1194. OpenSelection();
  1195. }
  1196. InvalidateLayout();
  1197. // Mark the change
  1198. SetSelectedWeapon( pActiveWeapon );
  1199. m_iDemoModeSlot = -1;
  1200. m_flDemoStartTime = -1;
  1201. }
  1202. }
  1203. break;
  1204. default:
  1205. break;
  1206. }
  1207. if( m_bPlaySelectionSounds && bPlaySwitchSound )
  1208. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  1209. }
  1210. //-----------------------------------------------------------------------------
  1211. // Purpose: Menu Selection Code
  1212. //-----------------------------------------------------------------------------
  1213. void CHudWeaponSelection::SelectSlot( int iSlot )
  1214. {
  1215. // A menu may be overriding weapon selection commands
  1216. if ( HandleHudMenuInput( iSlot ) )
  1217. {
  1218. return;
  1219. }
  1220. // If we're in observer mode, see if the spectator GUI wants to use it
  1221. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1222. if ( pPlayer && pPlayer->IsObserver() )
  1223. {
  1224. CTFSpectatorGUI *pPanel = (CTFSpectatorGUI*)gViewPortInterface->FindPanelByName( PANEL_SPECGUI );
  1225. if ( pPanel )
  1226. {
  1227. pPanel->SelectSpec( iSlot );
  1228. }
  1229. return;
  1230. }
  1231. // If we're not allowed to draw, ignore weapon selections
  1232. if ( !CHudElement::ShouldDraw() )
  1233. {
  1234. return;
  1235. }
  1236. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  1237. if ( !IsInSelectionMode() && ( iSlot - 1 >= MAX_WEAPON_SLOTS ) )
  1238. {
  1239. OpenSelection();
  1240. }
  1241. UpdateSelectionTime();
  1242. SelectWeaponSlot( iSlot );
  1243. }
  1244. //-----------------------------------------------------------------------------
  1245. // Purpose: Menu Selection Code
  1246. //-----------------------------------------------------------------------------
  1247. void CHudWeaponSelection::SwitchToLastWeapon()
  1248. {
  1249. C_TFPlayer *pTFPlayer = ToTFPlayer( C_BasePlayer::GetLocalPlayer() );
  1250. if ( !pTFPlayer )
  1251. return;
  1252. if (TFGameRules() && TFGameRules()->IsPasstimeMode() && pTFPlayer->m_Shared.HasPasstimeBall() )
  1253. return;
  1254. CBaseHudWeaponSelection::SwitchToLastWeapon();
  1255. }