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.

761 lines
22 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 <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/ILocalize.h"
  18. // memdbgon must be the last include file in a .cpp file!!!
  19. #include "tier0/memdbgon.h"
  20. //-----------------------------------------------------------------------------
  21. // Purpose: hl2 weapon selection hud element
  22. //-----------------------------------------------------------------------------
  23. class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel
  24. {
  25. DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel );
  26. public:
  27. CHudWeaponSelection(const char *pElementName );
  28. virtual bool ShouldDraw();
  29. virtual void OnWeaponPickup( C_BaseCombatWeapon *pWeapon );
  30. virtual void CycleToNextWeapon( void );
  31. virtual void CycleToPrevWeapon( void );
  32. virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
  33. virtual void SelectWeaponSlot( int iSlot );
  34. virtual C_BaseCombatWeapon *GetSelectedWeapon( void )
  35. {
  36. return m_hSelectedWeapon;
  37. }
  38. virtual void OpenSelection( void );
  39. virtual void HideSelection( void );
  40. virtual void LevelInit();
  41. protected:
  42. virtual void OnThink();
  43. virtual void Paint();
  44. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  45. virtual bool IsWeaponSelectable()
  46. {
  47. if (IsInSelectionMode())
  48. return true;
  49. return false;
  50. }
  51. private:
  52. C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  53. C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  54. void FastWeaponSwitch( int iWeaponSlot );
  55. virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon )
  56. {
  57. m_hSelectedWeapon = pWeapon;
  58. }
  59. void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number);
  60. CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
  61. CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" );
  62. CPanelAnimationVarAliasType( float, m_flSmallBoxSize, "SmallBoxSize", "32", "proportional_float" );
  63. CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" );
  64. CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" );
  65. CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "12", "proportional_float" );
  66. CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" );
  67. CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" );
  68. CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" );
  69. CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" );
  70. CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255" );
  71. CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" );
  72. CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" );
  73. CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" );
  74. CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" );
  75. CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxClor", "SelectionSelectedBoxBg" );
  76. CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" );
  77. CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" );
  78. bool m_bFadingOut;
  79. };
  80. DECLARE_HUDELEMENT( CHudWeaponSelection );
  81. using namespace vgui;
  82. //-----------------------------------------------------------------------------
  83. // Purpose: Constructor
  84. //-----------------------------------------------------------------------------
  85. CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection")
  86. {
  87. vgui::Panel *pParent = g_pClientMode->GetViewport();
  88. SetParent( pParent );
  89. m_bFadingOut = false;
  90. }
  91. //-----------------------------------------------------------------------------
  92. // Purpose: sets up display for showing weapon pickup
  93. //-----------------------------------------------------------------------------
  94. void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
  95. {
  96. // add to pickup history
  97. CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
  98. if ( pHudHR )
  99. {
  100. pHudHR->AddToHistory( pWeapon );
  101. }
  102. }
  103. #define SELECTION_TIMEOUT_THRESHOLD 5.0f // Seconds
  104. #define SELECTION_FADEOUT_TIME 1.5f
  105. //-----------------------------------------------------------------------------
  106. // Purpose: updates animation status
  107. //-----------------------------------------------------------------------------
  108. void CHudWeaponSelection::OnThink( void )
  109. {
  110. // Time out after awhile of inactivity
  111. if ( ( gpGlobals->curtime - m_flSelectionTime ) > SELECTION_TIMEOUT_THRESHOLD )
  112. {
  113. if (!m_bFadingOut)
  114. {
  115. // start fading out
  116. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "FadeOutWeaponSelectionMenu" );
  117. m_bFadingOut = true;
  118. }
  119. else if (gpGlobals->curtime - m_flSelectionTime > SELECTION_TIMEOUT_THRESHOLD + SELECTION_FADEOUT_TIME)
  120. {
  121. // finished fade, close
  122. HideSelection();
  123. }
  124. }
  125. else if (m_bFadingOut)
  126. {
  127. // stop us fading out, show the animation again
  128. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "OpenWeaponSelectionMenu" );
  129. m_bFadingOut = false;
  130. }
  131. }
  132. //-----------------------------------------------------------------------------
  133. // Purpose: returns true if the panel should draw
  134. //-----------------------------------------------------------------------------
  135. bool CHudWeaponSelection::ShouldDraw()
  136. {
  137. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  138. if ( !pPlayer )
  139. {
  140. if ( IsInSelectionMode() )
  141. {
  142. HideSelection();
  143. }
  144. return false;
  145. }
  146. bool bret = CBaseHudWeaponSelection::ShouldDraw();
  147. if ( !bret )
  148. return false;
  149. return ( m_bSelectionVisible ) ? true : false;
  150. }
  151. //-----------------------------------------------------------------------------
  152. // Purpose:
  153. //-----------------------------------------------------------------------------
  154. void CHudWeaponSelection::LevelInit()
  155. {
  156. CHudElement::LevelInit();
  157. }
  158. //-------------------------------------------------------------------------
  159. // Purpose: draws the selection area
  160. //-------------------------------------------------------------------------
  161. void CHudWeaponSelection::Paint()
  162. {
  163. if (!ShouldDraw())
  164. return;
  165. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  166. if ( !pPlayer )
  167. return;
  168. // find and display our current selection
  169. C_BaseCombatWeapon *pSelectedWeapon = GetSelectedWeapon();
  170. if ( !pSelectedWeapon )
  171. return;
  172. int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1);
  173. // interpolate the selected box size between the small box size and the large box size
  174. // interpolation has been removed since there is no weapon pickup animation anymore, so it's all at the largest size
  175. float percentageDone = 1.0f; //min(1.0f, (gpGlobals->curtime - m_flPickupStartTime) / m_flWeaponPickupGrowTime);
  176. int largeBoxWide = m_flSmallBoxSize + ((m_flLargeBoxWide - m_flSmallBoxSize) * percentageDone);
  177. int largeBoxTall = m_flSmallBoxSize + ((m_flLargeBoxTall - m_flSmallBoxSize) * percentageDone);
  178. Color selectedColor;
  179. {for (int i = 0; i < 4; i++)
  180. {
  181. selectedColor[i] = m_BoxColor[i] + ((m_SelectedBoxColor[i] - m_BoxColor[i]) * percentageDone);
  182. }}
  183. // calculate where to start drawing
  184. int width = (MAX_WEAPON_SLOTS - 1) * (m_flSmallBoxSize + m_flBoxGap) + largeBoxWide;
  185. int xpos = (GetWide() - width) / 2;
  186. int ypos = 0;
  187. // iterate over all the weapon slots
  188. for ( int i = 0; i < MAX_WEAPON_SLOTS; i++ )
  189. {
  190. if ( i == iActiveSlot )
  191. {
  192. bool bFirstItem = true;
  193. for (int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++)
  194. {
  195. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot(i, slotpos);
  196. if ( !pWeapon )
  197. continue;
  198. // draw box for selected weapon
  199. DrawBox(xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, m_flSelectionAlphaOverride, bFirstItem ? i + 1 : -1);
  200. // draw icon
  201. Color col = GetFgColor();
  202. if ( pWeapon->GetSpriteActive() )
  203. {
  204. // find the center of the box to draw in
  205. int iconWidth = pWeapon->GetSpriteActive()->Width();
  206. int iconHeight = pWeapon->GetSpriteActive()->Height();
  207. int x_offs = (largeBoxWide - iconWidth) / 2;
  208. int y_offs = (largeBoxTall - iconHeight) / 2;
  209. if (!pWeapon->CanBeSelected())
  210. {
  211. // unselectable weapon, display as such
  212. col = Color(255, 0, 0, col[3]);
  213. }
  214. else if (pWeapon == pSelectedWeapon)
  215. {
  216. // currently selected weapon, display brighter
  217. col[3] = m_flSelectionAlphaOverride;
  218. // draw an active version over the top
  219. pWeapon->GetSpriteActive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  220. }
  221. // draw the inactive version
  222. pWeapon->GetSpriteInactive()->DrawSelf( xpos + x_offs, ypos + y_offs, col );
  223. }
  224. // draw text
  225. col = m_TextColor;
  226. const FileWeaponInfo_t &weaponInfo = pWeapon->GetWpnData();
  227. if (pWeapon == pSelectedWeapon)
  228. {
  229. wchar_t text[128];
  230. wchar_t *tempString = g_pVGuiLocalize->Find(weaponInfo.szPrintName);
  231. // setup our localized string
  232. if ( tempString )
  233. {
  234. #ifdef WIN32
  235. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%s", tempString);
  236. #else
  237. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%S", tempString);
  238. #endif
  239. text[sizeof(text)/sizeof(wchar_t) - 1] = 0;
  240. }
  241. else
  242. {
  243. // string wasn't found by g_pVGuiLocalize->Find()
  244. g_pVGuiLocalize->ConvertANSIToUnicode(weaponInfo.szPrintName, text, sizeof(text));
  245. }
  246. surface()->DrawSetTextColor( col );
  247. surface()->DrawSetTextFont( m_hTextFont );
  248. // count the position
  249. int slen = 0, charCount = 0, maxslen = 0;
  250. int firstslen = 0;
  251. {
  252. for (wchar_t *pch = text; *pch != 0; pch++)
  253. {
  254. if (*pch == '\n')
  255. {
  256. // newline character, drop to the next line
  257. if (slen > maxslen)
  258. {
  259. maxslen = slen;
  260. }
  261. if (!firstslen)
  262. {
  263. firstslen = slen;
  264. }
  265. slen = 0;
  266. }
  267. else if (*pch == '\r')
  268. {
  269. // do nothing
  270. }
  271. else
  272. {
  273. slen += surface()->GetCharacterWidth( m_hTextFont, *pch );
  274. charCount++;
  275. }
  276. }
  277. }
  278. if (slen > maxslen)
  279. {
  280. maxslen = slen;
  281. }
  282. if (!firstslen)
  283. {
  284. firstslen = maxslen;
  285. }
  286. int tx = xpos + ((largeBoxWide - firstslen) / 2);
  287. int ty = ypos + (int)m_flTextYPos;
  288. surface()->DrawSetTextPos( tx, ty );
  289. // adjust the charCount by the scan amount
  290. charCount *= m_flTextScan;
  291. for (wchar_t *pch = text; charCount > 0; pch++)
  292. {
  293. if (*pch == '\n')
  294. {
  295. // newline character, move to the next line
  296. surface()->DrawSetTextPos( xpos + ((largeBoxWide - slen) / 2), ty + (surface()->GetFontTall(m_hTextFont) * 1.1f));
  297. }
  298. else if (*pch == '\r')
  299. {
  300. // do nothing
  301. }
  302. else
  303. {
  304. surface()->DrawUnicodeChar(*pch);
  305. charCount--;
  306. }
  307. }
  308. }
  309. ypos += (largeBoxTall + m_flBoxGap);
  310. bFirstItem = false;
  311. }
  312. xpos += largeBoxWide;
  313. }
  314. else
  315. {
  316. // check to see if there is a weapons in this bucket
  317. if ( GetFirstPos( i ) )
  318. {
  319. // draw has weapon in slot
  320. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_BoxColor, m_flAlphaOverride, i + 1);
  321. }
  322. else
  323. {
  324. // draw empty slot
  325. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_EmptyBoxColor, m_flAlphaOverride, -1);
  326. }
  327. xpos += m_flSmallBoxSize;
  328. }
  329. // reset position
  330. ypos = 0;
  331. xpos += m_flBoxGap;
  332. }
  333. }
  334. //-----------------------------------------------------------------------------
  335. // Purpose: draws a selection box
  336. //-----------------------------------------------------------------------------
  337. void CHudWeaponSelection::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number)
  338. {
  339. BaseClass::DrawBox( x, y, wide, tall, color, normalizedAlpha / 255.0f );
  340. // draw the number
  341. if (number >= 0)
  342. {
  343. Color numberColor = m_NumberColor;
  344. numberColor[3] *= normalizedAlpha / 255.0f;
  345. surface()->DrawSetTextColor(numberColor);
  346. surface()->DrawSetTextFont(m_hNumberFont);
  347. wchar_t wch = '0' + number;
  348. surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos);
  349. surface()->DrawUnicodeChar(wch);
  350. }
  351. }
  352. //-----------------------------------------------------------------------------
  353. // Purpose: hud scheme settings
  354. //-----------------------------------------------------------------------------
  355. void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
  356. {
  357. BaseClass::ApplySchemeSettings(pScheme);
  358. SetPaintBackgroundEnabled(false);
  359. // set our size
  360. int screenWide, screenTall;
  361. int x, y;
  362. GetPos(x, y);
  363. GetHudSize(screenWide, screenTall);
  364. SetBounds(0, y, screenWide, screenTall - y);
  365. }
  366. //-----------------------------------------------------------------------------
  367. // Purpose: Opens weapon selection control
  368. //-----------------------------------------------------------------------------
  369. void CHudWeaponSelection::OpenSelection( void )
  370. {
  371. Assert(!IsInSelectionMode());
  372. CBaseHudWeaponSelection::OpenSelection();
  373. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("OpenWeaponSelectionMenu");
  374. }
  375. //-----------------------------------------------------------------------------
  376. // Purpose: Closes weapon selection control immediately
  377. //-----------------------------------------------------------------------------
  378. void CHudWeaponSelection::HideSelection( void )
  379. {
  380. CBaseHudWeaponSelection::HideSelection();
  381. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("CloseWeaponSelectionMenu");
  382. m_bFadingOut = false;
  383. }
  384. //-----------------------------------------------------------------------------
  385. // Purpose: Returns the next available weapon item in the weapon selection
  386. //-----------------------------------------------------------------------------
  387. C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  388. {
  389. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  390. if ( !pPlayer )
  391. return NULL;
  392. C_BaseCombatWeapon *pNextWeapon = NULL;
  393. // search all the weapons looking for the closest next
  394. int iLowestNextSlot = MAX_WEAPON_SLOTS;
  395. int iLowestNextPosition = MAX_WEAPON_POSITIONS;
  396. for ( int i = 0; i < MAX_WEAPONS; i++ )
  397. {
  398. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  399. if ( !pWeapon )
  400. continue;
  401. if ( pWeapon->CanBeSelected() )
  402. {
  403. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  404. // see if this weapon is further ahead in the selection list
  405. if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) )
  406. {
  407. // see if this weapon is closer than the current lowest
  408. if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) )
  409. {
  410. iLowestNextSlot = weaponSlot;
  411. iLowestNextPosition = weaponPosition;
  412. pNextWeapon = pWeapon;
  413. }
  414. }
  415. }
  416. }
  417. return pNextWeapon;
  418. }
  419. //-----------------------------------------------------------------------------
  420. // Purpose: Returns the prior available weapon item in the weapon selection
  421. //-----------------------------------------------------------------------------
  422. C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  423. {
  424. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  425. if ( !pPlayer )
  426. return NULL;
  427. C_BaseCombatWeapon *pPrevWeapon = NULL;
  428. // search all the weapons looking for the closest next
  429. int iLowestPrevSlot = -1;
  430. int iLowestPrevPosition = -1;
  431. for ( int i = 0; i < MAX_WEAPONS; i++ )
  432. {
  433. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  434. if ( !pWeapon )
  435. continue;
  436. if ( pWeapon->CanBeSelected() )
  437. {
  438. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  439. // see if this weapon is further ahead in the selection list
  440. if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) )
  441. {
  442. // see if this weapon is closer than the current lowest
  443. if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) )
  444. {
  445. iLowestPrevSlot = weaponSlot;
  446. iLowestPrevPosition = weaponPosition;
  447. pPrevWeapon = pWeapon;
  448. }
  449. }
  450. }
  451. }
  452. return pPrevWeapon;
  453. }
  454. //-----------------------------------------------------------------------------
  455. // Purpose: Moves the selection to the next item in the menu
  456. //-----------------------------------------------------------------------------
  457. void CHudWeaponSelection::CycleToNextWeapon( void )
  458. {
  459. // Get the local player.
  460. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  461. if ( !pPlayer )
  462. return;
  463. C_BaseCombatWeapon *pNextWeapon = NULL;
  464. if ( IsInSelectionMode() )
  465. {
  466. // find the next selection spot
  467. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  468. if ( !pWeapon )
  469. return;
  470. pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  471. }
  472. else
  473. {
  474. // open selection at the current place
  475. pNextWeapon = pPlayer->GetActiveWeapon();
  476. if ( pNextWeapon )
  477. {
  478. pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  479. }
  480. }
  481. if ( !pNextWeapon )
  482. {
  483. // wrap around back to start
  484. pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1);
  485. }
  486. if ( pNextWeapon )
  487. {
  488. SetSelectedWeapon( pNextWeapon );
  489. if ( !IsInSelectionMode() )
  490. {
  491. OpenSelection();
  492. }
  493. // Play the "cycle to next weapon" sound
  494. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  495. }
  496. }
  497. //-----------------------------------------------------------------------------
  498. // Purpose: Moves the selection to the previous item in the menu
  499. //-----------------------------------------------------------------------------
  500. void CHudWeaponSelection::CycleToPrevWeapon( void )
  501. {
  502. // Get the local player.
  503. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  504. if ( !pPlayer )
  505. return;
  506. C_BaseCombatWeapon *pNextWeapon = NULL;
  507. if ( IsInSelectionMode() )
  508. {
  509. // find the next selection spot
  510. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  511. if ( !pWeapon )
  512. return;
  513. pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  514. }
  515. else
  516. {
  517. // open selection at the current place
  518. pNextWeapon = pPlayer->GetActiveWeapon();
  519. if ( pNextWeapon )
  520. {
  521. pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  522. }
  523. }
  524. if ( !pNextWeapon )
  525. {
  526. // wrap around back to end of weapon list
  527. pNextWeapon = FindPrevWeaponInWeaponSelection(MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS);
  528. }
  529. if ( pNextWeapon )
  530. {
  531. SetSelectedWeapon( pNextWeapon );
  532. if ( !IsInSelectionMode() )
  533. {
  534. OpenSelection();
  535. }
  536. // Play the "cycle to next weapon" sound
  537. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  538. }
  539. }
  540. //-----------------------------------------------------------------------------
  541. // Purpose: returns the weapon in the specified slot
  542. //-----------------------------------------------------------------------------
  543. C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
  544. {
  545. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  546. if ( !player )
  547. return NULL;
  548. for ( int i = 0; i < MAX_WEAPONS; i++ )
  549. {
  550. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  551. if ( pWeapon == NULL )
  552. continue;
  553. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos )
  554. return pWeapon;
  555. }
  556. return NULL;
  557. }
  558. //-----------------------------------------------------------------------------
  559. // Purpose: Opens the next weapon in the slot
  560. //-----------------------------------------------------------------------------
  561. void CHudWeaponSelection::FastWeaponSwitch( int iWeaponSlot )
  562. {
  563. // get the slot the player's weapon is in
  564. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  565. if ( !pPlayer )
  566. return;
  567. // see where we should start selection
  568. int iPosition = -1;
  569. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  570. if ( pActiveWeapon && pActiveWeapon->GetSlot() == iWeaponSlot )
  571. {
  572. // start after this weapon
  573. iPosition = pActiveWeapon->GetPosition();
  574. }
  575. C_BaseCombatWeapon *pNextWeapon = NULL;
  576. // search for the weapon after the current one
  577. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, iPosition);
  578. // make sure it's in the same bucket
  579. if ( !pNextWeapon || pNextWeapon->GetSlot() != iWeaponSlot )
  580. {
  581. // just look for any weapon in this slot
  582. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, -1);
  583. }
  584. // see if we found a weapon that's different from the current and in the selected slot
  585. if ( pNextWeapon && pNextWeapon != pActiveWeapon && pNextWeapon->GetSlot() == iWeaponSlot )
  586. {
  587. // select the new weapon
  588. ::input->MakeWeaponSelection( pNextWeapon );
  589. }
  590. else if ( pNextWeapon != pActiveWeapon )
  591. {
  592. // error sound
  593. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  594. }
  595. }
  596. //-----------------------------------------------------------------------------
  597. // Purpose: Moves selection to the specified slot
  598. //-----------------------------------------------------------------------------
  599. void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
  600. {
  601. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  602. --iSlot;
  603. // Get the local player.
  604. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  605. if ( !pPlayer )
  606. return;
  607. // Don't try and read past our possible number of slots
  608. if ( iSlot > MAX_WEAPON_SLOTS )
  609. return;
  610. // Make sure the player's allowed to switch weapons
  611. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  612. return;
  613. // do a fast switch if set
  614. if ( hud_fastswitch.GetBool() )
  615. {
  616. FastWeaponSwitch( iSlot );
  617. return;
  618. }
  619. int slotPos = 0;
  620. C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon();
  621. // start later in the list
  622. if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot )
  623. {
  624. slotPos = pActiveWeapon->GetPosition() + 1;
  625. }
  626. // find the weapon in this slot
  627. pActiveWeapon = GetNextActivePos( iSlot, slotPos );
  628. if ( !pActiveWeapon )
  629. {
  630. pActiveWeapon = GetNextActivePos( iSlot, 0 );
  631. }
  632. if ( pActiveWeapon != NULL )
  633. {
  634. if ( !IsInSelectionMode() )
  635. {
  636. // open the weapon selection
  637. OpenSelection();
  638. }
  639. // Mark the change
  640. SetSelectedWeapon( pActiveWeapon );
  641. }
  642. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  643. }