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.

508 lines
13 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hud.h"
  8. #include "hudelement.h"
  9. #include "hud_macros.h"
  10. #include "hud_bitmapnumericdisplay.h"
  11. #include "iclientmode.h"
  12. #include "c_dod_player.h"
  13. #include "ihudlcd.h"
  14. #include <vgui/ISurface.h>
  15. #include <vgui_controls/AnimationController.h>
  16. //-----------------------------------------------------------------------------
  17. // Purpose: Displays current ammunition level
  18. //-----------------------------------------------------------------------------
  19. class CHudAmmo : public CHudElement, public vgui::Panel
  20. {
  21. DECLARE_CLASS_SIMPLE( CHudAmmo, vgui::Panel );
  22. public:
  23. CHudAmmo( const char *pElementName );
  24. void Init( void );
  25. void VidInit( void );
  26. void SetAmmo(int ammo, bool playAnimation);
  27. void SetAmmo2(int ammo2, bool playAnimation);
  28. protected:
  29. virtual void OnThink();
  30. virtual void Paint( void );
  31. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  32. private:
  33. void DrawText( char *text, int x, int y, Color clrText );
  34. void DrawNumbers( int num, int x, int y );
  35. void PaintGrenadeAmmo( CWeaponDODBase *pWpn );
  36. void PaintBazookaAmmo( CWeaponDODBase *pWpn );
  37. void PaintMGAmmo( CWeaponDODBase *pWpn );
  38. void PaintGunAmmo( CWeaponDODBase *pWpn );
  39. void PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn );
  40. CHandle< C_BaseCombatWeapon > m_hCurrentActiveWeapon;
  41. int m_iAmmo;
  42. int m_iAmmo2;
  43. bool m_bUsesClips;
  44. int m_iAdditiveWhiteID;
  45. CPanelAnimationVarAliasType( float, digit2_xpos, "digit2_xpos", "0", "proportional_float" );
  46. CPanelAnimationVarAliasType( float, digit2_ypos, "digit2_ypos", "0", "proportional_float" );
  47. CPanelAnimationVarAliasType( float, bar_xpos, "bar_xpos", "0", "proportional_float" );
  48. CPanelAnimationVarAliasType( float, bar_ypos, "bar_ypos", "0", "proportional_float" );
  49. CPanelAnimationVarAliasType( float, bar_width, "bar_width", "2", "proportional_float" );
  50. CPanelAnimationVarAliasType( float, bar_height, "bar_height", "2", "proportional_float" );
  51. CPanelAnimationVarAliasType( float, icon_xpos, "icon_xpos", "0", "proportional_float" );
  52. CPanelAnimationVarAliasType( float, icon_ypos, "icon_ypos", "0", "proportional_float" );
  53. CPanelAnimationVar( vgui::HFont, m_hNumberFont, "NumberFont", "HudSelectionNumbers" );
  54. Color m_clrIcon;
  55. CHudTexture *m_pMGNumbers[10];
  56. };
  57. //DECLARE_HUDELEMENT( CHudAmmo );
  58. //-----------------------------------------------------------------------------
  59. // Purpose: Constructor
  60. //-----------------------------------------------------------------------------
  61. CHudAmmo::CHudAmmo( const char *pElementName ) : vgui::Panel( NULL, "HudAmmo" ), CHudElement( pElementName )
  62. {
  63. SetParent( g_pClientMode->GetViewport() );
  64. m_iAdditiveWhiteID = vgui::surface()->CreateNewTextureID();
  65. vgui::surface()->DrawSetTextureFile( m_iAdditiveWhiteID, "vgui/white_additive" , true, false);
  66. SetActive( true );
  67. m_clrIcon = Color(255,255,255,255);
  68. SetHiddenBits( HIDEHUD_HEALTH | HIDEHUD_PLAYERDEAD | HIDEHUD_WEAPONSELECTION );
  69. hudlcd->SetGlobalStat( "(ammo_primary)", "0" );
  70. hudlcd->SetGlobalStat( "(ammo_secondary)", "0" );
  71. hudlcd->SetGlobalStat( "(weapon_print_name)", "" );
  72. hudlcd->SetGlobalStat( "(weapon_name)", "" );
  73. }
  74. //-----------------------------------------------------------------------------
  75. // Purpose:
  76. //-----------------------------------------------------------------------------
  77. void CHudAmmo::Init( void )
  78. {
  79. m_iAmmo = -1;
  80. m_iAmmo2 = -1;
  81. }
  82. void CHudAmmo::ApplySchemeSettings(vgui::IScheme *pScheme)
  83. {
  84. BaseClass::ApplySchemeSettings(pScheme);
  85. }
  86. //-----------------------------------------------------------------------------
  87. // Purpose:
  88. //-----------------------------------------------------------------------------
  89. void CHudAmmo::VidInit( void )
  90. {
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose: called every frame to get ammo info from the weapon
  94. //-----------------------------------------------------------------------------
  95. void CHudAmmo::OnThink()
  96. {
  97. C_BaseCombatWeapon *wpn = GetActiveWeapon();
  98. hudlcd->SetGlobalStat( "(weapon_print_name)", wpn ? wpn->GetPrintName() : " " );
  99. hudlcd->SetGlobalStat( "(weapon_name)", wpn ? wpn->GetName() : " " );
  100. C_BasePlayer *player = C_BasePlayer::GetLocalPlayer();
  101. if (!wpn || !player || !wpn->UsesPrimaryAmmo())
  102. {
  103. hudlcd->SetGlobalStat( "(ammo_primary)", "n/a" );
  104. hudlcd->SetGlobalStat( "(ammo_secondary)", "n/a" );
  105. SetPaintEnabled(false);
  106. SetPaintBackgroundEnabled(false);
  107. return;
  108. }
  109. else
  110. {
  111. SetPaintEnabled(true);
  112. SetPaintBackgroundEnabled(true);
  113. }
  114. // get the ammo in our clip
  115. int ammo1 = wpn->Clip1();
  116. int ammo2;
  117. if (ammo1 < 0)
  118. {
  119. // we don't use clip ammo, just use the total ammo count
  120. ammo1 = player->GetAmmoCount(wpn->GetPrimaryAmmoType());
  121. ammo2 = 0;
  122. }
  123. else
  124. {
  125. // we use clip ammo, so the second ammo is the total ammo
  126. ammo2 = player->GetAmmoCount(wpn->GetPrimaryAmmoType());
  127. }
  128. hudlcd->SetGlobalStat( "(ammo_primary)", VarArgs( "%d", ammo1 ) );
  129. hudlcd->SetGlobalStat( "(ammo_secondary)", VarArgs( "%d", ammo2 ) );
  130. if (wpn == m_hCurrentActiveWeapon)
  131. {
  132. // same weapon, just update counts
  133. SetAmmo(ammo1, true);
  134. SetAmmo2(ammo2, true);
  135. }
  136. else
  137. {
  138. // diferent weapon, change without triggering
  139. SetAmmo(ammo1, false);
  140. SetAmmo2(ammo2, false);
  141. // update whether or not we show the total ammo display
  142. if (wpn->UsesClipsForAmmo1())
  143. {
  144. m_bUsesClips = true;
  145. }
  146. else
  147. {
  148. m_bUsesClips = false;
  149. }
  150. m_hCurrentActiveWeapon = wpn;
  151. }
  152. }
  153. //-----------------------------------------------------------------------------
  154. // Purpose: Updates ammo display
  155. //-----------------------------------------------------------------------------
  156. void CHudAmmo::SetAmmo(int ammo, bool playAnimation)
  157. {
  158. if (ammo != m_iAmmo)
  159. {
  160. m_iAmmo = ammo;
  161. }
  162. }
  163. //-----------------------------------------------------------------------------
  164. // Purpose: Updates 2nd ammo display
  165. //-----------------------------------------------------------------------------
  166. void CHudAmmo::SetAmmo2(int ammo2, bool playAnimation)
  167. {
  168. if (ammo2 != m_iAmmo2)
  169. {
  170. m_iAmmo2 = ammo2;
  171. }
  172. }
  173. void CHudAmmo::PaintGrenadeAmmo( CWeaponDODBase *pWpn )
  174. {
  175. const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
  176. Assert( pAmmoIcon );
  177. int x,y,w,h;
  178. GetBounds( x, y, w, h );
  179. if (m_iAmmo > 0 && pAmmoIcon )
  180. {
  181. int xpos = w - 2 * pAmmoIcon->Width();
  182. int ypos = h - pAmmoIcon->Height();
  183. pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon );
  184. char buf[16];
  185. Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo );
  186. DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon );
  187. }
  188. }
  189. void CHudAmmo::PaintRifleGrenadeAmmo( CWeaponDODBase *pWpn )
  190. {
  191. const CHudTexture *pAmmoIcon = pWpn->GetSpriteAmmo();
  192. Assert( pAmmoIcon );
  193. int x,y,w,h;
  194. GetBounds( x, y, w, h );
  195. int ammo = m_iAmmo + m_iAmmo2;
  196. if (ammo > 0 && pAmmoIcon )
  197. {
  198. int xpos = w - 2 * pAmmoIcon->Width();
  199. int ypos = h - pAmmoIcon->Height();
  200. pAmmoIcon->DrawSelf( xpos, ypos, pAmmoIcon->Width(), pAmmoIcon->Height(), m_clrIcon );
  201. char buf[16];
  202. Q_snprintf( buf, sizeof(buf), "x %d", ammo );
  203. DrawText( buf, xpos + pAmmoIcon->Width(), ypos + pAmmoIcon->Height() / 2, m_clrIcon );
  204. }
  205. }
  206. void CHudAmmo::PaintBazookaAmmo( CWeaponDODBase *pWpn )
  207. {
  208. const CHudTexture *pTubeIcon = pWpn->GetSpriteAmmo2();
  209. const CHudTexture *pRocketIcon = pWpn->GetSpriteAmmo();
  210. const CHudTexture *pExtraIcon = pWpn->GetSpriteAutoaim();
  211. Assert( pTubeIcon );
  212. Assert( pRocketIcon );
  213. Assert( pExtraIcon );
  214. int xpos = 0;
  215. int ypos = 0;
  216. int x, y, w, h;
  217. GetBounds(x,y,w,h);
  218. //Draw the rocket tube
  219. if( pTubeIcon )
  220. {
  221. xpos = w - 2 * pTubeIcon->Width();
  222. ypos = h - pTubeIcon->Height();
  223. pTubeIcon->DrawSelf( xpos, ypos, m_clrIcon );
  224. }
  225. //If our clip is full, draw the rocket
  226. if( pRocketIcon )
  227. {
  228. if( m_iAmmo > 0 )
  229. pRocketIcon->DrawSelf( xpos, ypos, m_clrIcon );
  230. xpos += pRocketIcon->Width() + 10;
  231. ypos += pRocketIcon->Height();
  232. }
  233. char buf[16];
  234. Q_snprintf( buf, sizeof(buf), "%d %d", m_iAmmo, m_iAmmo2 );
  235. DrawText( buf, xpos, ypos, m_clrIcon );
  236. //Draw the extra rockets
  237. if( m_iAmmo2 > 0 && pExtraIcon )
  238. {
  239. ypos -= pExtraIcon->Height();
  240. pExtraIcon->DrawSelf( xpos, ypos, m_clrIcon );
  241. xpos += pExtraIcon->Width();
  242. char buf[16];
  243. Q_snprintf( buf, sizeof(buf), "x %d", m_iAmmo2 );
  244. DrawText( buf, xpos, ypos + ( pExtraIcon->Height() * 0.75 ), m_clrIcon );
  245. }
  246. }
  247. void CHudAmmo::PaintMGAmmo( CWeaponDODBase *pWpn )
  248. {
  249. const CHudTexture *pFullClip = pWpn->GetSpriteAmmo();
  250. const CHudTexture *pExtraClip = pWpn->GetSpriteAmmo2();
  251. int xpos = 0;
  252. int ypos = 0;
  253. int x, y, w, h;
  254. GetBounds(x,y,w,h);
  255. if( pFullClip )
  256. {
  257. xpos = w - pFullClip->Width() * 3;
  258. ypos = h - pFullClip->Height();
  259. pFullClip->DrawSelf( xpos, ypos, m_clrIcon );
  260. //Haxoration! The box that contains the numbers must be in the same position
  261. // in both the webley and mg34/mg42/30cal sprites.
  262. DrawNumbers( m_iAmmo, xpos + 36, ypos + pFullClip->Height() - 16 );
  263. xpos += pFullClip->Width();
  264. ypos += pFullClip->Height();
  265. }
  266. //how many full or partially full clips do we have?
  267. int clips = m_iAmmo2 / pWpn->GetMaxClip1();
  268. //account for the partial clip, if it exists
  269. if( clips * pWpn->GetMaxClip1() < m_iAmmo2 )
  270. clips++;
  271. if( pExtraClip && clips > 0 )
  272. {
  273. ypos -= pExtraClip->Height();
  274. pExtraClip->DrawSelf( xpos, ypos, m_clrIcon );
  275. char buf[16];
  276. Q_snprintf( buf, sizeof(buf), "x %d", clips );
  277. DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon );
  278. }
  279. }
  280. void CHudAmmo::PaintGunAmmo( CWeaponDODBase *pWpn )
  281. {
  282. //regular gun
  283. const CHudTexture *pEmptyClip = pWpn->GetSpriteAmmo();
  284. const CHudTexture *pFullClip = pWpn->GetSpriteAmmo2();
  285. const CHudTexture *pExtraClip = pWpn->GetSpriteAutoaim();
  286. Assert( pEmptyClip );
  287. Assert( pFullClip );
  288. Assert( pExtraClip );
  289. int x, y, w, h;
  290. GetBounds( x, y, w, h );
  291. int xpos = 0;
  292. int ypos = 0;
  293. if( pFullClip )
  294. {
  295. xpos = w - 3 * pFullClip->Width();
  296. ypos = h - pFullClip->Height() * 1.2;
  297. //Always draw the empty clip
  298. pFullClip->DrawSelf( xpos, ypos, Color(255,255,255,255) );
  299. }
  300. if( pEmptyClip )
  301. {
  302. // base percent is how much of the bullet clip to always draw.
  303. // total cropped height of the bullet sprite will be
  304. // base percent + bullet height * bullets
  305. float flBasePercent = (float)pWpn->GetDODWpnData().m_iHudClipBaseHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight;
  306. float flBulletHeightPercent = (float)pWpn->GetDODWpnData().m_iHudClipBulletHeight / (float)pWpn->GetDODWpnData().m_iHudClipHeight;
  307. float flHeight = (float)pEmptyClip->Height();
  308. //Now we draw the bullets inside based on how full our clip is
  309. float flDrawHeight = flHeight * ( 1.0 - ( flBasePercent + flBulletHeightPercent * m_iAmmo ) );
  310. int nOffset = (int)flDrawHeight;
  311. pEmptyClip->DrawSelfCropped( xpos, ypos + nOffset, 0, nOffset, pEmptyClip->Width(), pEmptyClip->Height() - nOffset, Color(255,255,255,255) );
  312. ypos += pEmptyClip->Height();
  313. xpos += pEmptyClip->Width() + 10;
  314. }
  315. //how many full or partially full clips do we have?
  316. int clips = m_iAmmo2 / pWpn->GetMaxClip1();
  317. //account for the partial clip, if it exists
  318. if( clips * pWpn->GetMaxClip1() < m_iAmmo2 )
  319. clips++;
  320. if( pExtraClip && clips > 0 )
  321. {
  322. //align the extra clip on the same baseline as the large clip
  323. ypos -= pExtraClip->Height();
  324. pExtraClip->DrawSelf( xpos, ypos, Color(255,255,255,255) );
  325. char buf[16];
  326. Q_snprintf( buf, sizeof(buf), "x %d", clips );
  327. DrawText( buf, xpos + pExtraClip->Width(), ypos + pExtraClip->Height() / 2, m_clrIcon );
  328. }
  329. }
  330. void CHudAmmo::Paint( void )
  331. {
  332. C_DODPlayer *pPlayer = C_DODPlayer::GetLocalDODPlayer();
  333. if( !pPlayer )
  334. return;
  335. CWeaponDODBase *pWpn = pPlayer->GetActiveDODWeapon();
  336. if( !pWpn )
  337. return;
  338. switch( pWpn->GetDODWpnData().m_WeaponType )
  339. {
  340. case WPN_TYPE_GRENADE:
  341. PaintGrenadeAmmo(pWpn);
  342. break;
  343. case WPN_TYPE_RIFLEGRENADE:
  344. PaintRifleGrenadeAmmo(pWpn);
  345. break;
  346. case WPN_TYPE_BAZOOKA:
  347. PaintBazookaAmmo(pWpn);
  348. break;
  349. case WPN_TYPE_MG:
  350. PaintMGAmmo(pWpn);
  351. break;
  352. default:
  353. PaintGunAmmo(pWpn);
  354. break;
  355. }
  356. }
  357. void CHudAmmo::DrawText( char *text, int x, int y, Color clrText )
  358. {
  359. vgui::surface()->DrawSetTextColor( clrText );
  360. vgui::surface()->DrawSetTextFont( m_hNumberFont );
  361. vgui::surface()->DrawSetTextPos( x, y );
  362. for (char *pch = text; *pch != 0; pch++)
  363. {
  364. vgui::surface()->DrawUnicodeChar(*pch);
  365. }
  366. }
  367. void CHudAmmo::DrawNumbers( int num, int x, int y )
  368. {
  369. if( !m_pMGNumbers[0] )
  370. {
  371. int i;
  372. for( i=0;i<10;i++ )
  373. {
  374. char buf[8];
  375. Q_snprintf( buf, sizeof(buf), "mg_%d", i );
  376. m_pMGNumbers[i] = gHUD.GetIcon( buf );
  377. }
  378. }
  379. Assert( num < 1000 );
  380. int xpos = x;
  381. int ypos = y;
  382. int num_working = num;
  383. int iconWidth = m_pMGNumbers[0]->Width();
  384. int hundreds = num_working / 100;
  385. num_working -= hundreds * 100;
  386. m_pMGNumbers[hundreds]->DrawSelf( xpos, ypos, m_clrIcon );
  387. xpos += iconWidth;
  388. int tens = num_working / 10;
  389. num_working -= tens * 10;
  390. m_pMGNumbers[tens]->DrawSelf( xpos, ypos, m_clrIcon );
  391. xpos += iconWidth;
  392. m_pMGNumbers[num_working]->DrawSelf( xpos, ypos, m_clrIcon );
  393. xpos += iconWidth;
  394. }