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.

1525 lines
43 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 "input.h"
  11. #include "../hud_crosshair.h"
  12. #include "VGuiMatSurface/IMatSystemSurface.h"
  13. #include <KeyValues.h>
  14. #include <vgui/IScheme.h>
  15. #include <vgui/ISurface.h>
  16. #include <vgui/ISystem.h>
  17. #include <vgui_controls/AnimationController.h>
  18. #include <vgui_controls/Panel.h>
  19. #include "vgui/ILocalize.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. ConVar hud_showemptyweaponslots( "hud_showemptyweaponslots", "1", FCVAR_ARCHIVE, "Shows slots for missing weapons when recieving weapons out of order" );
  23. #define SELECTION_TIMEOUT_THRESHOLD 0.5f // Seconds
  24. #define SELECTION_FADEOUT_TIME 0.75f
  25. #define PLUS_DISPLAY_TIMEOUT 0.5f // Seconds
  26. #define PLUS_FADEOUT_TIME 0.75f
  27. #define FASTSWITCH_DISPLAY_TIMEOUT 1.5f
  28. #define FASTSWITCH_FADEOUT_TIME 1.5f
  29. #define CAROUSEL_SMALL_DISPLAY_ALPHA 200.0f
  30. #define FASTSWITCH_SMALL_DISPLAY_ALPHA 160.0f
  31. #define MAX_CAROUSEL_SLOTS 5
  32. //-----------------------------------------------------------------------------
  33. // Purpose: hl2 weapon selection hud element
  34. //-----------------------------------------------------------------------------
  35. class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel
  36. {
  37. DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel );
  38. public:
  39. CHudWeaponSelection(const char *pElementName );
  40. virtual bool ShouldDraw();
  41. virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon );
  42. virtual void CycleToNextWeapon( void );
  43. virtual void CycleToPrevWeapon( void );
  44. virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
  45. virtual void SelectWeaponSlot( int iSlot );
  46. virtual C_BaseCombatWeapon *GetSelectedWeapon( void )
  47. {
  48. return m_hSelectedWeapon;
  49. }
  50. virtual void OpenSelection( void );
  51. virtual void HideSelection( void );
  52. virtual void LevelInit();
  53. protected:
  54. virtual void OnThink();
  55. virtual void Paint();
  56. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  57. virtual bool IsWeaponSelectable()
  58. {
  59. if (IsInSelectionMode())
  60. return true;
  61. return false;
  62. }
  63. virtual void SetWeaponSelected()
  64. {
  65. CBaseHudWeaponSelection::SetWeaponSelected();
  66. switch( hud_fastswitch.GetInt() )
  67. {
  68. case HUDTYPE_FASTSWITCH:
  69. case HUDTYPE_CAROUSEL:
  70. ActivateFastswitchWeaponDisplay( GetSelectedWeapon() );
  71. break;
  72. case HUDTYPE_PLUS:
  73. ActivateWeaponHighlight( GetSelectedWeapon() );
  74. break;
  75. default:
  76. // do nothing
  77. break;
  78. }
  79. }
  80. private:
  81. C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  82. C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  83. void DrawLargeWeaponBox( C_BaseCombatWeapon *pWeapon, bool bSelected, int x, int y, int wide, int tall, Color color, float alpha, int number );
  84. void ActivateFastswitchWeaponDisplay( C_BaseCombatWeapon *pWeapon );
  85. void ActivateWeaponHighlight( C_BaseCombatWeapon *pWeapon );
  86. float GetWeaponBoxAlpha( bool bSelected );
  87. int GetLastPosInSlot( int iSlot ) const;
  88. void FastWeaponSwitch( int iWeaponSlot );
  89. void PlusTypeFastWeaponSwitch( int iWeaponSlot );
  90. virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon )
  91. {
  92. m_hSelectedWeapon = pWeapon;
  93. }
  94. virtual void SetSelectedSlot( int slot )
  95. {
  96. m_iSelectedSlot = slot;
  97. }
  98. void SetSelectedSlideDir( int dir )
  99. {
  100. m_iSelectedSlideDir = dir;
  101. }
  102. void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number);
  103. CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
  104. CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" );
  105. CPanelAnimationVar( float, m_flBlur, "Blur", "0" );
  106. CPanelAnimationVarAliasType( float, m_flSmallBoxSize, "SmallBoxSize", "32", "proportional_float" );
  107. CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" );
  108. CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" );
  109. CPanelAnimationVarAliasType( float, m_flMediumBoxWide, "MediumBoxWide", "75", "proportional_float" );
  110. CPanelAnimationVarAliasType( float, m_flMediumBoxTall, "MediumBoxTall", "50", "proportional_float" );
  111. CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "12", "proportional_float" );
  112. CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" );
  113. CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" );
  114. CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" );
  115. CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "0" );
  116. CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "0" );
  117. CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" );
  118. CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" );
  119. CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" );
  120. CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" );
  121. CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxColor", "SelectionSelectedBoxBg" );
  122. CPanelAnimationVar( Color, m_SelectedFgColor, "SelectedFgColor", "FgColor" );
  123. CPanelAnimationVar( Color, m_BrightBoxColor, "SelectedFgColor", "BgColor" );
  124. CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" );
  125. CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" );
  126. bool m_bFadingOut;
  127. // fastswitch weapon display
  128. struct WeaponBox_t
  129. {
  130. int m_iSlot;
  131. int m_iSlotPos;
  132. };
  133. CUtlVector<WeaponBox_t> m_WeaponBoxes;
  134. int m_iSelectedWeaponBox;
  135. int m_iSelectedSlideDir;
  136. int m_iSelectedBoxPosition;
  137. int m_iSelectedSlot;
  138. C_BaseCombatWeapon *m_pLastWeapon;
  139. CPanelAnimationVar( float, m_flHorizWeaponSelectOffsetPoint, "WeaponBoxOffset", "0" );
  140. };
  141. DECLARE_HUDELEMENT( CHudWeaponSelection );
  142. using namespace vgui;
  143. //-----------------------------------------------------------------------------
  144. // Purpose: Constructor
  145. //-----------------------------------------------------------------------------
  146. CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection")
  147. {
  148. vgui::Panel *pParent = g_pClientMode->GetViewport();
  149. SetParent( pParent );
  150. m_bFadingOut = false;
  151. }
  152. //-----------------------------------------------------------------------------
  153. // Purpose: sets up display for showing weapon pickup
  154. //-----------------------------------------------------------------------------
  155. void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
  156. {
  157. // add to pickup history
  158. CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
  159. if ( pHudHR )
  160. {
  161. pHudHR->AddToHistory( pWeapon );
  162. }
  163. }
  164. //-----------------------------------------------------------------------------
  165. // Purpose: updates animation status
  166. //-----------------------------------------------------------------------------
  167. void CHudWeaponSelection::OnThink( void )
  168. {
  169. float flSelectionTimeout = SELECTION_TIMEOUT_THRESHOLD;
  170. float flSelectionFadeoutTime = SELECTION_FADEOUT_TIME;
  171. if ( hud_fastswitch.GetBool() )
  172. {
  173. flSelectionTimeout = FASTSWITCH_DISPLAY_TIMEOUT;
  174. flSelectionFadeoutTime = FASTSWITCH_FADEOUT_TIME;
  175. }
  176. // Time out after awhile of inactivity
  177. if ( ( gpGlobals->curtime - m_flSelectionTime ) > flSelectionTimeout )
  178. {
  179. if (!m_bFadingOut)
  180. {
  181. // start fading out
  182. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FadeOutWeaponSelectionMenu" );
  183. m_bFadingOut = true;
  184. }
  185. else if ( gpGlobals->curtime - m_flSelectionTime > flSelectionTimeout + flSelectionFadeoutTime )
  186. {
  187. // finished fade, close
  188. HideSelection();
  189. }
  190. }
  191. else if (m_bFadingOut)
  192. {
  193. // stop us fading out, show the animation again
  194. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "OpenWeaponSelectionMenu" );
  195. m_bFadingOut = false;
  196. }
  197. }
  198. //-----------------------------------------------------------------------------
  199. // Purpose: returns true if the panel should draw
  200. //-----------------------------------------------------------------------------
  201. bool CHudWeaponSelection::ShouldDraw()
  202. {
  203. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  204. if ( !pPlayer )
  205. {
  206. if ( IsInSelectionMode() )
  207. {
  208. HideSelection();
  209. }
  210. return false;
  211. }
  212. bool bret = CBaseHudWeaponSelection::ShouldDraw();
  213. if ( !bret )
  214. return false;
  215. // draw weapon selection a little longer if in fastswitch so we can see what we've selected
  216. if ( hud_fastswitch.GetBool() && ( gpGlobals->curtime - m_flSelectionTime ) < (FASTSWITCH_DISPLAY_TIMEOUT + FASTSWITCH_FADEOUT_TIME) )
  217. return true;
  218. return ( m_bSelectionVisible ) ? true : false;
  219. }
  220. //-----------------------------------------------------------------------------
  221. // Purpose:
  222. //-----------------------------------------------------------------------------
  223. void CHudWeaponSelection::LevelInit()
  224. {
  225. CHudElement::LevelInit();
  226. m_iSelectedWeaponBox = -1;
  227. m_iSelectedSlideDir = 0;
  228. m_pLastWeapon = NULL;
  229. }
  230. //-----------------------------------------------------------------------------
  231. // Purpose: starts animating the center of the draw point to the newly selected weapon
  232. //-----------------------------------------------------------------------------
  233. void CHudWeaponSelection::ActivateFastswitchWeaponDisplay( C_BaseCombatWeapon *pSelectedWeapon )
  234. {
  235. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  236. if ( !pPlayer )
  237. return;
  238. // make sure all our configuration data is read
  239. MakeReadyForUse();
  240. m_WeaponBoxes.RemoveAll();
  241. m_iSelectedWeaponBox = 0;
  242. // find out where our selected weapon is in the full list
  243. int cWeapons = 0;
  244. int iLastSelectedWeaponBox = -1;
  245. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  246. {
  247. for (int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++)
  248. {
  249. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotpos );
  250. if ( !pWeapon )
  251. continue;
  252. WeaponBox_t box = { i, slotpos };
  253. m_WeaponBoxes.AddToTail( box );
  254. if ( pWeapon == pSelectedWeapon )
  255. {
  256. m_iSelectedWeaponBox = cWeapons;
  257. }
  258. if ( pWeapon == m_pLastWeapon )
  259. {
  260. iLastSelectedWeaponBox = cWeapons;
  261. }
  262. cWeapons++;
  263. }
  264. }
  265. if ( iLastSelectedWeaponBox == -1 )
  266. {
  267. // unexpected failure, no last weapon to scroll from, default to snap behavior
  268. m_pLastWeapon = NULL;
  269. }
  270. // calculate where we would have to start drawing for this weapon to slide into center
  271. float flStart, flStop, flTime;
  272. if ( !m_pLastWeapon || m_iSelectedSlideDir == 0 || m_flHorizWeaponSelectOffsetPoint != 0 )
  273. {
  274. // no previous weapon or weapon selected directly or selection during slide, snap to exact position
  275. m_pLastWeapon = pSelectedWeapon;
  276. flStart = flStop = flTime = 0;
  277. }
  278. else
  279. {
  280. // offset display for a scroll
  281. // causing selected weapon to slide into position
  282. // scroll direction based on user's "previous" or "next" selection
  283. int numIcons = 0;
  284. int start = iLastSelectedWeaponBox;
  285. for (int i=0; i<cWeapons; i++)
  286. {
  287. // count icons in direction of slide to destination
  288. if ( start == m_iSelectedWeaponBox )
  289. break;
  290. if ( m_iSelectedSlideDir < 0 )
  291. {
  292. start--;
  293. }
  294. else
  295. {
  296. start++;
  297. }
  298. // handle wraparound in either direction
  299. start = ( start + cWeapons ) % cWeapons;
  300. numIcons++;
  301. }
  302. flStart = numIcons * (m_flLargeBoxWide + m_flBoxGap);
  303. if ( m_iSelectedSlideDir < 0 )
  304. flStart *= -1;
  305. flStop = 0;
  306. // shorten duration for scrolling when desired weapon is farther away
  307. // otherwise a large skip in the same duration causes the scroll to fly too fast
  308. flTime = numIcons * 0.20f;
  309. if ( numIcons > 1 )
  310. flTime *= 0.5f;
  311. }
  312. m_flHorizWeaponSelectOffsetPoint = flStart;
  313. g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "WeaponBoxOffset", flStop, 0, flTime, AnimationController::INTERPOLATOR_LINEAR );
  314. // start the highlight after the scroll completes
  315. m_flBlur = 7.f;
  316. g_pClientMode->GetViewportAnimationController()->RunAnimationCommand( this, "Blur", 0, flTime, 0.75f, AnimationController::INTERPOLATOR_DEACCEL );
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: starts animating the highlight for the selected weapon
  320. //-----------------------------------------------------------------------------
  321. void CHudWeaponSelection::ActivateWeaponHighlight( C_BaseCombatWeapon *pSelectedWeapon )
  322. {
  323. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  324. if ( !pPlayer )
  325. return;
  326. // make sure all our configuration data is read
  327. MakeReadyForUse();
  328. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_iSelectedSlot, m_iSelectedBoxPosition );
  329. if ( !pWeapon )
  330. return;
  331. // start the highlight after the scroll completes
  332. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "WeaponHighlight" );
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose: returns an (per frame animating) alpha value for different weapon boxes
  336. //-----------------------------------------------------------------------------
  337. float CHudWeaponSelection::GetWeaponBoxAlpha( bool bSelected )
  338. {
  339. float alpha;
  340. if ( bSelected )
  341. {
  342. alpha = m_flSelectionAlphaOverride;
  343. }
  344. else
  345. {
  346. alpha = m_flSelectionAlphaOverride * (m_flAlphaOverride / 255.0f);
  347. }
  348. return alpha;
  349. }
  350. //-------------------------------------------------------------------------
  351. // Purpose: draws the selection area
  352. //-------------------------------------------------------------------------
  353. void CHudWeaponSelection::Paint()
  354. {
  355. int width;
  356. int xpos;
  357. int ypos;
  358. if (!ShouldDraw())
  359. return;
  360. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  361. if ( !pPlayer )
  362. return;
  363. // find and display our current selection
  364. C_BaseCombatWeapon *pSelectedWeapon = NULL;
  365. switch ( hud_fastswitch.GetInt() )
  366. {
  367. case HUDTYPE_FASTSWITCH:
  368. case HUDTYPE_CAROUSEL:
  369. pSelectedWeapon = pPlayer->GetActiveWeapon();
  370. break;
  371. default:
  372. pSelectedWeapon = GetSelectedWeapon();
  373. break;
  374. }
  375. if ( !pSelectedWeapon )
  376. return;
  377. bool bPushedViewport = false;
  378. if( hud_fastswitch.GetInt() == HUDTYPE_FASTSWITCH || hud_fastswitch.GetInt() == HUDTYPE_PLUS )
  379. {
  380. CMatRenderContextPtr pRenderContext( materials );
  381. if( pRenderContext->GetRenderTarget() )
  382. {
  383. surface()->PushFullscreenViewport();
  384. bPushedViewport = true;
  385. }
  386. }
  387. // interpolate the selected box size between the small box size and the large box size
  388. // interpolation has been removed since there is no weapon pickup animation anymore, so it's all at the largest size
  389. float percentageDone = 1.0f; //min(1.0f, (gpGlobals->curtime - m_flPickupStartTime) / m_flWeaponPickupGrowTime);
  390. int largeBoxWide = m_flSmallBoxSize + ((m_flLargeBoxWide - m_flSmallBoxSize) * percentageDone);
  391. int largeBoxTall = m_flSmallBoxSize + ((m_flLargeBoxTall - m_flSmallBoxSize) * percentageDone);
  392. Color selectedColor;
  393. for (int i = 0; i < 4; i++)
  394. {
  395. selectedColor[i] = m_BoxColor[i] + ((m_SelectedBoxColor[i] - m_BoxColor[i]) * percentageDone);
  396. }
  397. switch ( hud_fastswitch.GetInt() )
  398. {
  399. case HUDTYPE_CAROUSEL:
  400. {
  401. // carousel style - flat line of items
  402. ypos = 0;
  403. if ( m_iSelectedWeaponBox == -1 || m_WeaponBoxes.Count() <= 1 )
  404. {
  405. // nothing to do
  406. return;
  407. }
  408. else if ( m_WeaponBoxes.Count() < MAX_CAROUSEL_SLOTS )
  409. {
  410. // draw the selected weapon as a 1 of n style
  411. width = (m_WeaponBoxes.Count()-1) * (m_flLargeBoxWide+m_flBoxGap) + m_flLargeBoxWide;
  412. xpos = (GetWide() - width)/2;
  413. for ( int i=0; i<m_WeaponBoxes.Count(); i++ )
  414. {
  415. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos );
  416. if ( !pWeapon )
  417. break;
  418. float alpha = GetWeaponBoxAlpha( i == m_iSelectedWeaponBox );
  419. if ( i == m_iSelectedWeaponBox )
  420. {
  421. // draw selected in highlighted style
  422. DrawLargeWeaponBox( pWeapon, true, xpos, ypos, m_flLargeBoxWide, m_flLargeBoxTall, selectedColor, alpha, -1 );
  423. }
  424. else
  425. {
  426. DrawLargeWeaponBox( pWeapon, false, xpos, ypos, m_flLargeBoxWide, m_flLargeBoxTall / 1.5f, m_BoxColor, alpha, -1 );
  427. }
  428. xpos += (m_flLargeBoxWide + m_flBoxGap);
  429. }
  430. }
  431. else
  432. {
  433. // draw the selected weapon in the center, as a continuous scrolling carosuel
  434. // draw at center the current selected and all items to its right
  435. xpos = GetWide()/2 + m_flHorizWeaponSelectOffsetPoint - largeBoxWide/2;
  436. int i = m_iSelectedWeaponBox;
  437. while ( 1 )
  438. {
  439. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos );
  440. if ( !pWeapon )
  441. break;
  442. float alpha;
  443. if ( i == m_iSelectedWeaponBox && !m_flHorizWeaponSelectOffsetPoint )
  444. {
  445. // draw selected in highlighted style
  446. alpha = GetWeaponBoxAlpha( true );
  447. DrawLargeWeaponBox( pWeapon, true, xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, alpha, -1 );
  448. }
  449. else
  450. {
  451. alpha = GetWeaponBoxAlpha( false );
  452. DrawLargeWeaponBox( pWeapon, false, xpos, ypos, largeBoxWide, largeBoxTall / 1.5f, m_BoxColor, alpha, -1 );
  453. }
  454. // advance until past edge
  455. xpos += (largeBoxWide + m_flBoxGap);
  456. if ( xpos >= GetWide() )
  457. break;
  458. ++i;
  459. if ( i >= m_WeaponBoxes.Count() )
  460. {
  461. // wraparound
  462. i = 0;
  463. }
  464. }
  465. // draw all items left of center
  466. xpos = GetWide()/2 + m_flHorizWeaponSelectOffsetPoint - (3*largeBoxWide/2 + m_flBoxGap);
  467. i = m_iSelectedWeaponBox - 1;
  468. while ( 1 )
  469. {
  470. if ( i < 0 )
  471. {
  472. // wraparound
  473. i = m_WeaponBoxes.Count() - 1;
  474. }
  475. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_WeaponBoxes[i].m_iSlot, m_WeaponBoxes[i].m_iSlotPos );
  476. if ( !pWeapon )
  477. break;
  478. float alpha;
  479. if ( i == m_iSelectedWeaponBox && !m_flHorizWeaponSelectOffsetPoint )
  480. {
  481. // draw selected in highlighted style
  482. alpha = GetWeaponBoxAlpha( true );
  483. DrawLargeWeaponBox( pWeapon, true, xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, alpha, -1 );
  484. }
  485. else
  486. {
  487. alpha = GetWeaponBoxAlpha( false );
  488. DrawLargeWeaponBox( pWeapon, false, xpos, ypos, largeBoxWide, largeBoxTall / 1.5f, m_BoxColor, alpha, -1 );
  489. }
  490. // retreat until past edge
  491. xpos -= (largeBoxWide + m_flBoxGap);
  492. if ( xpos + largeBoxWide <= 0 )
  493. break;
  494. --i;
  495. }
  496. }
  497. }
  498. break;
  499. case HUDTYPE_PLUS:
  500. {
  501. float fCenterX, fCenterY;
  502. bool bBehindCamera = false;
  503. CHudCrosshair::GetDrawPosition( &fCenterX, &fCenterY, &bBehindCamera );
  504. // if the crosshair is behind the camera, don't draw it
  505. if( bBehindCamera )
  506. return;
  507. // bucket style
  508. int screenCenterX = (int) fCenterX;
  509. int screenCenterY = (int) fCenterY - 15; // Height isn't quite screen height, so adjust for center alignment
  510. // Modifiers for the four directions. Used to change the x and y offsets
  511. // of each box based on which bucket we're drawing. Bucket directions are
  512. // 0 = UP, 1 = RIGHT, 2 = DOWN, 3 = LEFT
  513. int xModifiers[] = { 0, 1, 0, -1, -1, 1 };
  514. int yModifiers[] = { -1, 0, 1, 0, 1, 1 };
  515. // Draw the four buckets
  516. for ( int i = 0; i < MAX_WEAPON_SLOTS; ++i )
  517. {
  518. // Set the top left corner so the first box would be centered in the screen.
  519. int xPos = screenCenterX -( m_flMediumBoxWide / 2 );
  520. int yPos = screenCenterY -( m_flMediumBoxTall / 2 );
  521. // Find out how many positions to draw - an empty position should still
  522. // be drawn if there is an active weapon in any slots past it.
  523. int lastSlotPos = -1;
  524. for ( int slotPos = 0; slotPos < MAX_WEAPON_POSITIONS; ++slotPos )
  525. {
  526. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotPos );
  527. if ( pWeapon )
  528. {
  529. lastSlotPos = slotPos;
  530. }
  531. }
  532. // Draw the weapons in this bucket
  533. for ( int slotPos = 0; slotPos <= lastSlotPos; ++slotPos )
  534. {
  535. // Offset the box position
  536. xPos += ( m_flMediumBoxWide + 5 ) * xModifiers[ i ];
  537. yPos += ( m_flMediumBoxTall + 5 ) * yModifiers[ i ];
  538. int boxWide = m_flMediumBoxWide;
  539. int boxTall = m_flMediumBoxTall;
  540. int x = xPos;
  541. int y = yPos;
  542. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotPos );
  543. bool selectedWeapon = false;
  544. if ( i == m_iSelectedSlot && slotPos == m_iSelectedBoxPosition )
  545. {
  546. // This is a bit of a misnomer... we really are asking "Is this the selected slot"?
  547. selectedWeapon = true;
  548. }
  549. // Draw the box with the appropriate icon
  550. DrawLargeWeaponBox( pWeapon,
  551. selectedWeapon,
  552. x,
  553. y,
  554. boxWide,
  555. boxTall,
  556. selectedWeapon ? selectedColor : m_BoxColor,
  557. GetWeaponBoxAlpha( selectedWeapon ),
  558. -1 );
  559. }
  560. }
  561. }
  562. break;
  563. case HUDTYPE_BUCKETS:
  564. {
  565. // bucket style
  566. width = (MAX_WEAPON_SLOTS - 1) * (m_flSmallBoxSize + m_flBoxGap) + largeBoxWide;
  567. xpos = (GetWide() - width) / 2;
  568. ypos = 0;
  569. int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1);
  570. // draw the bucket set
  571. // iterate over all the weapon slots
  572. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  573. {
  574. if ( i == iActiveSlot )
  575. {
  576. bool bDrawBucketNumber = true;
  577. int iLastPos = GetLastPosInSlot( i );
  578. for (int slotpos = 0; slotpos <= iLastPos; slotpos++)
  579. {
  580. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotpos );
  581. if ( !pWeapon )
  582. {
  583. if ( !hud_showemptyweaponslots.GetBool() )
  584. continue;
  585. DrawBox( xpos, ypos, largeBoxWide, largeBoxTall, m_EmptyBoxColor, m_flAlphaOverride, bDrawBucketNumber ? i + 1 : -1 );
  586. }
  587. else
  588. {
  589. bool bSelected = (pWeapon == pSelectedWeapon);
  590. DrawLargeWeaponBox( pWeapon,
  591. bSelected,
  592. xpos,
  593. ypos,
  594. largeBoxWide,
  595. largeBoxTall,
  596. bSelected ? selectedColor : m_BoxColor,
  597. GetWeaponBoxAlpha( bSelected ),
  598. bDrawBucketNumber ? i + 1 : -1 );
  599. }
  600. // move down to the next bucket
  601. ypos += (largeBoxTall + m_flBoxGap);
  602. bDrawBucketNumber = false;
  603. }
  604. xpos += largeBoxWide;
  605. }
  606. else
  607. {
  608. // check to see if there is a weapons in this bucket
  609. if ( GetFirstPos( i ) )
  610. {
  611. // draw has weapon in slot
  612. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_BoxColor, m_flAlphaOverride, i + 1);
  613. }
  614. else
  615. {
  616. // draw empty slot
  617. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_EmptyBoxColor, m_flAlphaOverride, -1);
  618. }
  619. xpos += m_flSmallBoxSize;
  620. }
  621. // reset position
  622. ypos = 0;
  623. xpos += m_flBoxGap;
  624. }
  625. }
  626. break;
  627. default:
  628. {
  629. // do nothing
  630. }
  631. break;
  632. }
  633. if( bPushedViewport )
  634. {
  635. surface()->PopFullscreenViewport();
  636. }
  637. }
  638. //-----------------------------------------------------------------------------
  639. // Purpose: draws a single weapon selection box
  640. //-----------------------------------------------------------------------------
  641. void CHudWeaponSelection::DrawLargeWeaponBox( C_BaseCombatWeapon *pWeapon, bool bSelected, int xpos, int ypos, int boxWide, int boxTall, Color selectedColor, float alpha, int number )
  642. {
  643. Color col = bSelected ? m_SelectedFgColor : GetFgColor();
  644. switch ( hud_fastswitch.GetInt() )
  645. {
  646. case HUDTYPE_BUCKETS:
  647. {
  648. // draw box for selected weapon
  649. DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number );
  650. // draw icon
  651. col[3] *= (alpha / 255.0f);
  652. if ( pWeapon->GetSpriteActive() )
  653. {
  654. // find the center of the box to draw in
  655. int iconWidth = pWeapon->GetSpriteActive()->Width();
  656. int iconHeight = pWeapon->GetSpriteActive()->Height();
  657. int x_offs = (boxWide - iconWidth) / 2;
  658. int y_offs;
  659. if ( bSelected && hud_fastswitch.GetInt() != 0 )
  660. {
  661. // place the icon aligned with the non-selected version
  662. y_offs = (boxTall / 1.5f - iconHeight) / 2;
  663. }
  664. else
  665. {
  666. y_offs = (boxTall - iconHeight) / 2;
  667. }
  668. if (!pWeapon->CanBeSelected())
  669. {
  670. // unselectable weapon, display as such
  671. col = Color(255, 0, 0, col[3]);
  672. }
  673. else if (bSelected)
  674. {
  675. // currently selected weapon, display brighter
  676. col[3] = alpha;
  677. // draw an active version over the top
  678. pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  679. }
  680. // draw the inactive version
  681. pWeapon->GetSpriteInactive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  682. }
  683. }
  684. break;
  685. case HUDTYPE_PLUS:
  686. case HUDTYPE_CAROUSEL:
  687. {
  688. if ( !pWeapon )
  689. {
  690. // draw red box for an empty bubble
  691. if( bSelected )
  692. {
  693. selectedColor.SetColor( 255, 0, 0, 40 );
  694. }
  695. DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number );
  696. return;
  697. }
  698. else
  699. {
  700. // draw box for selected weapon
  701. DrawBox( xpos, ypos, boxWide, boxTall, selectedColor, alpha, number );
  702. }
  703. int iconWidth;
  704. int iconHeight;
  705. int x_offs;
  706. int y_offs;
  707. // draw icon
  708. col[3] *= (alpha / 255.0f);
  709. if ( pWeapon->GetSpriteInactive() )
  710. {
  711. iconWidth = pWeapon->GetSpriteInactive()->Width();
  712. iconHeight = pWeapon->GetSpriteInactive()->Height();
  713. x_offs = (boxWide - iconWidth) / 2;
  714. if ( bSelected && HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
  715. {
  716. // place the icon aligned with the non-selected version
  717. y_offs = (boxTall/1.5f - iconHeight) / 2;
  718. }
  719. else
  720. {
  721. y_offs = (boxTall - iconHeight) / 2;
  722. }
  723. if ( !pWeapon->CanBeSelected() )
  724. {
  725. // unselectable weapon, display as such
  726. col = Color(255, 0, 0, col[3]);
  727. }
  728. // draw the inactive version
  729. pWeapon->GetSpriteInactive()->DrawSelf( xpos + x_offs, ypos + y_offs, iconWidth, iconHeight, col );
  730. }
  731. if ( bSelected && pWeapon->GetSpriteActive() )
  732. {
  733. // find the center of the box to draw in
  734. iconWidth = pWeapon->GetSpriteActive()->Width();
  735. iconHeight = pWeapon->GetSpriteActive()->Height();
  736. x_offs = (boxWide - iconWidth) / 2;
  737. if ( HUDTYPE_CAROUSEL == hud_fastswitch.GetInt() )
  738. {
  739. // place the icon aligned with the non-selected version
  740. y_offs = (boxTall/1.5f - iconHeight) / 2;
  741. }
  742. else
  743. {
  744. y_offs = (boxTall - iconHeight) / 2;
  745. }
  746. col[3] = 255;
  747. for (float fl = m_flBlur; fl > 0.0f; fl -= 1.0f)
  748. {
  749. if (fl >= 1.0f)
  750. {
  751. pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  752. }
  753. else
  754. {
  755. // draw a percentage of the last one
  756. col[3] *= fl;
  757. pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  758. }
  759. }
  760. }
  761. }
  762. break;
  763. default:
  764. {
  765. // do nothing
  766. }
  767. break;
  768. }
  769. if ( HUDTYPE_PLUS == hud_fastswitch.GetInt() )
  770. {
  771. // No text in plus bucket method
  772. return;
  773. }
  774. // draw text
  775. col = m_TextColor;
  776. const FileWeaponInfo_t &weaponInfo = pWeapon->GetWpnData();
  777. if ( bSelected )
  778. {
  779. wchar_t text[128];
  780. wchar_t *tempString = g_pVGuiLocalize->Find(weaponInfo.szPrintName);
  781. // setup our localized string
  782. if ( tempString )
  783. {
  784. #ifdef WIN32
  785. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%s", tempString);
  786. #else
  787. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%S", tempString);
  788. #endif
  789. text[sizeof(text)/sizeof(wchar_t) - 1] = 0;
  790. }
  791. else
  792. {
  793. // string wasn't found by g_pVGuiLocalize->Find()
  794. g_pVGuiLocalize->ConvertANSIToUnicode(weaponInfo.szPrintName, text, sizeof(text));
  795. }
  796. surface()->DrawSetTextColor( col );
  797. surface()->DrawSetTextFont( m_hTextFont );
  798. // count the position
  799. int slen = 0, charCount = 0, maxslen = 0;
  800. int firstslen = 0;
  801. {
  802. for (wchar_t *pch = text; *pch != 0; pch++)
  803. {
  804. if (*pch == '\n')
  805. {
  806. // newline character, drop to the next line
  807. if (slen > maxslen)
  808. {
  809. maxslen = slen;
  810. }
  811. if (!firstslen)
  812. {
  813. firstslen = slen;
  814. }
  815. slen = 0;
  816. }
  817. else if (*pch == '\r')
  818. {
  819. // do nothing
  820. }
  821. else
  822. {
  823. slen += surface()->GetCharacterWidth( m_hTextFont, *pch );
  824. charCount++;
  825. }
  826. }
  827. }
  828. if (slen > maxslen)
  829. {
  830. maxslen = slen;
  831. }
  832. if (!firstslen)
  833. {
  834. firstslen = maxslen;
  835. }
  836. int tx = xpos + ((m_flLargeBoxWide - firstslen) / 2);
  837. int ty = ypos + (int)m_flTextYPos;
  838. surface()->DrawSetTextPos( tx, ty );
  839. // adjust the charCount by the scan amount
  840. charCount *= m_flTextScan;
  841. for (wchar_t *pch = text; charCount > 0; pch++)
  842. {
  843. if (*pch == '\n')
  844. {
  845. // newline character, move to the next line
  846. surface()->DrawSetTextPos( xpos + ((boxWide - slen) / 2), ty + (surface()->GetFontTall(m_hTextFont) * 1.1f));
  847. }
  848. else if (*pch == '\r')
  849. {
  850. // do nothing
  851. }
  852. else
  853. {
  854. surface()->DrawUnicodeChar(*pch);
  855. charCount--;
  856. }
  857. }
  858. }
  859. }
  860. //-----------------------------------------------------------------------------
  861. // Purpose: draws a selection box
  862. //-----------------------------------------------------------------------------
  863. void CHudWeaponSelection::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number)
  864. {
  865. BaseClass::DrawBox( x, y, wide, tall, color, normalizedAlpha / 255.0f );
  866. // draw the number
  867. if (number >= 0)
  868. {
  869. Color numberColor = m_NumberColor;
  870. numberColor[3] *= normalizedAlpha / 255.0f;
  871. surface()->DrawSetTextColor(numberColor);
  872. surface()->DrawSetTextFont(m_hNumberFont);
  873. wchar_t wch = '0' + number;
  874. surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos);
  875. surface()->DrawUnicodeChar(wch);
  876. }
  877. }
  878. //-----------------------------------------------------------------------------
  879. // Purpose: hud scheme settings
  880. //-----------------------------------------------------------------------------
  881. void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
  882. {
  883. BaseClass::ApplySchemeSettings(pScheme);
  884. SetPaintBackgroundEnabled(false);
  885. // set our size
  886. int screenWide, screenTall;
  887. int x, y;
  888. GetPos(x, y);
  889. GetHudSize(screenWide, screenTall);
  890. if ( hud_fastswitch.GetInt() == HUDTYPE_CAROUSEL )
  891. {
  892. // need bounds to be exact width for proper clipping during scroll
  893. int width = MAX_CAROUSEL_SLOTS*m_flLargeBoxWide + (MAX_CAROUSEL_SLOTS-1)*m_flBoxGap;
  894. SetBounds( (screenWide-width)/2, y, width, screenTall - y);
  895. }
  896. else
  897. {
  898. SetBounds( x, y, screenWide - x, screenTall - y );
  899. }
  900. }
  901. //-----------------------------------------------------------------------------
  902. // Purpose: Opens weapon selection control
  903. //-----------------------------------------------------------------------------
  904. void CHudWeaponSelection::OpenSelection( void )
  905. {
  906. Assert(!IsInSelectionMode());
  907. CBaseHudWeaponSelection::OpenSelection();
  908. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("OpenWeaponSelectionMenu");
  909. m_iSelectedBoxPosition = 0;
  910. m_iSelectedSlot = -1;
  911. }
  912. //-----------------------------------------------------------------------------
  913. // Purpose: Closes weapon selection control immediately
  914. //-----------------------------------------------------------------------------
  915. void CHudWeaponSelection::HideSelection( void )
  916. {
  917. CBaseHudWeaponSelection::HideSelection();
  918. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("CloseWeaponSelectionMenu");
  919. m_bFadingOut = false;
  920. }
  921. //-----------------------------------------------------------------------------
  922. // Purpose: Returns the next available weapon item in the weapon selection
  923. //-----------------------------------------------------------------------------
  924. C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  925. {
  926. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  927. if ( !pPlayer )
  928. return NULL;
  929. C_BaseCombatWeapon *pNextWeapon = NULL;
  930. // search all the weapons looking for the closest next
  931. int iLowestNextSlot = MAX_WEAPON_SLOTS;
  932. int iLowestNextPosition = MAX_WEAPON_POSITIONS;
  933. for ( int i = 0; i < MAX_WEAPONS; i++ )
  934. {
  935. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  936. if ( !pWeapon )
  937. continue;
  938. if ( CanBeSelectedInHUD( pWeapon ) )
  939. {
  940. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  941. // see if this weapon is further ahead in the selection list
  942. if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) )
  943. {
  944. // see if this weapon is closer than the current lowest
  945. if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) )
  946. {
  947. iLowestNextSlot = weaponSlot;
  948. iLowestNextPosition = weaponPosition;
  949. pNextWeapon = pWeapon;
  950. }
  951. }
  952. }
  953. }
  954. return pNextWeapon;
  955. }
  956. //-----------------------------------------------------------------------------
  957. // Purpose: Returns the prior available weapon item in the weapon selection
  958. //-----------------------------------------------------------------------------
  959. C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  960. {
  961. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  962. if ( !pPlayer )
  963. return NULL;
  964. C_BaseCombatWeapon *pPrevWeapon = NULL;
  965. // search all the weapons looking for the closest next
  966. int iLowestPrevSlot = -1;
  967. int iLowestPrevPosition = -1;
  968. for ( int i = 0; i < MAX_WEAPONS; i++ )
  969. {
  970. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  971. if ( !pWeapon )
  972. continue;
  973. if ( CanBeSelectedInHUD( pWeapon ) )
  974. {
  975. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  976. // see if this weapon is further ahead in the selection list
  977. if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) )
  978. {
  979. // see if this weapon is closer than the current lowest
  980. if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) )
  981. {
  982. iLowestPrevSlot = weaponSlot;
  983. iLowestPrevPosition = weaponPosition;
  984. pPrevWeapon = pWeapon;
  985. }
  986. }
  987. }
  988. }
  989. return pPrevWeapon;
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Purpose: Moves the selection to the next item in the menu
  993. //-----------------------------------------------------------------------------
  994. void CHudWeaponSelection::CycleToNextWeapon( void )
  995. {
  996. // Get the local player.
  997. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  998. if ( !pPlayer )
  999. return;
  1000. m_pLastWeapon = pPlayer->GetActiveWeapon();
  1001. C_BaseCombatWeapon *pNextWeapon = NULL;
  1002. if ( IsInSelectionMode() )
  1003. {
  1004. // find the next selection spot
  1005. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  1006. if ( !pWeapon )
  1007. return;
  1008. pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  1009. }
  1010. else
  1011. {
  1012. // open selection at the current place
  1013. pNextWeapon = pPlayer->GetActiveWeapon();
  1014. if ( pNextWeapon )
  1015. {
  1016. pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  1017. }
  1018. }
  1019. if ( !pNextWeapon )
  1020. {
  1021. // wrap around back to start
  1022. pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1);
  1023. }
  1024. if ( pNextWeapon )
  1025. {
  1026. SetSelectedWeapon( pNextWeapon );
  1027. SetSelectedSlideDir( 1 );
  1028. if ( !IsInSelectionMode() )
  1029. {
  1030. OpenSelection();
  1031. }
  1032. // Play the "cycle to next weapon" sound
  1033. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  1034. }
  1035. }
  1036. //-----------------------------------------------------------------------------
  1037. // Purpose: Moves the selection to the previous item in the menu
  1038. //-----------------------------------------------------------------------------
  1039. void CHudWeaponSelection::CycleToPrevWeapon( void )
  1040. {
  1041. // Get the local player.
  1042. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1043. if ( !pPlayer )
  1044. return;
  1045. m_pLastWeapon = pPlayer->GetActiveWeapon();
  1046. C_BaseCombatWeapon *pNextWeapon = NULL;
  1047. if ( IsInSelectionMode() )
  1048. {
  1049. // find the next selection spot
  1050. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  1051. if ( !pWeapon )
  1052. return;
  1053. pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  1054. }
  1055. else
  1056. {
  1057. // open selection at the current place
  1058. pNextWeapon = pPlayer->GetActiveWeapon();
  1059. if ( pNextWeapon )
  1060. {
  1061. pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  1062. }
  1063. }
  1064. if ( !pNextWeapon )
  1065. {
  1066. // wrap around back to end of weapon list
  1067. pNextWeapon = FindPrevWeaponInWeaponSelection(MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS);
  1068. }
  1069. if ( pNextWeapon )
  1070. {
  1071. SetSelectedWeapon( pNextWeapon );
  1072. SetSelectedSlideDir( -1 );
  1073. if ( !IsInSelectionMode() )
  1074. {
  1075. OpenSelection();
  1076. }
  1077. // Play the "cycle to next weapon" sound
  1078. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  1079. }
  1080. }
  1081. //-----------------------------------------------------------------------------
  1082. // Purpose: returns the # of the last weapon in the specified slot
  1083. //-----------------------------------------------------------------------------
  1084. int CHudWeaponSelection::GetLastPosInSlot( int iSlot ) const
  1085. {
  1086. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  1087. int iMaxSlotPos;
  1088. if ( !player )
  1089. return -1;
  1090. iMaxSlotPos = -1;
  1091. for ( int i = 0; i < MAX_WEAPONS; i++ )
  1092. {
  1093. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  1094. if ( pWeapon == NULL )
  1095. continue;
  1096. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() > iMaxSlotPos )
  1097. iMaxSlotPos = pWeapon->GetPosition();
  1098. }
  1099. return iMaxSlotPos;
  1100. }
  1101. //-----------------------------------------------------------------------------
  1102. // Purpose: returns the weapon in the specified slot
  1103. //-----------------------------------------------------------------------------
  1104. C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
  1105. {
  1106. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  1107. if ( !player )
  1108. return NULL;
  1109. for ( int i = 0; i < MAX_WEAPONS; i++ )
  1110. {
  1111. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  1112. if ( pWeapon == NULL )
  1113. continue;
  1114. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos )
  1115. return pWeapon;
  1116. }
  1117. return NULL;
  1118. }
  1119. //-----------------------------------------------------------------------------
  1120. // Purpose: Opens the next weapon in the slot
  1121. //-----------------------------------------------------------------------------
  1122. void CHudWeaponSelection::FastWeaponSwitch( int iWeaponSlot )
  1123. {
  1124. // get the slot the player's weapon is in
  1125. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1126. if ( !pPlayer )
  1127. return;
  1128. m_pLastWeapon = NULL;
  1129. // see where we should start selection
  1130. int iPosition = -1;
  1131. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  1132. if ( pActiveWeapon && pActiveWeapon->GetSlot() == iWeaponSlot )
  1133. {
  1134. // start after this weapon
  1135. iPosition = pActiveWeapon->GetPosition();
  1136. }
  1137. C_BaseCombatWeapon *pNextWeapon = NULL;
  1138. // search for the weapon after the current one
  1139. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, iPosition);
  1140. // make sure it's in the same bucket
  1141. if ( !pNextWeapon || pNextWeapon->GetSlot() != iWeaponSlot )
  1142. {
  1143. // just look for any weapon in this slot
  1144. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, -1);
  1145. }
  1146. // see if we found a weapon that's different from the current and in the selected slot
  1147. if ( pNextWeapon && pNextWeapon != pActiveWeapon && pNextWeapon->GetSlot() == iWeaponSlot )
  1148. {
  1149. // select the new weapon
  1150. ::input->MakeWeaponSelection( pNextWeapon );
  1151. }
  1152. else if ( pNextWeapon != pActiveWeapon )
  1153. {
  1154. // error sound
  1155. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  1156. }
  1157. if ( HUDTYPE_CAROUSEL != hud_fastswitch.GetInt() )
  1158. {
  1159. // kill any fastswitch display
  1160. m_flSelectionTime = 0.0f;
  1161. }
  1162. }
  1163. //-----------------------------------------------------------------------------
  1164. // Purpose: Opens the next weapon in the slot
  1165. //-----------------------------------------------------------------------------
  1166. void CHudWeaponSelection::PlusTypeFastWeaponSwitch( int iWeaponSlot )
  1167. {
  1168. // get the slot the player's weapon is in
  1169. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1170. if ( !pPlayer )
  1171. return;
  1172. m_pLastWeapon = NULL;
  1173. int newSlot = m_iSelectedSlot;
  1174. // Changing slot number does not necessarily mean we need to change the slot - the player could be
  1175. // scrolling through the same slot but in the opposite direction. Slot pairs are 0,2 and 1,3 - so
  1176. // compare the 0 bits to see if we're within a pair. Otherwise, reset the box to the zero position.
  1177. if ( -1 == m_iSelectedSlot || ( ( m_iSelectedSlot ^ iWeaponSlot ) & 1 ) )
  1178. {
  1179. // Changing vertical/horizontal direction. Reset the selected box position to zero.
  1180. m_iSelectedBoxPosition = 0;
  1181. m_iSelectedSlot = iWeaponSlot;
  1182. }
  1183. else
  1184. {
  1185. // Still in the same horizontal/vertical direction. Determine which way we're moving in the slot.
  1186. int increment = 1;
  1187. if ( m_iSelectedSlot != iWeaponSlot )
  1188. {
  1189. // Decrementing within the slot. If we're at the zero position in this slot,
  1190. // jump to the zero position of the opposite slot. This also counts as our increment.
  1191. increment = -1;
  1192. if ( 0 == m_iSelectedBoxPosition )
  1193. {
  1194. newSlot = ( m_iSelectedSlot + 2 ) % 4;
  1195. increment = 0;
  1196. }
  1197. }
  1198. // Find out of the box position is at the end of the slot
  1199. int lastSlotPos = -1;
  1200. for ( int slotPos = 0; slotPos < MAX_WEAPON_POSITIONS; ++slotPos )
  1201. {
  1202. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( newSlot, slotPos );
  1203. if ( pWeapon )
  1204. {
  1205. lastSlotPos = slotPos;
  1206. }
  1207. }
  1208. // Increment/Decrement the selected box position
  1209. if ( m_iSelectedBoxPosition + increment <= lastSlotPos )
  1210. {
  1211. m_iSelectedBoxPosition += increment;
  1212. m_iSelectedSlot = newSlot;
  1213. }
  1214. else
  1215. {
  1216. // error sound
  1217. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  1218. return;
  1219. }
  1220. }
  1221. // Select the weapon in this position
  1222. bool bWeaponSelected = false;
  1223. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  1224. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( m_iSelectedSlot, m_iSelectedBoxPosition );
  1225. if ( pWeapon )
  1226. {
  1227. if ( pWeapon != pActiveWeapon )
  1228. {
  1229. // Select the new weapon
  1230. ::input->MakeWeaponSelection( pWeapon );
  1231. SetSelectedWeapon( pWeapon );
  1232. bWeaponSelected = true;
  1233. }
  1234. }
  1235. if ( !bWeaponSelected )
  1236. {
  1237. // Still need to set this to make hud display appear
  1238. SetSelectedWeapon( pPlayer->GetActiveWeapon() );
  1239. }
  1240. }
  1241. //-----------------------------------------------------------------------------
  1242. // Purpose: Moves selection to the specified slot
  1243. //-----------------------------------------------------------------------------
  1244. void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
  1245. {
  1246. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  1247. --iSlot;
  1248. // Get the local player.
  1249. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  1250. if ( !pPlayer )
  1251. return;
  1252. // Don't try and read past our possible number of slots
  1253. if ( iSlot >= MAX_WEAPON_SLOTS )
  1254. return;
  1255. // Make sure the player's allowed to switch weapons
  1256. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  1257. return;
  1258. switch( hud_fastswitch.GetInt() )
  1259. {
  1260. case HUDTYPE_FASTSWITCH:
  1261. case HUDTYPE_CAROUSEL:
  1262. {
  1263. FastWeaponSwitch( iSlot );
  1264. return;
  1265. }
  1266. case HUDTYPE_PLUS:
  1267. {
  1268. if ( !IsInSelectionMode() )
  1269. {
  1270. // open the weapon selection
  1271. OpenSelection();
  1272. }
  1273. PlusTypeFastWeaponSwitch( iSlot );
  1274. ActivateWeaponHighlight( GetSelectedWeapon() );
  1275. }
  1276. break;
  1277. case HUDTYPE_BUCKETS:
  1278. {
  1279. int slotPos = 0;
  1280. C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon();
  1281. // start later in the list
  1282. if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot )
  1283. {
  1284. slotPos = pActiveWeapon->GetPosition() + 1;
  1285. }
  1286. // find the weapon in this slot
  1287. pActiveWeapon = GetNextActivePos( iSlot, slotPos );
  1288. if ( !pActiveWeapon )
  1289. {
  1290. pActiveWeapon = GetNextActivePos( iSlot, 0 );
  1291. }
  1292. if ( pActiveWeapon != NULL )
  1293. {
  1294. if ( !IsInSelectionMode() )
  1295. {
  1296. // open the weapon selection
  1297. OpenSelection();
  1298. }
  1299. // Mark the change
  1300. SetSelectedWeapon( pActiveWeapon );
  1301. SetSelectedSlideDir( 0 );
  1302. }
  1303. }
  1304. default:
  1305. {
  1306. // do nothing
  1307. }
  1308. break;
  1309. }
  1310. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  1311. }