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.

425 lines
12 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 "dod_shareddefs.h"
  23. // NVNT damage
  24. #include "haptics/haptic_utils.h"
  25. using namespace vgui;
  26. // memdbgon must be the last include file in a .cpp file!!!
  27. #include "tier0/memdbgon.h"
  28. //-----------------------------------------------------------------------------
  29. // Purpose: HUD Damage indication
  30. //-----------------------------------------------------------------------------
  31. class CHudDODDamageIndicator : public CHudElement, public vgui::Panel
  32. {
  33. DECLARE_CLASS_SIMPLE( CHudDODDamageIndicator, vgui::Panel );
  34. public:
  35. CHudDODDamageIndicator( const char *pElementName );
  36. void Init( void );
  37. void Reset( void );
  38. virtual bool ShouldDraw( void );
  39. // Handler for our message
  40. void MsgFunc_Damage( bf_read &msg );
  41. private:
  42. virtual void Paint();
  43. virtual void ApplySchemeSettings(vgui::IScheme *pScheme);
  44. private:
  45. CPanelAnimationVarAliasType( float, m_flDmgX, "dmg_xpos", "10", "proportional_float" );
  46. CPanelAnimationVarAliasType( float, m_flDmgY, "dmg_ypos", "80", "proportional_float" );
  47. CPanelAnimationVarAliasType( float, m_flDmgWide, "dmg_wide", "30", "proportional_float" );
  48. CPanelAnimationVarAliasType( float, m_flDmgTall1, "dmg_tall1", "300", "proportional_float" );
  49. CPanelAnimationVarAliasType( float, m_flDmgTall2, "dmg_tall2", "240", "proportional_float" );
  50. CPanelAnimationVar( Color, m_DmgColorLeft, "DmgColorLeft", "255 0 0 0" );
  51. CPanelAnimationVar( Color, m_DmgColorRight, "DmgColorRight", "255 0 0 0" );
  52. CPanelAnimationVar( Color, m_DmgHighColorLeft, "DmgHighColorLeft", "255 0 0 0" );
  53. CPanelAnimationVar( Color, m_DmgHighColorRight, "DmgHighColorRight", "255 0 0 0" );
  54. CPanelAnimationVar( Color, m_DmgFullscreenColor, "DmgFullscreenColor", "255 0 0 0" );
  55. void DrawDamageIndicator(int side);
  56. void DrawFullscreenDamageIndicator();
  57. void GetDamagePosition( const Vector &vecDelta, float *flRotation );
  58. CMaterialReference m_WhiteAdditiveMaterial;
  59. };
  60. DECLARE_HUDELEMENT( CHudDODDamageIndicator );
  61. DECLARE_HUD_MESSAGE( CHudDODDamageIndicator, Damage );
  62. enum
  63. {
  64. DAMAGE_ANY,
  65. DAMAGE_LOW,
  66. DAMAGE_HIGH,
  67. };
  68. #define ANGLE_ANY 0.0f
  69. #define DMG_ANY 0
  70. struct DamageAnimation_t
  71. {
  72. const char *name;
  73. int bitsDamage;
  74. float angleMinimum;
  75. float angleMaximum;
  76. int damage;
  77. };
  78. //-----------------------------------------------------------------------------
  79. // Purpose: List of damage animations, finds first that matches criteria
  80. //-----------------------------------------------------------------------------
  81. static DamageAnimation_t g_DamageAnimations[] =
  82. {
  83. { "HudTakeDamageLeft", DMG_ANY, 45.0f, 135.0f, DAMAGE_ANY },
  84. { "HudTakeDamageRight", DMG_ANY, 225.0f, 315.0f, DAMAGE_ANY },
  85. { "HudTakeDamageBehind", DMG_ANY, 135.0f, 225.0f, DAMAGE_ANY },
  86. // fall through to front damage
  87. { "HudTakeDamageFront", DMG_ANY, ANGLE_ANY, ANGLE_ANY, DAMAGE_ANY },
  88. { NULL },
  89. };
  90. //-----------------------------------------------------------------------------
  91. // Purpose: Constructor
  92. //-----------------------------------------------------------------------------
  93. CHudDODDamageIndicator::CHudDODDamageIndicator( const char *pElementName ) : CHudElement( pElementName ), BaseClass(NULL, "HudDamageIndicator")
  94. {
  95. vgui::Panel *pParent = g_pClientMode->GetViewport();
  96. SetParent( pParent );
  97. m_WhiteAdditiveMaterial.Init( "vgui/white_additive", TEXTURE_GROUP_VGUI );
  98. SetHiddenBits( HIDEHUD_HEALTH );
  99. }
  100. //-----------------------------------------------------------------------------
  101. // Purpose:
  102. //-----------------------------------------------------------------------------
  103. void CHudDODDamageIndicator::Reset( void )
  104. {
  105. m_DmgColorLeft[3] = 0;
  106. m_DmgColorRight[3] = 0;
  107. m_DmgHighColorLeft[3] = 0;
  108. m_DmgHighColorRight[3] = 0;
  109. m_DmgFullscreenColor[3] = 0;
  110. }
  111. void CHudDODDamageIndicator::Init( void )
  112. {
  113. HOOK_HUD_MESSAGE( CHudDODDamageIndicator, Damage );
  114. }
  115. //-----------------------------------------------------------------------------
  116. // Purpose:
  117. //-----------------------------------------------------------------------------
  118. bool CHudDODDamageIndicator::ShouldDraw( void )
  119. {
  120. if ( !CHudElement::ShouldDraw() )
  121. return false;
  122. if ( !m_DmgColorLeft[3] && !m_DmgColorRight[3] && !m_DmgHighColorLeft[3] && !m_DmgHighColorRight[3]
  123. && !m_DmgFullscreenColor[3] )
  124. return false;
  125. return true;
  126. }
  127. //-----------------------------------------------------------------------------
  128. // Purpose: Draws a damage quad
  129. //-----------------------------------------------------------------------------
  130. void CHudDODDamageIndicator::DrawDamageIndicator(int side)
  131. {
  132. CMatRenderContextPtr pRenderContext( materials );
  133. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
  134. CMeshBuilder meshBuilder;
  135. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  136. int insetY = (m_flDmgTall1 - m_flDmgTall2) / 2;
  137. int x1 = m_flDmgX;
  138. int x2 = m_flDmgX + m_flDmgWide;
  139. int y[4] = { (int)(m_flDmgY), (int)(m_flDmgY + insetY), (int)(m_flDmgY + m_flDmgTall1 - insetY), (int)(m_flDmgY + m_flDmgTall1) };
  140. int alpha[4] = { 0, 1, 1, 0 };
  141. // see if we're high damage
  142. bool bHighDamage = false;
  143. if ( m_DmgHighColorRight[3] > m_DmgColorRight[3] || m_DmgHighColorLeft[3] > m_DmgColorLeft[3] )
  144. {
  145. // make more of the screen be covered by damage
  146. x1 = GetWide() * 0.0f;
  147. x2 = GetWide() * 0.5f;
  148. y[0] = 0.0f;
  149. y[1] = 0.0f;
  150. y[2] = GetTall();
  151. y[3] = GetTall();
  152. alpha[0] = 1.0f;
  153. alpha[1] = 0.0f;
  154. alpha[2] = 0.0f;
  155. alpha[3] = 1.0f;
  156. bHighDamage = true;
  157. }
  158. int r, g, b, a;
  159. switch ( side )
  160. {
  161. case 0: // left
  162. {
  163. if ( bHighDamage )
  164. {
  165. r = m_DmgHighColorLeft[0], g = m_DmgHighColorLeft[1], b = m_DmgHighColorLeft[2], a = m_DmgHighColorLeft[3];
  166. }
  167. else
  168. {
  169. r = m_DmgColorLeft[0], g = m_DmgColorLeft[1], b = m_DmgColorLeft[2], a = m_DmgColorLeft[3];
  170. }
  171. meshBuilder.Color4ub( r, g, b, a * alpha[0] );
  172. meshBuilder.TexCoord2f( 0,0,0 );
  173. meshBuilder.Position3f( x1, y[0], 0 );
  174. meshBuilder.AdvanceVertex();
  175. meshBuilder.Color4ub( r, g, b, a * alpha[1] );
  176. meshBuilder.TexCoord2f( 0,1,0 );
  177. meshBuilder.Position3f( x2, y[1], 0 );
  178. meshBuilder.AdvanceVertex();
  179. meshBuilder.Color4ub( r, g, b, a * alpha[2] );
  180. meshBuilder.TexCoord2f( 0,1,1 );
  181. meshBuilder.Position3f( x2, y[2], 0 );
  182. meshBuilder.AdvanceVertex();
  183. meshBuilder.Color4ub( r, g, b, a * alpha[3] );
  184. meshBuilder.TexCoord2f( 0,0,1 );
  185. meshBuilder.Position3f( x1, y[3], 0 );
  186. meshBuilder.AdvanceVertex();
  187. }
  188. break;
  189. case 1: // right
  190. {
  191. if ( bHighDamage )
  192. {
  193. r = m_DmgHighColorRight[0], g = m_DmgHighColorRight[1], b = m_DmgHighColorRight[2], a = m_DmgHighColorRight[3];
  194. }
  195. else
  196. {
  197. r = m_DmgColorRight[0], g = m_DmgColorRight[1], b = m_DmgColorRight[2], a = m_DmgColorRight[3];
  198. }
  199. // realign x coords
  200. x1 = GetWide() - x1;
  201. x2 = GetWide() - x2;
  202. meshBuilder.Color4ub( r, g, b, a * alpha[0]);
  203. meshBuilder.TexCoord2f( 0,0,0 );
  204. meshBuilder.Position3f( x1, y[0], 0 );
  205. meshBuilder.AdvanceVertex();
  206. meshBuilder.Color4ub( r, g, b, a * alpha[3] );
  207. meshBuilder.TexCoord2f( 0,0,1 );
  208. meshBuilder.Position3f( x1, y[3], 0 );
  209. meshBuilder.AdvanceVertex();
  210. meshBuilder.Color4ub( r, g, b, a * alpha[2] );
  211. meshBuilder.TexCoord2f( 0,1,1 );
  212. meshBuilder.Position3f( x2, y[2], 0 );
  213. meshBuilder.AdvanceVertex();
  214. meshBuilder.Color4ub( r, g, b, a * alpha[1] );
  215. meshBuilder.TexCoord2f( 0,1,0 );
  216. meshBuilder.Position3f( x2, y[1], 0 );
  217. meshBuilder.AdvanceVertex();
  218. }
  219. break;
  220. }
  221. meshBuilder.End();
  222. pMesh->Draw();
  223. }
  224. //-----------------------------------------------------------------------------
  225. // Purpose: Draws full screen damage fade
  226. //-----------------------------------------------------------------------------
  227. void CHudDODDamageIndicator::DrawFullscreenDamageIndicator()
  228. {
  229. CMatRenderContextPtr pRenderContext( materials );
  230. IMesh *pMesh = pRenderContext->GetDynamicMesh( true, NULL, NULL, m_WhiteAdditiveMaterial );
  231. CMeshBuilder meshBuilder;
  232. meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 );
  233. int r = m_DmgFullscreenColor[0], g = m_DmgFullscreenColor[1], b = m_DmgFullscreenColor[2], a = m_DmgFullscreenColor[3];
  234. float wide = GetWide(), tall = GetTall();
  235. meshBuilder.Color4ub( r, g, b, a );
  236. meshBuilder.TexCoord2f( 0,0,0 );
  237. meshBuilder.Position3f( 0.0f, 0.0f, 0 );
  238. meshBuilder.AdvanceVertex();
  239. meshBuilder.Color4ub( r, g, b, a );
  240. meshBuilder.TexCoord2f( 0,1,0 );
  241. meshBuilder.Position3f( wide, 0.0f, 0 );
  242. meshBuilder.AdvanceVertex();
  243. meshBuilder.Color4ub( r, g, b, a );
  244. meshBuilder.TexCoord2f( 0,1,1 );
  245. meshBuilder.Position3f( wide, tall, 0 );
  246. meshBuilder.AdvanceVertex();
  247. meshBuilder.Color4ub( r, g, b, a );
  248. meshBuilder.TexCoord2f( 0,0,1 );
  249. meshBuilder.Position3f( 0.0f, tall, 0 );
  250. meshBuilder.AdvanceVertex();
  251. meshBuilder.End();
  252. pMesh->Draw();
  253. }
  254. //-----------------------------------------------------------------------------
  255. // Purpose: Paints the damage display
  256. //-----------------------------------------------------------------------------
  257. void CHudDODDamageIndicator::Paint()
  258. {
  259. // draw fullscreen damage indicators
  260. DrawFullscreenDamageIndicator();
  261. // draw side damage indicators
  262. DrawDamageIndicator(0);
  263. DrawDamageIndicator(1);
  264. }
  265. // NVNT - hacky way of passing damage
  266. static long lastDamage_s = 0;
  267. //-----------------------------------------------------------------------------
  268. // Purpose: Message handler for Damage message
  269. //-----------------------------------------------------------------------------
  270. void CHudDODDamageIndicator::MsgFunc_Damage( bf_read &msg )
  271. {
  272. int damageTaken = msg.ReadByte(); // health
  273. long bitsDamage = msg.ReadLong(); // damage bits
  274. Vector vecFrom;
  275. msg.ReadBitVec3Coord( vecFrom );
  276. C_BasePlayer *pPlayer = C_BasePlayer::GetLocalPlayer();
  277. if ( !pPlayer )
  278. return;
  279. Vector vecDelta = (vecFrom - MainViewOrigin());
  280. VectorNormalize( vecDelta );
  281. if ( damageTaken > 0 )
  282. {
  283. // see which quandrant the effect is in
  284. float angle;
  285. GetDamagePosition( vecDelta, &angle );
  286. // see which effect to play
  287. DamageAnimation_t *dmgAnim = g_DamageAnimations;
  288. for ( ; dmgAnim->name != NULL; ++dmgAnim )
  289. {
  290. if ( dmgAnim->bitsDamage && !(bitsDamage & dmgAnim->bitsDamage) )
  291. continue;
  292. if ( dmgAnim->angleMinimum && angle < dmgAnim->angleMinimum )
  293. continue;
  294. if ( dmgAnim->angleMaximum && angle > dmgAnim->angleMaximum )
  295. continue;
  296. // we have a match, break
  297. break;
  298. }
  299. if ( dmgAnim->name )
  300. {
  301. g_pClientMode->GetViewportAnimationController()->StartAnimationSequence( dmgAnim->name );
  302. }
  303. }
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Convert a damage position in world units to the screen's units
  307. //-----------------------------------------------------------------------------
  308. void CHudDODDamageIndicator::GetDamagePosition( const Vector &vecDelta, float *flRotation )
  309. {
  310. float flRadius = 360.0f;
  311. // Player Data
  312. Vector playerPosition = MainViewOrigin();
  313. QAngle playerAngles = MainViewAngles();
  314. Vector forward, right, up(0,0,1);
  315. AngleVectors (playerAngles, &forward, NULL, NULL );
  316. forward.z = 0;
  317. VectorNormalize(forward);
  318. CrossProduct( up, forward, right );
  319. float front = DotProduct(vecDelta, forward);
  320. float side = DotProduct(vecDelta, right);
  321. float top = DotProduct(vecDelta, up);
  322. // NVNT pass damage. (use hap_damage amount to apply)
  323. // do rotation
  324. Vector hapDir(side,-top,front);
  325. if ( haptics )
  326. haptics->ApplyDamageEffect(((float)lastDamage_s), 0, hapDir);
  327. float xpos = flRadius * -side;
  328. float ypos = flRadius * -front;
  329. // Get the rotation (yaw)
  330. *flRotation = atan2(xpos, ypos) + M_PI;
  331. *flRotation *= 180 / M_PI;
  332. float yawRadians = -(*flRotation) * M_PI / 180.0f;
  333. float ca = cos( yawRadians );
  334. float sa = sin( yawRadians );
  335. // Rotate it around the circle
  336. xpos = (int)((ScreenWidth() / 2) + (flRadius * sa));
  337. ypos = (int)((ScreenHeight() / 2) - (flRadius * ca));
  338. }
  339. //-----------------------------------------------------------------------------
  340. // Purpose: hud scheme settings
  341. //-----------------------------------------------------------------------------
  342. void CHudDODDamageIndicator::ApplySchemeSettings(vgui::IScheme *pScheme)
  343. {
  344. BaseClass::ApplySchemeSettings(pScheme);
  345. SetPaintBackgroundEnabled(false);
  346. int wide, tall;
  347. GetHudSize(wide, tall);
  348. SetSize(wide, tall);
  349. }