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.

330 lines
11 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Hud element that indicates the direction of damage taken by the player
  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. using namespace vgui;
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. //-----------------------------------------------------------------------------
  26. // Purpose:
  27. //-----------------------------------------------------------------------------
  28. class CHudDamageIndicator : public CHudElement, public vgui::Panel
  29. {
  30. DECLARE_CLASS_SIMPLE( CHudDamageIndicator, vgui::Panel );
  31. public:
  32. CHudDamageIndicator( const char *pElementName );
  33. void Init( void );
  34. void VidInit( 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 OnThink();
  41. virtual void Paint();
  42. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  43. // Painting
  44. void GetDamagePosition( const Vector &vecDelta, float flRadius, float *xpos, float *ypos, float *flRotation );
  45. void DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation );
  46. private:
  47. // Indication times
  48. CPanelAnimationVarAliasType( float, m_flMinimumWidth, "MinimumWidth", "10", "proportional_float" );
  49. CPanelAnimationVarAliasType( float, m_flMaximumWidth, "MaximumWidth", "100", "proportional_float" );
  50. CPanelAnimationVarAliasType( float, m_flMinimumHeight, "MinimumHeight", "20", "proportional_float" );
  51. CPanelAnimationVarAliasType( float, m_flMaximumHeight, "MaximumHeight", "100", "proportional_float" );
  52. CPanelAnimationVarAliasType( float, m_flStartRadius, "StartRadius", "140", "proportional_float" );
  53. CPanelAnimationVarAliasType( float, m_flEndRadius, "EndRadius", "120", "proportional_float" );
  54. CPanelAnimationVar( float, m_iMaximumDamage, "MaximumDamage", "100" );
  55. CPanelAnimationVar( float, m_flMinimumTime, "MinimumTime", "1" );
  56. CPanelAnimationVar( float, m_flMaximumTime, "MaximumTime", "2" );
  57. CPanelAnimationVar( float, m_flTravelTime, "TravelTime", ".1" );
  58. CPanelAnimationVar( float, m_flFadeOutPercentage, "FadeOutPercentage", "0.7" );
  59. CPanelAnimationVar( float, m_flNoise, "Noise", "0.1" );
  60. // List of damages we've taken
  61. struct damage_t
  62. {
  63. int iScale;
  64. float flLifeTime;
  65. float flStartTime;
  66. Vector vecDelta; // Damage origin relative to the player
  67. };
  68. CUtlVector<damage_t> m_vecDamages;
  69. CMaterialReference m_WhiteAdditiveMaterial;
  70. };
  71. DECLARE_HUDELEMENT( CHudDamageIndicator );
  72. DECLARE_HUD_MESSAGE( CHudDamageIndicator, Damage );
  73. //-----------------------------------------------------------------------------
  74. // Purpose:
  75. //-----------------------------------------------------------------------------
  76. CHudDamageIndicator::CHudDamageIndicator( const char *pElementName ) :
  77. CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator")
  78. {
  79. vgui::Panel *pParent = g_pClientMode->GetViewport();
  80. SetParent( pParent );
  81. SetHiddenBits( HIDEHUD_HEALTH );
  82. m_WhiteAdditiveMaterial.Init( "VGUI/damageindicator", TEXTURE_GROUP_VGUI );
  83. }
  84. //-----------------------------------------------------------------------------
  85. // Purpose:
  86. //-----------------------------------------------------------------------------
  87. void CHudDamageIndicator::Init( void )
  88. {
  89. HOOK_HUD_MESSAGE( CHudDamageIndicator, Damage );
  90. Reset();
  91. }
  92. //-----------------------------------------------------------------------------
  93. // Purpose:
  94. //-----------------------------------------------------------------------------
  95. void CHudDamageIndicator::Reset( void )
  96. {
  97. m_vecDamages.Purge();
  98. }
  99. //-----------------------------------------------------------------------------
  100. // Purpose:
  101. //-----------------------------------------------------------------------------
  102. void CHudDamageIndicator::VidInit( void )
  103. {
  104. }
  105. //-----------------------------------------------------------------------------
  106. // Purpose:
  107. //-----------------------------------------------------------------------------
  108. void CHudDamageIndicator::OnThink()
  109. {
  110. }
  111. //-----------------------------------------------------------------------------
  112. // Purpose:
  113. //-----------------------------------------------------------------------------
  114. bool CHudDamageIndicator::ShouldDraw( void )
  115. {
  116. if ( !CHudElement::ShouldDraw() )
  117. return false;
  118. // Don't draw if we don't have any damage to indicate
  119. if ( !m_vecDamages.Count() )
  120. return false;
  121. return true;
  122. }
  123. //-----------------------------------------------------------------------------
  124. // Purpose: Convert a damage position in world units to the screen's units
  125. //-----------------------------------------------------------------------------
  126. void CHudDamageIndicator::GetDamagePosition( const Vector &vecDelta, float flRadius, float *xpos, float *ypos, float *flRotation )
  127. {
  128. // Player Data
  129. Vector playerPosition = MainViewOrigin();
  130. QAngle playerAngles = MainViewAngles();
  131. Vector forward, right, up(0,0,1);
  132. AngleVectors (playerAngles, &forward, NULL, NULL );
  133. forward.z = 0;
  134. VectorNormalize(forward);
  135. CrossProduct( up, forward, right );
  136. float front = DotProduct(vecDelta, forward);
  137. float side = DotProduct(vecDelta, right);
  138. *xpos = flRadius * -side;
  139. *ypos = flRadius * -front;
  140. // Get the rotation (yaw)
  141. *flRotation = atan2(*xpos,*ypos) + M_PI;
  142. *flRotation *= 180 / M_PI;
  143. float yawRadians = -(*flRotation) * M_PI / 180.0f;
  144. float ca = cos( yawRadians );
  145. float sa = sin( yawRadians );
  146. // Rotate it around the circle
  147. *xpos = (int)((ScreenWidth() / 2) + (flRadius * sa));
  148. *ypos = (int)((ScreenHeight() / 2) - (flRadius * ca));
  149. }
  150. //-----------------------------------------------------------------------------
  151. // Purpose: Draw a single damage indicator
  152. //-----------------------------------------------------------------------------
  153. void CHudDamageIndicator::DrawDamageIndicator(int x0, int y0, int x1, int y1, float alpha, float flRotation )
  154. {
  155. CMatRenderContextPtr pRenderContext( materials );
  156. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
  157. // Get the corners, since they're being rotated
  158. int wide = x1 - x0;
  159. int tall = y1 - y0;
  160. Vector2D vecCorners[4];
  161. Vector2D center( x0 + (wide * 0.5f), y0 + (tall * 0.5f) );
  162. float yawRadians = -flRotation * M_PI / 180.0f;
  163. Vector2D axis[2];
  164. axis[0].x = cos(yawRadians);
  165. axis[0].y = sin(yawRadians);
  166. axis[1].x = -axis[0].y;
  167. axis[1].y = axis[0].x;
  168. Vector2DMA( center, -0.5f * wide, axis[0], vecCorners[0] );
  169. Vector2DMA( vecCorners[0], -0.5f * tall, axis[1], vecCorners[0] );
  170. Vector2DMA( vecCorners[0], wide, axis[0], vecCorners[1] );
  171. Vector2DMA( vecCorners[1], tall, axis[1], vecCorners[2] );
  172. Vector2DMA( vecCorners[0], tall, axis[1], vecCorners[3] );
  173. // Draw the sucker
  174. CMeshBuilder meshBuilder;
  175. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  176. int iAlpha = alpha * 255;
  177. meshBuilder.Color4ub( 255,255,255, iAlpha );
  178. meshBuilder.TexCoord2f( 0,0,0 );
  179. meshBuilder.Position3f( vecCorners[0].x,vecCorners[0].y,0 );
  180. meshBuilder.AdvanceVertex();
  181. meshBuilder.Color4ub( 255,255,255, iAlpha );
  182. meshBuilder.TexCoord2f( 0,1,0 );
  183. meshBuilder.Position3f( vecCorners[1].x,vecCorners[1].y,0 );
  184. meshBuilder.AdvanceVertex();
  185. meshBuilder.Color4ub( 255,255,255, iAlpha );
  186. meshBuilder.TexCoord2f( 0,1,1 );
  187. meshBuilder.Position3f( vecCorners[2].x,vecCorners[2].y,0 );
  188. meshBuilder.AdvanceVertex();
  189. meshBuilder.Color4ub( 255,255,255, iAlpha );
  190. meshBuilder.TexCoord2f( 0,0,1 );
  191. meshBuilder.Position3f( vecCorners[3].x,vecCorners[3].y,0 );
  192. meshBuilder.AdvanceVertex();
  193. meshBuilder.End();
  194. pMesh->Draw();
  195. }
  196. //-----------------------------------------------------------------------------
  197. // Purpose:
  198. //-----------------------------------------------------------------------------
  199. void CHudDamageIndicator::Paint()
  200. {
  201. // Iterate backwards, because we might remove them as we go
  202. int iSize = m_vecDamages.Count();
  203. for (int i = iSize-1; i >= 0; i--)
  204. {
  205. // Scale size to the damage
  206. float clampedDamage = clamp( (float) m_vecDamages[i].iScale, 0.f, m_iMaximumDamage );
  207. int iWidth = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumWidth, m_flMaximumWidth) * 0.5;
  208. int iHeight = RemapVal(clampedDamage, 0, m_iMaximumDamage, m_flMinimumHeight, m_flMaximumHeight) * 0.5;
  209. // Find the place to draw it
  210. float xpos, ypos;
  211. float flRotation;
  212. float flTimeSinceStart = ( gpGlobals->curtime - m_vecDamages[i].flStartTime );
  213. float flRadius = RemapVal( MIN( flTimeSinceStart, m_flTravelTime ), 0, m_flTravelTime, m_flStartRadius, m_flEndRadius );
  214. GetDamagePosition( m_vecDamages[i].vecDelta, flRadius, &xpos, &ypos, &flRotation );
  215. // Calculate life left
  216. float flLifeLeft = ( m_vecDamages[i].flLifeTime - gpGlobals->curtime );
  217. if ( flLifeLeft > 0 )
  218. {
  219. float flPercent = flTimeSinceStart / (m_vecDamages[i].flLifeTime - m_vecDamages[i].flStartTime);
  220. float alpha;
  221. if ( flPercent <= m_flFadeOutPercentage )
  222. {
  223. alpha = 1.0;
  224. }
  225. else
  226. {
  227. alpha = 1.0 - RemapVal( flPercent, m_flFadeOutPercentage, 1.0, 0.0, 1.0 );
  228. }
  229. DrawDamageIndicator( xpos-iWidth, ypos-iHeight, xpos+iWidth, ypos+iHeight, alpha, flRotation );
  230. }
  231. else
  232. {
  233. m_vecDamages.Remove(i);
  234. }
  235. }
  236. }
  237. //-----------------------------------------------------------------------------
  238. // Purpose: Message handler for Damage message
  239. //-----------------------------------------------------------------------------
  240. void CHudDamageIndicator::MsgFunc_Damage( bf_read &msg )
  241. {
  242. damage_t damage;
  243. damage.iScale = msg.ReadShort();
  244. msg.ReadLong(); // Read & ignored
  245. if ( !msg.ReadOneBit() )
  246. return;
  247. if ( damage.iScale > m_iMaximumDamage )
  248. {
  249. damage.iScale = m_iMaximumDamage;
  250. }
  251. Vector vecOrigin;
  252. msg.ReadBitVec3Coord( vecOrigin );
  253. damage.flStartTime = gpGlobals->curtime;
  254. damage.flLifeTime = gpGlobals->curtime + RemapVal(damage.iScale, 0, m_iMaximumDamage, m_flMinimumTime, m_flMaximumTime);
  255. if ( vecOrigin == vec3_origin )
  256. {
  257. vecOrigin = MainViewOrigin();
  258. }
  259. damage.vecDelta = (vecOrigin - MainViewOrigin());
  260. VectorNormalize( damage.vecDelta );
  261. // Add some noise
  262. damage.vecDelta[0] += random->RandomFloat( -m_flNoise, m_flNoise );
  263. damage.vecDelta[1] += random->RandomFloat( -m_flNoise, m_flNoise );
  264. damage.vecDelta[2] += random->RandomFloat( -m_flNoise, m_flNoise );
  265. VectorNormalize( damage.vecDelta );
  266. m_vecDamages.AddToTail( damage );
  267. }
  268. //-----------------------------------------------------------------------------
  269. // Purpose: hud scheme settings
  270. //-----------------------------------------------------------------------------
  271. void CHudDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme)
  272. {
  273. BaseClass::ApplySchemeSettings(pScheme);
  274. SetPaintBackgroundEnabled(false);
  275. // set our size
  276. int screenWide, screenTall;
  277. int x, y;
  278. GetPos(x, y);
  279. GetHudSize(screenWide, screenTall);
  280. SetBounds(0, y, screenWide, screenTall - y);
  281. }