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.

670 lines
17 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 "ammodef.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/Panel.h>
  16. #include <string.h>
  17. #define HL1_MAX_WEAPON_SLOTS 5
  18. //-----------------------------------------------------------------------------
  19. // Purpose: hl2 weapon selection hud element
  20. //-----------------------------------------------------------------------------
  21. class CHudWeaponSelection : public CBaseHudWeaponSelection, public vgui::Panel
  22. {
  23. DECLARE_CLASS_SIMPLE( CHudWeaponSelection, vgui::Panel );
  24. public:
  25. CHudWeaponSelection(const char *pElementName );
  26. bool ShouldDraw();
  27. void CycleToNextWeapon( void );
  28. void CycleToPrevWeapon( void );
  29. C_BaseCombatWeapon *GetWeaponInSlot( int iSlot, int iSlotPos );
  30. void SelectWeaponSlot( int iSlot );
  31. C_BaseCombatWeapon *GetSelectedWeapon( void )
  32. {
  33. return m_hSelectedWeapon;
  34. }
  35. void VidInit( void );
  36. C_BaseCombatWeapon *GetNextActivePos( int iSlot, int iSlotPos );
  37. protected:
  38. void Paint();
  39. void ApplySchemeSettings(vgui::IScheme *pScheme);
  40. private:
  41. C_BaseCombatWeapon *FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  42. C_BaseCombatWeapon *FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition);
  43. void FastWeaponSwitch( int iWeaponSlot );
  44. void DrawAmmoBar( C_BaseCombatWeapon *pWeapon, int x, int y, int nWidth, int nHeight );
  45. int DrawBar( int x, int y, int width, int height, float f );
  46. void SetSelectedWeapon( C_BaseCombatWeapon *pWeapon )
  47. {
  48. m_hSelectedWeapon = pWeapon;
  49. }
  50. CHudTexture *icon_buckets[ HL1_MAX_WEAPON_SLOTS ];
  51. CHudTexture *icon_selection;
  52. Color m_clrReddish;
  53. Color m_clrGreenish;
  54. };
  55. DECLARE_HUDELEMENT( CHudWeaponSelection );
  56. using namespace vgui;
  57. //-----------------------------------------------------------------------------
  58. // Purpose: Constructor
  59. //-----------------------------------------------------------------------------
  60. CHudWeaponSelection::CHudWeaponSelection( const char *pElementName ) : CBaseHudWeaponSelection(pElementName), BaseClass(NULL, "HudWeaponSelection")
  61. {
  62. vgui::Panel *pParent = g_pClientMode->GetViewport();
  63. SetParent( pParent );
  64. }
  65. void CHudWeaponSelection::VidInit()
  66. {
  67. Reset();
  68. for ( int i = 0; i < HL1_MAX_WEAPON_SLOTS; i++ )
  69. {
  70. char szNumString[ 10 ];
  71. sprintf( szNumString, "bucket%d", i );
  72. icon_buckets[ i ] = gHUD.GetIcon( szNumString );
  73. }
  74. }
  75. //-----------------------------------------------------------------------------
  76. // Purpose: returns true if the panel should draw
  77. //-----------------------------------------------------------------------------
  78. bool CHudWeaponSelection::ShouldDraw()
  79. {
  80. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  81. if ( !pPlayer )
  82. {
  83. if ( IsInSelectionMode() )
  84. {
  85. HideSelection();
  86. }
  87. return false;
  88. }
  89. bool bret = CBaseHudWeaponSelection::ShouldDraw();
  90. if ( !bret )
  91. return false;
  92. return ( m_bSelectionVisible ) ? true : false;
  93. }
  94. //-------------------------------------------------------------------------
  95. // Purpose: draws the selection area
  96. //-------------------------------------------------------------------------
  97. void CHudWeaponSelection::Paint()
  98. {
  99. if (!ShouldDraw())
  100. return;
  101. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  102. if ( !pPlayer )
  103. return;
  104. // find and display our current selection
  105. C_BaseCombatWeapon *pSelectedWeapon = GetSelectedWeapon();
  106. if ( !pSelectedWeapon )
  107. return;
  108. int iActiveSlot = (pSelectedWeapon ? pSelectedWeapon->GetSlot() : -1);
  109. int xpos = 10;
  110. // iterate over all the weapon slots
  111. for ( int i = 0; i < HL1_MAX_WEAPON_SLOTS; i++ )
  112. {
  113. int nWidth;
  114. int r1, g1, b1, a1;
  115. (gHUD.m_clrYellowish).GetColor( r1, g1, b1, a1 );
  116. int ypos = 10;
  117. icon_buckets[ i ]->DrawSelf( xpos, ypos, Color( r1, g1, b1, 255 ) );
  118. ypos = icon_buckets[ i ]->Height() + 10;
  119. if ( i == iActiveSlot )
  120. {
  121. bool bFirstItem = true;
  122. nWidth = icon_buckets[ i ]->Width();
  123. for ( int slotpos = 0; slotpos < MAX_WEAPON_POSITIONS; slotpos++ )
  124. {
  125. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, slotpos );
  126. if ( !pWeapon )
  127. continue;
  128. // icons use old system, drawing in screen space
  129. if ( pWeapon->GetSpriteActive() )
  130. {
  131. int r, g, b, a;
  132. (gHUD.m_clrYellowish).GetColor( r, g, b, a );
  133. if (pWeapon == pSelectedWeapon)
  134. {
  135. pWeapon->GetSpriteActive()->DrawSelf( xpos, ypos, Color( r, g, b, a ) );
  136. if ( !icon_selection )
  137. {
  138. icon_selection = gHUD.GetIcon( "selection" );
  139. }
  140. if ( icon_selection )
  141. {
  142. icon_selection->DrawSelf( xpos, ypos, Color( r, g, b, a ) );
  143. }
  144. }
  145. else
  146. {
  147. if ( pWeapon->HasAmmo() )
  148. {
  149. a = 192;
  150. }
  151. else
  152. {
  153. m_clrReddish.GetColor( r, g, b, a );
  154. a = 128;
  155. }
  156. if ( pWeapon->GetSpriteInactive() )
  157. {
  158. pWeapon->GetSpriteInactive()->DrawSelf( xpos, ypos, Color( r, g, b, a ) );
  159. }
  160. }
  161. }
  162. // Draw Ammo Bar
  163. DrawAmmoBar( pWeapon, xpos + 10, ypos, 20, 4 );
  164. ypos += pWeapon->GetSpriteActive()->Height() + 5;
  165. if ( bFirstItem )
  166. {
  167. nWidth = pWeapon->GetSpriteActive()->Width();
  168. bFirstItem = false;
  169. }
  170. }
  171. }
  172. else
  173. {
  174. // Draw Row of weapons.
  175. for ( int iPos = 0; iPos < MAX_WEAPON_POSITIONS; iPos++ )
  176. {
  177. int r2, g2, b2, a2;
  178. C_BaseCombatWeapon *pWeapon = GetWeaponInSlot( i, iPos );
  179. if ( !pWeapon )
  180. continue;
  181. if ( pWeapon->HasAmmo() )
  182. {
  183. (gHUD.m_clrYellowish).GetColor( r2, g2, b2, a2 );
  184. a2 = 128;
  185. }
  186. else
  187. {
  188. m_clrReddish.GetColor( r2, g2, b2, a2 );
  189. a2 = 96;
  190. }
  191. Color clrBox( r2, g2, b2, a2 );
  192. vgui::surface()->DrawSetColor( clrBox );
  193. vgui::surface()->DrawFilledRect( xpos, ypos, xpos + icon_buckets[ i ]->Width(), ypos + icon_buckets[ i ]->Height() );
  194. ypos += icon_buckets[ i ]->Height() + 5;
  195. }
  196. nWidth = icon_buckets[ i ]->Width();
  197. }
  198. // advance position
  199. xpos += nWidth + 5;
  200. }
  201. }
  202. void CHudWeaponSelection::DrawAmmoBar( C_BaseCombatWeapon *pWeapon, int x, int y, int nWidth, int nHeight )
  203. {
  204. if ( pWeapon->GetPrimaryAmmoType() != -1 )
  205. {
  206. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  207. int nAmmoCount = pPlayer->GetAmmoCount( pWeapon->GetPrimaryAmmoType() );
  208. if ( !nAmmoCount )
  209. return;
  210. float flPct = (float)nAmmoCount / (float)GetAmmoDef()->MaxCarry( pWeapon->GetPrimaryAmmoType() );
  211. x = DrawBar( x, y, nWidth, nHeight, flPct );
  212. // Do we have secondary ammo too?
  213. if ( pWeapon->GetSecondaryAmmoType() != -1 )
  214. {
  215. flPct = (float)pPlayer->GetAmmoCount( pWeapon->GetSecondaryAmmoType() ) / (float)GetAmmoDef()->MaxCarry( pWeapon->GetSecondaryAmmoType() );
  216. x += 5; //!!!
  217. DrawBar( x, y, nWidth, nHeight, flPct );
  218. }
  219. }
  220. }
  221. int CHudWeaponSelection::DrawBar( int x, int y, int nWidth, int nHeight, float flPct )
  222. {
  223. Color clrBar;
  224. int r, g, b, a;
  225. if ( flPct < 0 )
  226. {
  227. flPct = 0;
  228. }
  229. else if ( flPct > 1 )
  230. {
  231. flPct = 1;
  232. }
  233. if ( flPct )
  234. {
  235. int nBarWidth = flPct * nWidth;
  236. // Always show at least one pixel if we have ammo.
  237. if (nBarWidth <= 0)
  238. nBarWidth = 1;
  239. m_clrGreenish.GetColor( r, g, b, a );
  240. clrBar.SetColor( r, g, b, 255 );
  241. vgui::surface()->DrawSetColor( clrBar );
  242. vgui::surface()->DrawFilledRect( x, y, x + nBarWidth, y + nHeight );
  243. x += nBarWidth;
  244. nWidth -= nBarWidth;
  245. }
  246. (gHUD.m_clrYellowish).GetColor( r, g, b, a );
  247. clrBar.SetColor( r, g, b, 128 );
  248. vgui::surface()->DrawSetColor( clrBar );
  249. vgui::surface()->DrawFilledRect( x, y, x + nWidth, y + nHeight );
  250. return ( x + nWidth );
  251. }
  252. //-----------------------------------------------------------------------------
  253. // Purpose: hud scheme settings
  254. //-----------------------------------------------------------------------------
  255. void CHudWeaponSelection::ApplySchemeSettings(vgui::IScheme *pScheme)
  256. {
  257. BaseClass::ApplySchemeSettings(pScheme);
  258. SetPaintBackgroundEnabled(false);
  259. // set our size
  260. int screenWide, screenTall;
  261. int x, y;
  262. GetPos(x, y);
  263. GetHudSize(screenWide, screenTall);
  264. SetBounds(0, y, screenWide, screenTall - y);
  265. m_clrReddish = pScheme->GetColor( "Reddish", Color( 255, 16, 16, 255 ) );
  266. m_clrGreenish = pScheme->GetColor( "Greenish", Color( 255, 16, 16, 255 ) );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Returns the next available weapon item in the weapon selection
  270. //-----------------------------------------------------------------------------
  271. C_BaseCombatWeapon *CHudWeaponSelection::FindNextWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  272. {
  273. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  274. if ( !pPlayer )
  275. return NULL;
  276. C_BaseCombatWeapon *pNextWeapon = NULL;
  277. // search all the weapons looking for the closest next
  278. int iLowestNextSlot = HL1_MAX_WEAPON_SLOTS;
  279. int iLowestNextPosition = MAX_WEAPON_POSITIONS;
  280. for ( int i = 0; i < MAX_WEAPONS; i++ )
  281. {
  282. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  283. if ( !pWeapon )
  284. continue;
  285. if ( pWeapon->CanBeSelected() )
  286. {
  287. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  288. // see if this weapon is further ahead in the selection list
  289. if ( weaponSlot > iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition > iCurrentPosition) )
  290. {
  291. // see if this weapon is closer than the current lowest
  292. if ( weaponSlot < iLowestNextSlot || (weaponSlot == iLowestNextSlot && weaponPosition < iLowestNextPosition) )
  293. {
  294. iLowestNextSlot = weaponSlot;
  295. iLowestNextPosition = weaponPosition;
  296. pNextWeapon = pWeapon;
  297. }
  298. }
  299. }
  300. }
  301. return pNextWeapon;
  302. }
  303. //-----------------------------------------------------------------------------
  304. // Purpose: Returns the prior available weapon item in the weapon selection
  305. //-----------------------------------------------------------------------------
  306. C_BaseCombatWeapon *CHudWeaponSelection::FindPrevWeaponInWeaponSelection(int iCurrentSlot, int iCurrentPosition)
  307. {
  308. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  309. if ( !pPlayer )
  310. return NULL;
  311. C_BaseCombatWeapon *pPrevWeapon = NULL;
  312. // search all the weapons looking for the closest next
  313. int iLowestPrevSlot = -1;
  314. int iLowestPrevPosition = -1;
  315. for ( int i = 0; i < MAX_WEAPONS; i++ )
  316. {
  317. C_BaseCombatWeapon *pWeapon = pPlayer->GetWeapon(i);
  318. if ( !pWeapon )
  319. continue;
  320. if ( pWeapon->CanBeSelected() )
  321. {
  322. int weaponSlot = pWeapon->GetSlot(), weaponPosition = pWeapon->GetPosition();
  323. // see if this weapon is further ahead in the selection list
  324. if ( weaponSlot < iCurrentSlot || (weaponSlot == iCurrentSlot && weaponPosition < iCurrentPosition) )
  325. {
  326. // see if this weapon is closer than the current lowest
  327. if ( weaponSlot > iLowestPrevSlot || (weaponSlot == iLowestPrevSlot && weaponPosition > iLowestPrevPosition) )
  328. {
  329. iLowestPrevSlot = weaponSlot;
  330. iLowestPrevPosition = weaponPosition;
  331. pPrevWeapon = pWeapon;
  332. }
  333. }
  334. }
  335. }
  336. return pPrevWeapon;
  337. }
  338. //-----------------------------------------------------------------------------
  339. // Purpose: Moves the selection to the next item in the menu
  340. //-----------------------------------------------------------------------------
  341. void CHudWeaponSelection::CycleToNextWeapon( void )
  342. {
  343. // Get the local player.
  344. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  345. if ( !pPlayer )
  346. return;
  347. C_BaseCombatWeapon *pNextWeapon = NULL;
  348. if ( IsInSelectionMode() )
  349. {
  350. // find the next selection spot
  351. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  352. if ( !pWeapon )
  353. return;
  354. pNextWeapon = FindNextWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  355. }
  356. else
  357. {
  358. // open selection at the current place
  359. pNextWeapon = pPlayer->GetActiveWeapon();
  360. if ( pNextWeapon )
  361. {
  362. pNextWeapon = FindNextWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  363. }
  364. }
  365. if ( !pNextWeapon )
  366. {
  367. // wrap around back to start
  368. pNextWeapon = FindNextWeaponInWeaponSelection(-1, -1);
  369. }
  370. if ( pNextWeapon )
  371. {
  372. SetSelectedWeapon( pNextWeapon );
  373. if( hud_fastswitch.GetInt() > 0 )
  374. {
  375. SelectWeapon();
  376. }
  377. else if ( !IsInSelectionMode() )
  378. {
  379. OpenSelection();
  380. }
  381. // Play the "cycle to next weapon" sound
  382. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  383. }
  384. }
  385. //-----------------------------------------------------------------------------
  386. // Purpose: Moves the selection to the previous item in the menu
  387. //-----------------------------------------------------------------------------
  388. void CHudWeaponSelection::CycleToPrevWeapon( void )
  389. {
  390. // Get the local player.
  391. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  392. if ( !pPlayer )
  393. return;
  394. C_BaseCombatWeapon *pNextWeapon = NULL;
  395. if ( IsInSelectionMode() )
  396. {
  397. // find the next selection spot
  398. C_BaseCombatWeapon *pWeapon = GetSelectedWeapon();
  399. if ( !pWeapon )
  400. return;
  401. pNextWeapon = FindPrevWeaponInWeaponSelection( pWeapon->GetSlot(), pWeapon->GetPosition() );
  402. }
  403. else
  404. {
  405. // open selection at the current place
  406. pNextWeapon = pPlayer->GetActiveWeapon();
  407. if ( pNextWeapon )
  408. {
  409. pNextWeapon = FindPrevWeaponInWeaponSelection( pNextWeapon->GetSlot(), pNextWeapon->GetPosition() );
  410. }
  411. }
  412. if ( !pNextWeapon )
  413. {
  414. // wrap around back to end of weapon list
  415. pNextWeapon = FindPrevWeaponInWeaponSelection( HL1_MAX_WEAPON_SLOTS, MAX_WEAPON_POSITIONS );
  416. }
  417. if ( pNextWeapon )
  418. {
  419. SetSelectedWeapon( pNextWeapon );
  420. if( hud_fastswitch.GetInt() > 0 )
  421. {
  422. SelectWeapon();
  423. }
  424. else if ( !IsInSelectionMode() )
  425. {
  426. OpenSelection();
  427. }
  428. // Play the "cycle to next weapon" sound
  429. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  430. }
  431. }
  432. //-----------------------------------------------------------------------------
  433. // Purpose: returns the weapon in the specified slot
  434. //-----------------------------------------------------------------------------
  435. C_BaseCombatWeapon *CHudWeaponSelection::GetWeaponInSlot( int iSlot, int iSlotPos )
  436. {
  437. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  438. if ( !player )
  439. return NULL;
  440. for ( int i = 0; i < MAX_WEAPONS; i++ )
  441. {
  442. C_BaseCombatWeapon *pWeapon = player->GetWeapon(i);
  443. if ( pWeapon == NULL )
  444. continue;
  445. if ( pWeapon->GetSlot() == iSlot && pWeapon->GetPosition() == iSlotPos )
  446. return pWeapon;
  447. }
  448. return NULL;
  449. }
  450. //-----------------------------------------------------------------------------
  451. // Purpose: Moves selection to the specified slot
  452. //-----------------------------------------------------------------------------
  453. void CHudWeaponSelection::SelectWeaponSlot( int iSlot )
  454. {
  455. // iSlot is one higher than it should be, since it's the number key, not the 0-based index into the weapons
  456. --iSlot;
  457. // Get the local player.
  458. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  459. if ( !pPlayer )
  460. return;
  461. // Don't try and read past our possible number of slots
  462. if ( iSlot > HL1_MAX_WEAPON_SLOTS )
  463. return;
  464. // Make sure the player's allowed to switch weapons
  465. if ( pPlayer->IsAllowedToSwitchWeapons() == false )
  466. return;
  467. // do a fast switch if set
  468. if ( hud_fastswitch.GetBool() )
  469. {
  470. FastWeaponSwitch( iSlot );
  471. return;
  472. }
  473. int slotPos = 0;
  474. C_BaseCombatWeapon *pActiveWeapon = GetSelectedWeapon();
  475. // start later in the list
  476. if ( IsInSelectionMode() && pActiveWeapon && pActiveWeapon->GetSlot() == iSlot )
  477. {
  478. slotPos = pActiveWeapon->GetPosition() + 1;
  479. }
  480. // find the weapon in this slot
  481. pActiveWeapon = GetNextActivePos( iSlot, slotPos );
  482. if ( !pActiveWeapon )
  483. {
  484. pActiveWeapon = GetNextActivePos( iSlot, 0 );
  485. }
  486. if ( pActiveWeapon != NULL )
  487. {
  488. SetSelectedWeapon( pActiveWeapon );
  489. if( hud_fastswitch.GetInt() > 0 )
  490. {
  491. // only one active item in bucket, so change directly to weapon
  492. SelectWeapon();
  493. }
  494. else if ( !IsInSelectionMode() )
  495. {
  496. // open the weapon selection
  497. OpenSelection();
  498. }
  499. }
  500. pPlayer->EmitSound( "Player.WeaponSelectionMoveSlot" );
  501. }
  502. //-----------------------------------------------------------------------------
  503. // Purpose: Opens the next weapon in the slot
  504. //-----------------------------------------------------------------------------
  505. void CHudWeaponSelection::FastWeaponSwitch( int iWeaponSlot )
  506. {
  507. // get the slot the player's weapon is in
  508. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  509. if ( !pPlayer )
  510. return;
  511. // see where we should start selection
  512. int iPosition = -1;
  513. C_BaseCombatWeapon *pActiveWeapon = pPlayer->GetActiveWeapon();
  514. if ( pActiveWeapon && pActiveWeapon->GetSlot() == iWeaponSlot )
  515. {
  516. // start after this weapon
  517. iPosition = pActiveWeapon->GetPosition();
  518. }
  519. C_BaseCombatWeapon *pNextWeapon = NULL;
  520. // search for the weapon after the current one
  521. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, iPosition);
  522. // make sure it's in the same bucket
  523. if ( !pNextWeapon || pNextWeapon->GetSlot() != iWeaponSlot )
  524. {
  525. // just look for any weapon in this slot
  526. pNextWeapon = FindNextWeaponInWeaponSelection(iWeaponSlot, -1);
  527. }
  528. // see if we found a weapon that's different from the current and in the selected slot
  529. if ( pNextWeapon && pNextWeapon != pActiveWeapon && pNextWeapon->GetSlot() == iWeaponSlot )
  530. {
  531. // select the new weapon
  532. ::input->MakeWeaponSelection( pNextWeapon );
  533. }
  534. else if ( pNextWeapon != pActiveWeapon )
  535. {
  536. // error sound
  537. pPlayer->EmitSound( "Player.DenyWeaponSelection" );
  538. }
  539. }
  540. C_BaseCombatWeapon *CHudWeaponSelection::GetNextActivePos( int iSlot, int iSlotPos )
  541. {
  542. if ( iSlot >= HL1_MAX_WEAPON_SLOTS )
  543. return NULL;
  544. return CBaseHudWeaponSelection::GetNextActivePos( iSlot, iSlotPos );
  545. }