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.

461 lines
14 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "hud.h"
  8. #include "text_message.h"
  9. #include "hud_macros.h"
  10. #include "iclientmode.h"
  11. #include "view.h"
  12. #include <KeyValues.h>
  13. #include <vgui_controls/AnimationController.h>
  14. #include <vgui/ISurface.h>
  15. #include "VGuiMatSurface/IMatSystemSurface.h"
  16. #include "materialsystem/imaterial.h"
  17. #include "materialsystem/imesh.h"
  18. #include "materialsystem/imaterialvar.h"
  19. #include "IEffects.h"
  20. #include "hudelement.h"
  21. #include "clienteffectprecachesystem.h"
  22. #include "sourcevr/isourcevirtualreality.h"
  23. using namespace vgui;
  24. // memdbgon must be the last include file in a .cpp file!!!
  25. #include "tier0/memdbgon.h"
  26. //-----------------------------------------------------------------------------
  27. // Purpose: HDU Damage indication
  28. //-----------------------------------------------------------------------------
  29. class CHudDamageIndicator : public CHudElement, public vgui::Panel
  30. {
  31. DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel );
  32. public:
  33. CHudDamageIndicator( const char *pElementName );
  34. void Init( void );
  35. void Reset( void );
  36. virtual bool ShouldDraw( void );
  37. // Handler for our message
  38. void MsgFunc_Damage( bf_read &msg );
  39. private:
  40. virtual void Paint();
  41. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  42. private:
  43. CPanelAnimationVarAliasType( float, m_flDmgX, "dmg_xpos", "10", "proportional_float" );
  44. CPanelAnimationVarAliasType( float, m_flDmgY, "dmg_ypos", "80", "proportional_float" );
  45. CPanelAnimationVarAliasType( float, m_flDmgWide, "dmg_wide", "30", "proportional_float" );
  46. CPanelAnimationVarAliasType( float, m_flDmgTall1, "dmg_tall1", "300", "proportional_float" );
  47. CPanelAnimationVarAliasType( float, m_flDmgTall2, "dmg_tall2", "240", "proportional_float" );
  48. CPanelAnimationVar( Color, m_DmgColorLeft, "DmgColorLeft", "255 0 0 0" );
  49. CPanelAnimationVar( Color, m_DmgColorRight, "DmgColorRight", "255 0 0 0" );
  50. CPanelAnimationVar( Color, m_DmgHighColorLeft, "DmgHighColorLeft", "255 0 0 0" );
  51. CPanelAnimationVar( Color, m_DmgHighColorRight, "DmgHighColorRight", "255 0 0 0" );
  52. CPanelAnimationVar( Color, m_DmgFullscreenColor, "DmgFullscreenColor", "255 0 0 0" );
  53. void DrawDamageIndicator(int side);
  54. void DrawFullscreenDamageIndicator();
  55. void GetDamagePosition( const Vector &vecDelta, float *flRotation );
  56. CMaterialReference m_WhiteAdditiveMaterial;
  57. };
  58. DECLARE_HUDELEMENT( CHudDamageIndicator );
  59. DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage );
  60. enum
  61. {
  62. DAMAGE_ANY,
  63. DAMAGE_LOW,
  64. DAMAGE_HIGH,
  65. };
  66. #define ANGLE_ANY 0.0f
  67. #define DMG_ANY 0
  68. struct DamageAnimation_t
  69. {
  70. const char *name;
  71. int bitsDamage;
  72. float angleMinimum;
  73. float angleMaximum;
  74. int damage;
  75. };
  76. //-----------------------------------------------------------------------------
  77. // Purpose: List of damage animations, finds first that matches criteria
  78. //-----------------------------------------------------------------------------
  79. static DamageAnimation_t g_DamageAnimations[] =
  80. {
  81. { "HudTakeDamageDrown", DMG_DROWN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  82. { "HudTakeDamagePoison", DMG_POISON, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  83. { "HudTakeDamageBurn", DMG_BURN, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  84. { "HudTakeDamageRadiation", DMG_RADIATION, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  85. { "HudTakeDamageRadiation", DMG_ACID, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  86. { "HudTakeDamageHighLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_HIGH },
  87. { "HudTakeDamageHighRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_HIGH },
  88. { "HudTakeDamageHigh", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_HIGH },
  89. { "HudTakeDamageLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_ANY },
  90. { "HudTakeDamageRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_ANY },
  91. { "HudTakeDamageBehind", DMG_ANY, 135.0f, 225.0f, DAMAGE_ANY },
  92. // fall through to front damage
  93. { "HudTakeDamageFront", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  94. { NULL },
  95. };
  96. //-----------------------------------------------------------------------------
  97. // Purpose: Constructor
  98. //-----------------------------------------------------------------------------
  99. CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator")
  100. {
  101. vgui::Panel *pParent = g_pClientMode->GetViewport();
  102. SetParent( pParent );
  103. m_WhiteAdditiveMaterial.Init( "vgui/white_additive", TEXTURE_GROUP_VGUI );
  104. SetHiddenBits( HIDEHUD_HEALTH );
  105. }
  106. //-----------------------------------------------------------------------------
  107. // Purpose:
  108. //-----------------------------------------------------------------------------
  109. void CHudDamageIndicator::Reset( void )
  110. {
  111. m_DmgColorLeft[3] = 0;
  112. m_DmgColorRight[3] = 0;
  113. m_DmgHighColorLeft[3] = 0;
  114. m_DmgHighColorRight[3] = 0;
  115. m_DmgFullscreenColor[3] = 0;
  116. }
  117. void CHudDamageIndicator::Init( void )
  118. {
  119. HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage );
  120. }
  121. //-----------------------------------------------------------------------------
  122. // Purpose: Save CPU cycles by letting the HUD system early cull
  123. // costly traversal. Called per frame, return true if thinking and
  124. // painting need to occur.
  125. //-----------------------------------------------------------------------------
  126. bool CHudDamageIndicator::ShouldDraw( void )
  127. {
  128. bool bNeedsDraw = m_DmgColorLeft[3] ||
  129. m_DmgColorRight[3] ||
  130. m_DmgHighColorLeft[3] ||
  131. m_DmgHighColorRight[3] ||
  132. m_DmgFullscreenColor[3];
  133. return ( bNeedsDraw && CHudElement::ShouldDraw() );
  134. }
  135. //-----------------------------------------------------------------------------
  136. // Purpose: Draws a damage quad
  137. //-----------------------------------------------------------------------------
  138. void CHudDamageIndicator::DrawDamageIndicator(int side)
  139. {
  140. CMatRenderContextPtr pRenderContext( materials );
  141. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
  142. CMeshBuilder meshBuilder;
  143. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  144. int insetY = (m_flDmgTall1 - m_flDmgTall2) / 2;
  145. int x1 = m_flDmgX;
  146. int x2 = m_flDmgX + m_flDmgWide;
  147. int y[4] = { (int)m_flDmgY, (int)(m_flDmgY + insetY), (int)(m_flDmgY + m_flDmgTall1 - insetY), (int)(m_flDmgY + m_flDmgTall1) };
  148. int alpha[4] = { 0, 1, 1, 0 };
  149. // see if we're high damage
  150. bool bHighDamage = false;
  151. if ( m_DmgHighColorRight[3] > m_DmgColorRight[3] || m_DmgHighColorLeft[3] > m_DmgColorLeft[3] )
  152. {
  153. // make more of the screen be covered by damage
  154. x1 = GetWide() * 0.0f;
  155. x2 = GetWide() * 0.5f;
  156. y[0] = 0.0f;
  157. y[1] = 0.0f;
  158. y[2] = GetTall();
  159. y[3] = GetTall();
  160. alpha[0] = 1.0f;
  161. alpha[1] = 0.0f;
  162. alpha[2] = 0.0f;
  163. alpha[3] = 1.0f;
  164. bHighDamage = true;
  165. }
  166. int r, g, b, a;
  167. if (side == 1)
  168. {
  169. if ( bHighDamage )
  170. {
  171. r = m_DmgHighColorRight[0], g = m_DmgHighColorRight[1], b = m_DmgHighColorRight[2], a = m_DmgHighColorRight[3];
  172. }
  173. else
  174. {
  175. r = m_DmgColorRight[0], g = m_DmgColorRight[1], b = m_DmgColorRight[2], a = m_DmgColorRight[3];
  176. }
  177. // realign x coords
  178. x1 = GetWide() - x1;
  179. x2 = GetWide() - x2;
  180. meshBuilder.Color4ub( r, g, b, a * alpha[0]);
  181. meshBuilder.TexCoord2f( 0,0,0 );
  182. meshBuilder.Position3f( x1, y[0], 0 );
  183. meshBuilder.AdvanceVertex();
  184. meshBuilder.Color4ub( r, g, b, a * alpha[3] );
  185. meshBuilder.TexCoord2f( 0,0,1 );
  186. meshBuilder.Position3f( x1, y[3], 0 );
  187. meshBuilder.AdvanceVertex();
  188. meshBuilder.Color4ub( r, g, b, a * alpha[2] );
  189. meshBuilder.TexCoord2f( 0,1,1 );
  190. meshBuilder.Position3f( x2, y[2], 0 );
  191. meshBuilder.AdvanceVertex();
  192. meshBuilder.Color4ub( r, g, b, a * alpha[1] );
  193. meshBuilder.TexCoord2f( 0,1,0 );
  194. meshBuilder.Position3f( x2, y[1], 0 );
  195. meshBuilder.AdvanceVertex();
  196. }
  197. else
  198. {
  199. if ( bHighDamage )
  200. {
  201. r = m_DmgHighColorLeft[0], g = m_DmgHighColorLeft[1], b = m_DmgHighColorLeft[2], a = m_DmgHighColorLeft[3];
  202. }
  203. else
  204. {
  205. r = m_DmgColorLeft[0], g = m_DmgColorLeft[1], b = m_DmgColorLeft[2], a = m_DmgColorLeft[3];
  206. }
  207. meshBuilder.Color4ub( r, g, b, a * alpha[0] );
  208. meshBuilder.TexCoord2f( 0,0,0 );
  209. meshBuilder.Position3f( x1, y[0], 0 );
  210. meshBuilder.AdvanceVertex();
  211. meshBuilder.Color4ub( r, g, b, a * alpha[1] );
  212. meshBuilder.TexCoord2f( 0,1,0 );
  213. meshBuilder.Position3f( x2, y[1], 0 );
  214. meshBuilder.AdvanceVertex();
  215. meshBuilder.Color4ub( r, g, b, a * alpha[2] );
  216. meshBuilder.TexCoord2f( 0,1,1 );
  217. meshBuilder.Position3f( x2, y[2], 0 );
  218. meshBuilder.AdvanceVertex();
  219. meshBuilder.Color4ub( r, g, b, a * alpha[3] );
  220. meshBuilder.TexCoord2f( 0,0,1 );
  221. meshBuilder.Position3f( x1, y[3], 0 );
  222. meshBuilder.AdvanceVertex();
  223. }
  224. meshBuilder.End();
  225. pMesh->Draw();
  226. }
  227. //-----------------------------------------------------------------------------
  228. // Purpose: Draws full screen damage fade
  229. //-----------------------------------------------------------------------------
  230. void CHudDamageIndicator::DrawFullscreenDamageIndicator()
  231. {
  232. CMatRenderContextPtr pRenderContext( materials );
  233. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
  234. CMeshBuilder meshBuilder;
  235. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  236. int r = m_DmgFullscreenColor[0], g = m_DmgFullscreenColor[1], b = m_DmgFullscreenColor[2], a = m_DmgFullscreenColor[3];
  237. float wide = GetWide(), tall = GetTall();
  238. meshBuilder.Color4ub( r, g, b, a );
  239. meshBuilder.TexCoord2f( 0,0,0 );
  240. meshBuilder.Position3f( 0.0f, 0.0f, 0 );
  241. meshBuilder.AdvanceVertex();
  242. meshBuilder.Color4ub( r, g, b, a );
  243. meshBuilder.TexCoord2f( 0,1,0 );
  244. meshBuilder.Position3f( wide, 0.0f, 0 );
  245. meshBuilder.AdvanceVertex();
  246. meshBuilder.Color4ub( r, g, b, a );
  247. meshBuilder.TexCoord2f( 0,1,1 );
  248. meshBuilder.Position3f( wide, tall, 0 );
  249. meshBuilder.AdvanceVertex();
  250. meshBuilder.Color4ub( r, g, b, a );
  251. meshBuilder.TexCoord2f( 0,0,1 );
  252. meshBuilder.Position3f( 0.0f, tall, 0 );
  253. meshBuilder.AdvanceVertex();
  254. meshBuilder.End();
  255. pMesh->Draw();
  256. }
  257. //-----------------------------------------------------------------------------
  258. // Purpose: Paints the damage display
  259. //-----------------------------------------------------------------------------
  260. void CHudDamageIndicator::Paint()
  261. {
  262. // draw fullscreen damage indicators
  263. DrawFullscreenDamageIndicator();
  264. // draw side damage indicators
  265. DrawDamageIndicator(0);
  266. DrawDamageIndicator(1);
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: Message handler for Damage message
  270. //-----------------------------------------------------------------------------
  271. void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg )
  272. {
  273. int armor = msg.ReadByte(); // armor
  274. int damageTaken = msg.ReadByte(); // health
  275. long bitsDamage = msg.ReadLong(); // damage bits
  276. Vector vecFrom;
  277. vecFrom.x = msg.ReadFloat();
  278. vecFrom.y = msg.ReadFloat();
  279. vecFrom.z = msg.ReadFloat();
  280. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  281. if ( !pPlayer )
  282. return;
  283. // player has just died, just run the dead damage animation
  284. if ( pPlayer->GetHealth() <= 0 )
  285. {
  286. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( "HudPlayerDeath" );
  287. return;
  288. }
  289. // ignore damage without direction
  290. // this should never happen, unless it's drowning damage,
  291. // or the player is forcibly killed, handled above
  292. if ( vecFrom == vec3_origin && !(bitsDamage & DMG_DROWN))
  293. return;
  294. Vector vecDelta = (vecFrom - MainViewOrigin());
  295. VectorNormalize( vecDelta );
  296. int highDamage = DAMAGE_LOW;
  297. if ( damageTaken > 25 )
  298. {
  299. highDamage = DAMAGE_HIGH;
  300. }
  301. // if we have no suit, all damage is high
  302. if ( !pPlayer->IsSuitEquipped() )
  303. {
  304. highDamage = DAMAGE_HIGH;
  305. }
  306. if ( damageTaken > 0 || armor > 0 )
  307. {
  308. // see which quandrant the effect is in
  309. float angle;
  310. GetDamagePosition( vecDelta, &angle );
  311. // see which effect to play
  312. DamageAnimation_t *dmgAnim = g_DamageAnimations;
  313. for ( ; dmgAnim->name != NULL; ++dmgAnim )
  314. {
  315. if ( dmgAnim->bitsDamage && !(bitsDamage & dmgAnim->bitsDamage) )
  316. continue;
  317. if ( dmgAnim->angleMinimum && angle < dmgAnim->angleMinimum )
  318. continue;
  319. if ( dmgAnim->angleMaximum && angle > dmgAnim->angleMaximum )
  320. continue;
  321. if ( dmgAnim->damage && dmgAnim->damage != highDamage )
  322. continue;
  323. // we have a match, break
  324. break;
  325. }
  326. if ( dmgAnim->name )
  327. {
  328. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( dmgAnim->name );
  329. }
  330. }
  331. }
  332. //-----------------------------------------------------------------------------
  333. // Purpose: Convert a damage position in world units to the screen's units
  334. //-----------------------------------------------------------------------------
  335. void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float *flRotation )
  336. {
  337. float flRadius = 360.0f;
  338. // Player Data
  339. Vector playerPosition = MainViewOrigin();
  340. QAngle playerAngles = MainViewAngles();
  341. Vector forward, right, up(0,0,1);
  342. AngleVectors (playerAngles, &forward, NULL, NULL );
  343. forward.z = 0;
  344. VectorNormalize(forward);
  345. CrossProduct( up, forward, right );
  346. float front = DotProduct(vecDelta, forward);
  347. float side = DotProduct(vecDelta, right);
  348. float xpos = flRadius * -side;
  349. float ypos = flRadius * -front;
  350. // Get the rotation (yaw)
  351. *flRotation = atan2(xpos, ypos) + M_PI;
  352. *flRotation *= 180 / M_PI;
  353. float yawRadians = -(*flRotation) * M_PI / 180.0f;
  354. float ca = cos( yawRadians );
  355. float sa = sin( yawRadians );
  356. // Rotate it around the circle
  357. xpos = (int)((GetWide() / 2) + (flRadius * sa));
  358. ypos = (int)((GetTall() / 2) - (flRadius * ca));
  359. }
  360. //-----------------------------------------------------------------------------
  361. // Purpose: hud scheme settings
  362. //-----------------------------------------------------------------------------
  363. void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme)
  364. {
  365. BaseClass::ApplySchemeSettings(pScheme);
  366. SetPaintBackgroundEnabled(false);
  367. int vx, vy, vw, vh;
  368. vgui::surface()->GetFullscreenViewport( vx, vy, vw, vh );
  369. SetForceStereoRenderToFrameBuffer( true );
  370. if( UseVR() )
  371. {
  372. m_flDmgY = 0.125f * (float)vh;
  373. m_flDmgTall1 = 0.625f * (float)vh;
  374. m_flDmgTall2 = 0.4f * (float)vh;
  375. m_flDmgWide = 0.1f * (float)vw;
  376. }
  377. SetSize(vw, vh);
  378. }