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.

845 lines
25 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 "iinput.h"
  11. #include "cs_gamerules.h"
  12. #include <KeyValues.h>
  13. #include <vgui/IScheme.h>
  14. #include <vgui/ISurface.h>
  15. #include <vgui/ISystem.h>
  16. #include <vgui_controls/AnimationController.h>
  17. #include <vgui_controls/Panel.h>
  18. #include "vgui/ILocalize.h"
  19. #include <string.h>
  20. //-----------------------------------------------------------------------------
  21. // Purpose: cstrike 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 void SwitchToLastWeapon( void );
  33. virtual C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
  34. virtual void SelectWeaponSlot( int iSlot );
  35. virtual void SelectWeapon( void );
  36. virtual C_BaseCombatWeapon *GetSelectedWeapon( void )
  37. {
  38. return m_hSelectedWeapon;
  39. }
  40. virtual void OpenSelection( void );
  41. virtual void HideSelection( void );
  42. virtual void CancelWeaponSelection( void );
  43. virtual void LevelInit();
  44. protected:
  45. virtual void OnThink();
  46. virtual void Paint();
  47. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  48. virtual bool IsWeaponSelectable()
  49. {
  50. if (IsInSelectionMode())
  51. return true;
  52. return false;
  53. }
  54. virtual bool IsHudMenuTakingInput();
  55. virtual bool IsHudMenuPreventingWeaponSelection();
  56. private:
  57. C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  58. C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  59. virtual void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon )
  60. {
  61. m_hSelectedWeapon = pWeapon;
  62. }
  63. void DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number);
  64. CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
  65. CPanelAnimationVar( vgui::HFont, m_hTextFont, "TextFont", "HudSelectionText" );
  66. CPanelAnimationVarAliasType( float, m_flSmallBoxSize, "SmallBoxSize", "32", "proportional_float" );
  67. CPanelAnimationVarAliasType( float, m_flLargeBoxWide, "LargeBoxWide", "108", "proportional_float" );
  68. CPanelAnimationVarAliasType( float, m_flLargeBoxTall, "LargeBoxTall", "72", "proportional_float" );
  69. CPanelAnimationVarAliasType( float, m_flBoxGap, "BoxGap", "12", "proportional_float" );
  70. CPanelAnimationVarAliasType( float, m_flSelectionNumberXPos, "SelectionNumberXPos", "4", "proportional_float" );
  71. CPanelAnimationVarAliasType( float, m_flSelectionNumberYPos, "SelectionNumberYPos", "4", "proportional_float" );
  72. CPanelAnimationVarAliasType( float, m_flIconXPos, "IconXPos", "16", "proportional_float" );
  73. CPanelAnimationVarAliasType( float, m_flIconYPos, "IconYPos", "8", "proportional_float" );
  74. CPanelAnimationVarAliasType( float, m_flTextYPos, "TextYPos", "54", "proportional_float" );
  75. CPanelAnimationVar( float, m_flAlphaOverride, "Alpha", "255" );
  76. CPanelAnimationVar( float, m_flSelectionAlphaOverride, "SelectionAlpha", "255" );
  77. CPanelAnimationVar( Color, m_TextColor, "TextColor", "SelectionTextFg" );
  78. CPanelAnimationVar( Color, m_NumberColor, "NumberColor", "SelectionNumberFg" );
  79. CPanelAnimationVar( Color, m_EmptyBoxColor, "EmptyBoxColor", "SelectionEmptyBoxBg" );
  80. CPanelAnimationVar( Color, m_BoxColor, "BoxColor", "SelectionBoxBg" );
  81. CPanelAnimationVar( Color, m_SelectedBoxColor, "SelectedBoxClor", "SelectionSelectedBoxBg" );
  82. CPanelAnimationVar( float, m_flWeaponPickupGrowTime, "SelectionGrowTime", "0.1" );
  83. CPanelAnimationVar( float, m_flTextScan, "TextScan", "1.0" );
  84. CPanelAnimationVar( int, m_iMaxSlots, "MaxSlots", "6" );
  85. CPanelAnimationVar( bool, m_bPlaySelectionSounds, "PlaySelectSounds", "1" );
  86. };
  87. DECLARE_HUDELEMENT( CHudWeaponSelection );
  88. using namespace vgui;
  89. //-----------------------------------------------------------------------------
  90. // Purpose: Constructor
  91. //-----------------------------------------------------------------------------
  92. CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection")
  93. {
  94. vgui::Panel *pParent = g_pClientMode->GetViewport();
  95. SetParent( pParent );
  96. SetHiddenBits( HIDEHUD_WEAPONSELECTION | HIDEHUD_PLAYERDEAD );
  97. }
  98. //-----------------------------------------------------------------------------
  99. // Purpose: sets up display for showing weapon pickup
  100. //-----------------------------------------------------------------------------
  101. void CHudWeaponSelection::OnWeaponPickup( C_BaseCombatWeapon *pWeapon )
  102. {
  103. // add to pickup history
  104. CHudHistoryResource *pHudHR = GET_HUDELEMENT( CHudHistoryResource );
  105. if ( pHudHR )
  106. {
  107. pHudHR->AddToHistory( pWeapon );
  108. }
  109. }
  110. //-----------------------------------------------------------------------------
  111. // Purpose: updates animation status
  112. //-----------------------------------------------------------------------------
  113. void CHudWeaponSelection::OnThink()
  114. {
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose: returns true if the CHudMenu should take slot1, etc commands
  118. //-----------------------------------------------------------------------------
  119. bool CHudWeaponSelection::IsHudMenuTakingInput()
  120. {
  121. return CBaseHudWeaponSelection::IsHudMenuTakingInput();
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: returns true if the weapon selection hud should be hidden because
  125. // the CHudMenu is open
  126. //-----------------------------------------------------------------------------
  127. bool CHudWeaponSelection::IsHudMenuPreventingWeaponSelection()
  128. {
  129. return false;
  130. }
  131. //-----------------------------------------------------------------------------
  132. // Purpose: returns true if the panel should draw
  133. //-----------------------------------------------------------------------------
  134. bool CHudWeaponSelection::ShouldDraw()
  135. {
  136. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  137. if ( !pPlayer )
  138. {
  139. if ( IsInSelectionMode() )
  140. {
  141. HideSelection();
  142. }
  143. return false;
  144. }
  145. bool bret = CBaseHudWeaponSelection::ShouldDraw();
  146. if ( !bret )
  147. return false;
  148. return ( m_bSelectionVisible ) ? true : false;
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose:
  152. //-----------------------------------------------------------------------------
  153. void CHudWeaponSelection::LevelInit()
  154. {
  155. CHudElement::LevelInit();
  156. m_iMaxSlots = clamp( m_iMaxSlots, 0, MAX_WEAPON_SLOTS );
  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 = (m_iMaxSlots - 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 < m_iMaxSlots; 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 selected weapon
  199. DrawBox(xpos, ypos, largeBoxWide, largeBoxTall, selectedColor, m_flSelectionAlphaOverride, bFirstItem ? i + 1 : -1);
  200. // draw icon
  201. Color col = GetFgColor();
  202. // icons use old system, drawing in screen space
  203. if ( pWeapon->GetSpriteActive() )
  204. {
  205. if (!pWeapon->CanBeSelected())
  206. {
  207. // unselectable weapon, display as such
  208. col = Color(255, 0, 0, col[3]);
  209. }
  210. else if (pWeapon == pSelectedWeapon)
  211. {
  212. // currently selected weapon, display brighter
  213. col[3] = m_flSelectionAlphaOverride;
  214. }
  215. pWeapon->GetSpriteActive()->DrawSelf( xpos + m_flIconXPos, ypos + m_flIconYPos, col );
  216. }
  217. // draw text
  218. col = m_TextColor;
  219. const FileWeaponInfo_t &weaponInfo = pWeapon->GetWpnData();
  220. if (pWeapon == pSelectedWeapon)
  221. {
  222. wchar_t text[128];
  223. wchar_t *tempString = g_pVGuiLocalize->Find(weaponInfo.szPrintName);
  224. // setup our localized string
  225. if ( tempString )
  226. {
  227. #ifdef WIN32
  228. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%s", tempString);
  229. #else
  230. _snwprintf(text, sizeof(text)/sizeof(wchar_t) - 1, L"%S", tempString);
  231. #endif
  232. text[sizeof(text)/sizeof(wchar_t) - 1] = 0;
  233. }
  234. else
  235. {
  236. // string wasn't found by g_pVGuiLocalize->Find()
  237. g_pVGuiLocalize->ConvertANSIToUnicode(weaponInfo.szPrintName, text, sizeof(text));
  238. }
  239. surface()->DrawSetTextColor( col );
  240. surface()->DrawSetTextFont( m_hTextFont );
  241. // count the position
  242. int slen = 0, charCount = 0, maxslen = 0;
  243. {
  244. for (wchar_t *pch = text; *pch != 0; pch++)
  245. {
  246. if (*pch == '\n')
  247. {
  248. // newline character, drop to the next line
  249. if (slen > maxslen)
  250. {
  251. maxslen = slen;
  252. }
  253. slen = 0;
  254. }
  255. else if (*pch == '\r')
  256. {
  257. // do nothing
  258. }
  259. else
  260. {
  261. slen += surface()->GetCharacterWidth( m_hTextFont, *pch );
  262. charCount++;
  263. }
  264. }
  265. }
  266. if (slen > maxslen)
  267. {
  268. maxslen = slen;
  269. }
  270. int tx = xpos + ((largeBoxWide - maxslen) / 2);
  271. int ty = ypos + (int)m_flTextYPos;
  272. surface()->DrawSetTextPos( tx, ty );
  273. // adjust the charCount by the scan amount
  274. charCount *= m_flTextScan;
  275. for (wchar_t *pch = text; charCount > 0; pch++)
  276. {
  277. if (*pch == '\n')
  278. {
  279. // newline character, move to the next line
  280. surface()->DrawSetTextPos( xpos + ((largeBoxWide - slen) / 2), ty + (surface()->GetFontTall(m_hTextFont) * 1.1f));
  281. }
  282. else if (*pch == '\r')
  283. {
  284. // do nothing
  285. }
  286. else
  287. {
  288. surface()->DrawUnicodeChar(*pch);
  289. charCount--;
  290. }
  291. }
  292. }
  293. ypos += (largeBoxTall + m_flBoxGap);
  294. bFirstItem = false;
  295. }
  296. xpos += largeBoxWide;
  297. }
  298. else
  299. {
  300. // check to see if there is a weapons in this bucket
  301. if ( GetFirstPos( i ) )
  302. {
  303. // draw has weapon in slot
  304. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_BoxColor, m_flAlphaOverride, i + 1);
  305. }
  306. else
  307. {
  308. // draw empty slot
  309. DrawBox(xpos, ypos, m_flSmallBoxSize, m_flSmallBoxSize, m_EmptyBoxColor, m_flAlphaOverride, -1);
  310. }
  311. xpos += m_flSmallBoxSize;
  312. }
  313. // reset position
  314. ypos = 0;
  315. xpos += m_flBoxGap;
  316. }
  317. }
  318. //-----------------------------------------------------------------------------
  319. // Purpose: draws a selection box
  320. //-----------------------------------------------------------------------------
  321. void CHudWeaponSelection::DrawBox(int x, int y, int wide, int tall, Color color, float normalizedAlpha, int number)
  322. {
  323. BaseClass::DrawBox( x, y, wide, tall, color, normalizedAlpha / 255.0f );
  324. // draw the number
  325. if (number >= 0)
  326. {
  327. Color numberColor = m_NumberColor;
  328. numberColor[3] *= normalizedAlpha / 255.0f;
  329. surface()->DrawSetTextColor(numberColor);
  330. surface()->DrawSetTextFont(m_hNumberFont);
  331. wchar_t wch = '0' + number;
  332. surface()->DrawSetTextPos(x + m_flSelectionNumberXPos, y + m_flSelectionNumberYPos);
  333. surface()->DrawUnicodeChar(wch);
  334. }
  335. }
  336. //-----------------------------------------------------------------------------
  337. // Purpose: hud scheme settings
  338. //-----------------------------------------------------------------------------
  339. void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
  340. {
  341. BaseClass::ApplySchemeSettings(pScheme);
  342. SetPaintBackgroundEnabled(false);
  343. // set our size
  344. int screenWide, screenTall;
  345. int x, y;
  346. GetPos(x, y);
  347. GetHudSize(screenWide, screenTall);
  348. SetBounds(0, y, screenWide, screenTall - y);
  349. }
  350. //-----------------------------------------------------------------------------
  351. // Purpose: Opens weapon selection control
  352. //-----------------------------------------------------------------------------
  353. void CHudWeaponSelection::OpenSelection( void )
  354. {
  355. Assert(!IsInSelectionMode());
  356. CBaseHudWeaponSelection::OpenSelection();
  357. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("OpenWeaponSelectionMenu");
  358. }
  359. //-----------------------------------------------------------------------------
  360. // Purpose: Closes weapon selection control
  361. //-----------------------------------------------------------------------------
  362. void CHudWeaponSelection::HideSelection( void )
  363. {
  364. CBaseHudWeaponSelection::HideSelection();
  365. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence("CloseWeaponSelectionMenu");
  366. }
  367. //-----------------------------------------------------------------------------
  368. // Purpose: Returns the next available weapon item in the weapon selection
  369. //-----------------------------------------------------------------------------
  370. C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  371. {
  372. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  373. if ( !pPlayer )
  374. return NULL;
  375. C_BaseCombatWeapon *pNextWeapon = NULL;
  376. // search all the weapons looking for the closest next
  377. int iLowestNextSlot = MAX_WEAPON_SLOTS;
  378. int iLowestNextPosition = MAX_WEAPON_POSITIONS;
  379. for ( int i = 0; i < MAX_WEAPONS; i++ )
  380. {
  381. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  382. if ( !pWeapon )
  383. continue;
  384. if ( pWeapon->CanBeSelected() )
  385. {
  386. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  387. // see if this weapon is further ahead in the selection list
  388. if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) )
  389. {
  390. // see if this weapon is closer than the current lowest
  391. if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) )
  392. {
  393. iLowestNextSlot = weaponSlot;
  394. iLowestNextPosition = weaponPosition;
  395. pNextWeapon = pWeapon;
  396. }
  397. }
  398. }
  399. }
  400. return pNextWeapon;
  401. }
  402. //-----------------------------------------------------------------------------
  403. // Purpose: Returns the prior available weapon item in the weapon selection
  404. //-----------------------------------------------------------------------------
  405. C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  406. {
  407. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  408. if ( !pPlayer )
  409. return NULL;
  410. C_BaseCombatWeapon *pPrevWeapon = NULL;
  411. // search all the weapons looking for the closest next
  412. int iLowestPrevSlot = -1;
  413. int iLowestPrevPosition = -1;
  414. for ( int i = 0; i < MAX_WEAPONS; i++ )
  415. {
  416. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  417. if ( !pWeapon )
  418. continue;
  419. if ( pWeapon->CanBeSelected() )
  420. {
  421. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  422. // see if this weapon is further ahead in the selection list
  423. if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) )
  424. {
  425. // see if this weapon is closer than the current lowest
  426. if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) )
  427. {
  428. iLowestPrevSlot = weaponSlot;
  429. iLowestPrevPosition = weaponPosition;
  430. pPrevWeapon = pWeapon;
  431. }
  432. }
  433. }
  434. }
  435. return pPrevWeapon;
  436. }
  437. //-----------------------------------------------------------------------------
  438. // Purpose: Moves the selection to the next item in the menu
  439. //-----------------------------------------------------------------------------
  440. void CHudWeaponSelection::CycleToNextWeapon( void )
  441. {
  442. // Get the local player.
  443. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  444. if ( !pPlayer )
  445. return;
  446. C_BaseCombatWeapon *pNextWeapon = NULL;
  447. if ( IsInSelectionMode() )
  448. {
  449. // find the next selection spot
  450. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  451. if ( !pWeapon )
  452. return;
  453. pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  454. }
  455. else
  456. {
  457. // open selection at the current place
  458. pNextWeapon = pPlayer->GetActiveWeapon();
  459. if ( pNextWeapon )
  460. {
  461. pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  462. }
  463. }
  464. if ( !pNextWeapon )
  465. {
  466. // wrap around back to start
  467. pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1);
  468. }
  469. if ( pNextWeapon )
  470. {
  471. SetSelectedWeapon( pNextWeapon );
  472. if( hud_fastswitch.GetInt() > 0 )
  473. {
  474. SelectWeapon();
  475. }
  476. else if ( !IsInSelectionMode() )
  477. {
  478. OpenSelection();
  479. }
  480. // Play the "cycle to next weapon" sound
  481. if( m_bPlaySelectionSounds )
  482. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  483. }
  484. }
  485. //-----------------------------------------------------------------------------
  486. // Purpose: Moves the selection to the previous item in the menu
  487. //-----------------------------------------------------------------------------
  488. void CHudWeaponSelection::CycleToPrevWeapon( void )
  489. {
  490. // Get the local player.
  491. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  492. if ( !pPlayer )
  493. return;
  494. if ( pPlayer->IsPlayerDead() )
  495. return;
  496. C_BaseCombatWeapon *pNextWeapon = NULL;
  497. if ( IsInSelectionMode() )
  498. {
  499. // find the next selection spot
  500. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  501. if ( !pWeapon )
  502. return;
  503. pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  504. }
  505. else
  506. {
  507. // open selection at the current place
  508. pNextWeapon = pPlayer->GetActiveWeapon();
  509. if ( pNextWeapon )
  510. {
  511. pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  512. }
  513. }
  514. if ( !pNextWeapon )
  515. {
  516. // wrap around back to end of weapon list
  517. pNextWeapon = FindPrevWeaponInWeaponSelection(MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS);
  518. }
  519. if ( pNextWeapon )
  520. {
  521. SetSelectedWeapon( pNextWeapon );
  522. if( hud_fastswitch.GetInt() > 0 )
  523. {
  524. SelectWeapon();
  525. }
  526. else if ( !IsInSelectionMode() )
  527. {
  528. OpenSelection();
  529. }
  530. // Play the "cycle to next weapon" sound
  531. if( m_bPlaySelectionSounds )
  532. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  533. }
  534. }
  535. //-----------------------------------------------------------------------------
  536. // Purpose: Switches the last weapon the player was using
  537. //-----------------------------------------------------------------------------
  538. void CHudWeaponSelection::SwitchToLastWeapon( void )
  539. {
  540. // Get the player's last weapon
  541. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  542. if ( !player )
  543. return;
  544. if ( player->IsPlayerDead() )
  545. return;
  546. C_BaseCombatWeapon *lastWeapon = player->GetLastWeapon();
  547. C_BaseCombatWeapon *activeWeapon = player->GetActiveWeapon();
  548. if ( lastWeapon == activeWeapon )
  549. lastWeapon = NULL;
  550. // make sure our last weapon is still with us and valid (has ammo etc)
  551. if ( lastWeapon )
  552. {
  553. int i;
  554. for ( i = 0; i < MAX_WEAPONS; i++ )
  555. {
  556. C_BaseCombatWeapon *weapon = player->GetWeapon(i);
  557. if ( !weapon || !weapon->CanBeSelected() )
  558. continue;
  559. if (weapon == lastWeapon )
  560. break;
  561. }
  562. if ( i == MAX_WEAPONS )
  563. lastWeapon = NULL; // weapon not found/valid
  564. }
  565. // if we don't have a 'last weapon' choose best weapon
  566. if ( !lastWeapon )
  567. {
  568. lastWeapon = GameRules()->GetNextBestWeapon( player, activeWeapon );
  569. }
  570. ::input->MakeWeaponSelection( lastWeapon );
  571. }
  572. //-----------------------------------------------------------------------------
  573. // Purpose: returns the weapon in the specified slot
  574. //-----------------------------------------------------------------------------
  575. C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
  576. {
  577. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  578. if ( !player )
  579. return NULL;
  580. if ( player->IsPlayerDead() )
  581. return NULL;
  582. for ( int i = 0; i < MAX_WEAPONS; i++ )
  583. {
  584. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  585. if ( pWeapon == NULL )
  586. continue;
  587. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos )
  588. return pWeapon;
  589. }
  590. return NULL;
  591. }
  592. //-----------------------------------------------------------------------------
  593. // Purpose: Player has chosen to draw the currently selected weapon
  594. //-----------------------------------------------------------------------------
  595. void CHudWeaponSelection::SelectWeapon( void )
  596. {
  597. if ( !GetSelectedWeapon() )
  598. {
  599. engine->ClientCmd( "cancelselect\n" );
  600. return;
  601. }
  602. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  603. if ( !player )
  604. return;
  605. C_BaseCombatWeapon *activeWeapon = player->GetActiveWeapon();
  606. // Don't allow selections of weapons that can't be selected (out of ammo, etc)
  607. if ( !GetSelectedWeapon()->CanBeSelected() )
  608. {
  609. player->EmitSound( "Player.DenyWeaponSelection" );
  610. }
  611. else
  612. {
  613. // Only play the "weapon selected" sound if they are selecting
  614. // a weapon different than the one that is already active.
  615. if (GetSelectedWeapon() != activeWeapon)
  616. {
  617. // Play the "weapon selected" sound
  618. player->EmitSound( "Player.WeaponSelected" );
  619. }
  620. SetWeaponSelected();
  621. m_hSelectedWeapon = NULL;
  622. engine->ClientCmd( "cancelselect\n" );
  623. }
  624. }
  625. //-----------------------------------------------------------------------------
  626. // Purpose: Abort selecting a weapon
  627. //-----------------------------------------------------------------------------
  628. void CHudWeaponSelection::CancelWeaponSelection()
  629. {
  630. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  631. if ( !player )
  632. return;
  633. // Fastswitches happen in a single frame, so the Weapon Selection HUD Element isn't visible
  634. // yet, but it's going to be next frame. We need to ask it if it thinks it's going to draw,
  635. // instead of checking it's IsActive flag.
  636. if ( ShouldDraw() )
  637. {
  638. HideSelection();
  639. m_hSelectedWeapon = NULL;
  640. }
  641. else
  642. {
  643. engine->ClientCmd("escape");
  644. }
  645. }
  646. //-----------------------------------------------------------------------------
  647. // Purpose: Moves selection to the specified slot
  648. //-----------------------------------------------------------------------------
  649. void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
  650. {
  651. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  652. --iSlot;
  653. // Get the local player.
  654. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  655. if ( !pPlayer )
  656. return;
  657. // Don't try and read past our possible number of slots
  658. if ( iSlot > MAX_WEAPON_SLOTS )
  659. return;
  660. // Make sure the player's allowed to switch weapons
  661. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  662. return;
  663. int slotPos = 0;
  664. C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon();
  665. // start later in the list
  666. if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot )
  667. {
  668. slotPos = pActiveWeapon->GetPosition() + 1;
  669. }
  670. // find the weapon in this slot
  671. pActiveWeapon = GetNextActivePos( iSlot, slotPos );
  672. if ( !pActiveWeapon )
  673. {
  674. pActiveWeapon = GetNextActivePos( iSlot, 0 );
  675. }
  676. if ( pActiveWeapon != NULL )
  677. {
  678. // Mark the change
  679. SetSelectedWeapon( pActiveWeapon );
  680. bool bMultipleWeaponsInSlot = false;
  681. for( int i=0;i<MAX_WEAPON_POSITIONS;i++ )
  682. {
  683. C_BaseCombatWeapon *pSlotWpn = GetWeaponInSlot( pActiveWeapon->GetSlot(), i );
  684. if( pSlotWpn != NULL && pSlotWpn != pActiveWeapon )
  685. {
  686. bMultipleWeaponsInSlot = true;
  687. break;
  688. }
  689. }
  690. // if fast weapon switch is on, then weapons can be selected in a single keypress
  691. // but only if there is only one item in the bucket
  692. if( hud_fastswitch.GetInt() > 0 && bMultipleWeaponsInSlot == false )
  693. {
  694. // only one active item in bucket, so change directly to weapon
  695. SelectWeapon();
  696. }
  697. else if ( !IsInSelectionMode() )
  698. {
  699. // open the weapon selection
  700. OpenSelection();
  701. }
  702. }
  703. if( m_bPlaySelectionSounds )
  704. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  705. }