Counter Strike : Global Offensive Source Code
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.

381 lines
10 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A blood spray effect to expose successful hits.
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "precache_register.h"
  8. #include "fx_sparks.h"
  9. #include "iefx.h"
  10. #include "c_te_effect_dispatch.h"
  11. #include "particles_ez.h"
  12. #include "decals.h"
  13. #include "engine/IEngineSound.h"
  14. #include "fx_quad.h"
  15. #include "engine/ivdebugoverlay.h"
  16. #include "shareddefs.h"
  17. #include "fx_blood.h"
  18. #include "view.h"
  19. #include "c_cs_player.h"
  20. // NOTE: This has to be the last file included!
  21. #include "tier0/memdbgon.h"
  22. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectCSBloodSpray )
  23. PRECACHE( PARTICLE_SYSTEM, "blood_impact_basic" )
  24. PRECACHE( PARTICLE_SYSTEM, "blood_impact_heavy" )
  25. PRECACHE( PARTICLE_SYSTEM, "blood_impact_medium" )
  26. PRECACHE( PARTICLE_SYSTEM, "blood_impact_light" )
  27. PRECACHE( PARTICLE_SYSTEM, "blood_impact_light_headshot" )
  28. PRECACHE_REGISTER_END()
  29. static ConVar damage_impact_heavy( "damage_impact_heavy", "40", FCVAR_NONE, "Damage ABOVE this value is considered heavy damage" );
  30. static ConVar damage_impact_medium( "damage_impact_medium", "20", FCVAR_NONE, "Damage BELOW this value is considered light damage" );
  31. class CHitEffectRamp
  32. {
  33. public:
  34. float m_flDamageAmount;
  35. float m_flMinAlpha;
  36. float m_flMaxAlpha;
  37. float m_flMinSize;
  38. float m_flMaxSize;
  39. float m_flMinVelocity;
  40. float m_flMaxVelocity;
  41. };
  42. void InterpolateRamp(
  43. const CHitEffectRamp &a,
  44. const CHitEffectRamp &b,
  45. CHitEffectRamp &out,
  46. int iDamage )
  47. {
  48. float t = RemapVal( iDamage, a.m_flDamageAmount, b.m_flDamageAmount, 0, 1 );
  49. out.m_flMinAlpha = FLerp( a.m_flMinAlpha, b.m_flMinAlpha, t );
  50. out.m_flMaxAlpha = FLerp( a.m_flMaxAlpha, b.m_flMaxAlpha, t );
  51. out.m_flMinAlpha = clamp( out.m_flMinAlpha, 0, 255 );
  52. out.m_flMaxAlpha = clamp( out.m_flMaxAlpha, 0, 255 );
  53. out.m_flMinSize = FLerp( a.m_flMinSize, b.m_flMinSize, t );
  54. out.m_flMaxSize = FLerp( a.m_flMaxSize, b.m_flMaxSize, t );
  55. out.m_flMinVelocity = FLerp( a.m_flMinVelocity, b.m_flMinVelocity, t );
  56. out.m_flMaxVelocity = FLerp( a.m_flMaxVelocity, b.m_flMaxVelocity, t );
  57. }
  58. void FX_HitEffectSmoke(
  59. CSmartPtr<CBloodSprayEmitter> pEmitter,
  60. int iDamage,
  61. const Vector &vEntryPoint,
  62. const Vector &vDirection,
  63. float flScale)
  64. {
  65. SimpleParticle newParticle;
  66. PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" );
  67. // These parameters create a ramp based on how much damage the shot did.
  68. CHitEffectRamp ramps[2] =
  69. {
  70. {
  71. 0,
  72. 30, // min/max alpha
  73. 70,
  74. 0.5, // min/max size
  75. 1,
  76. 0, // min/max velocity (not used here)
  77. 0
  78. },
  79. {
  80. 50,
  81. 30, // min/max alpha
  82. 70,
  83. 1, // min/max size
  84. 2,
  85. 0, // min/max velocity (not used here)
  86. 0
  87. }
  88. };
  89. CHitEffectRamp interpolatedRamp;
  90. InterpolateRamp(
  91. ramps[0],
  92. ramps[1],
  93. interpolatedRamp,
  94. iDamage );
  95. for ( int i=0; i < 2; i++ )
  96. {
  97. SimpleParticle &newParticle = *pEmitter->AddSimpleParticle( hMaterial, vEntryPoint, 0, 0 );
  98. newParticle.m_flLifetime = 0.0f;
  99. newParticle.m_flDieTime = 3.0f;
  100. newParticle.m_uchStartSize = random->RandomInt(
  101. interpolatedRamp.m_flMinSize,
  102. interpolatedRamp.m_flMaxSize ) * flScale;
  103. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4;
  104. newParticle.m_vecVelocity = Vector( 0, 0, 5 ) + RandomVector( -2, 2 );
  105. newParticle.m_uchStartAlpha = random->RandomInt(
  106. interpolatedRamp.m_flMinSize,
  107. interpolatedRamp.m_flMaxSize );
  108. newParticle.m_uchEndAlpha = 0;
  109. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  110. newParticle.m_flRollDelta = random->RandomFloat( -1, 1 );
  111. newParticle.m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY;
  112. float colorRamp = random->RandomFloat( 0.5f, 1.25f );
  113. newParticle.m_uchColor[0] = MIN( 1.0f, colorRamp ) * 255.0f;
  114. newParticle.m_uchColor[1] = MIN( 1.0f, colorRamp ) * 255.0f;
  115. newParticle.m_uchColor[2] = MIN( 1.0f, colorRamp ) * 255.0f;
  116. }
  117. }
  118. void FX_HitEffectBloodSpray(
  119. CSmartPtr<CBloodSprayEmitter> pEmitter,
  120. int iDamage,
  121. const Vector &vEntryPoint,
  122. const Vector &vSprayNormal,
  123. const char *pMaterialName,
  124. float flLODDistance,
  125. float flDistanceScale,
  126. float flScale,
  127. float flSpeed )
  128. {
  129. PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( pMaterialName );
  130. SimpleParticle *pParticle;
  131. float color[3] = { 1.0, 0, 0 };
  132. Vector up( 0, 0, 1 );
  133. Vector right = up.Cross( vSprayNormal );
  134. VectorNormalize( right );
  135. // These parameters create a ramp based on how much damage the shot did.
  136. CHitEffectRamp ramps[2] =
  137. {
  138. {
  139. 0,
  140. 80, // min/max alpha
  141. 128,
  142. flScale/2,// min/max size
  143. flScale,
  144. 10, // min/max velocity
  145. 20
  146. },
  147. {
  148. 50,
  149. 80, // min/max alpha
  150. 128,
  151. flScale/2,// min/max size
  152. flScale,
  153. 30, // min/max velocity
  154. 60
  155. }
  156. };
  157. CHitEffectRamp interpolatedRamp;
  158. InterpolateRamp(
  159. ramps[0],
  160. ramps[1],
  161. interpolatedRamp,
  162. iDamage );
  163. for ( int i = 0; i < 6; i++ )
  164. {
  165. // Originate from within a circle '2 * scale' inches in diameter.
  166. Vector offset = vEntryPoint + ( flScale * vSprayNormal * 0.5 );
  167. offset += right * random->RandomFloat( -1, 1 ) * flScale;
  168. offset += up * random->RandomFloat( -1, 1 ) * flScale;
  169. pParticle = pEmitter->AddSimpleParticle( hMaterial, offset, 0, 0 );
  170. if ( pParticle != NULL )
  171. {
  172. pParticle->m_flLifetime = 0.0f;
  173. pParticle->m_flDieTime = random->RandomFloat( 0.7f, 1.3f);
  174. // All the particles are between red and white. The whiter the particle is, the slower it goes.
  175. float whiteness = random->RandomFloat( 0.1, 0.7 );
  176. float speedFactor = 1 - whiteness;
  177. float spread = 0.5f;
  178. pParticle->m_vecVelocity.Random( -spread, spread );
  179. pParticle->m_vecVelocity += vSprayNormal * random->RandomInt( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity ) * flSpeed * speedFactor;
  180. float colorRamp = random->RandomFloat( 0.5f, 0.75f ) + flLODDistance;
  181. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  182. pParticle->m_uchColor[1] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f;
  183. pParticle->m_uchColor[2] = MIN( 1.0f, whiteness * colorRamp ) * 255.0f;
  184. pParticle->m_uchStartSize = random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize ) * flDistanceScale;
  185. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4 * flDistanceScale;
  186. pParticle->m_uchStartAlpha = random->RandomInt( interpolatedRamp.m_flMinAlpha, interpolatedRamp.m_flMaxAlpha );
  187. pParticle->m_uchEndAlpha = 0;
  188. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  189. pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
  190. }
  191. }
  192. }
  193. void FX_HitEffectBloodSplatter(
  194. CSmartPtr<CBloodSprayEmitter> pTrailEmitter,
  195. int iDamage,
  196. const Vector &vExitPoint,
  197. const Vector &vSplatterNormal,
  198. float flLODDistance )
  199. {
  200. float flScale = 4;
  201. pTrailEmitter->SetSortOrigin( vExitPoint );
  202. PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" );
  203. Vector up( 0, 0, 1 );
  204. Vector right = up.Cross( vSplatterNormal );
  205. VectorNormalize( right );
  206. // These parameters create a ramp based on how much damage the shot did.
  207. CHitEffectRamp ramps[2] =
  208. {
  209. {
  210. 0,
  211. 0, // min/max alpha
  212. 75,
  213. 1.5f, // min/max size
  214. 2.0f,
  215. 25.0f * flScale, // min/max velocity
  216. 35.0f * flScale
  217. },
  218. {
  219. 50,
  220. 0, // min/max alpha
  221. 140,
  222. 1.5f,// min/max size
  223. 2.0f,
  224. 65.0f * flScale, // min/max velocity
  225. 75.0f * flScale
  226. }
  227. };
  228. CHitEffectRamp interpolatedRamp;
  229. InterpolateRamp(
  230. ramps[0],
  231. ramps[1],
  232. interpolatedRamp,
  233. iDamage );
  234. for ( int i = 0; i < 20; i++ )
  235. {
  236. // Originate from within a circle 'scale' inches in diameter.
  237. Vector offset = vExitPoint;
  238. offset += right * random->RandomFloat( -0.15f, 0.15f ) * flScale;
  239. offset += up * random->RandomFloat( -0.15f, 0.15f ) * flScale;
  240. SimpleParticle *tParticle = (SimpleParticle*)pTrailEmitter->AddSimpleParticle(
  241. hMaterial,
  242. vExitPoint,
  243. random->RandomFloat( 0.225f, 0.35f ),
  244. random->RandomFloat( interpolatedRamp.m_flMinSize, interpolatedRamp.m_flMaxSize )
  245. );
  246. if ( tParticle == NULL )
  247. break;
  248. Vector offDir = vSplatterNormal + RandomVector( -0.05f, 0.05f );
  249. tParticle->m_vecVelocity = offDir * random->RandomFloat( interpolatedRamp.m_flMinVelocity, interpolatedRamp.m_flMaxVelocity );
  250. tParticle->m_iFlags = SIMPLE_PARTICLE_FLAG_NO_VEL_DECAY;
  251. tParticle->m_uchColor[0] = 150;
  252. tParticle->m_uchColor[1] = 0;
  253. tParticle->m_uchColor[2] = 0;
  254. tParticle->m_uchStartAlpha = interpolatedRamp.m_flMaxAlpha / 2;
  255. tParticle->m_uchEndAlpha = 0;
  256. }
  257. }
  258. //-----------------------------------------------------------------------------
  259. // Purpose:
  260. // Input : origin -
  261. // normal -
  262. // scale -
  263. //-----------------------------------------------------------------------------
  264. void FX_CS_BloodSpray( const Vector &origin, const Vector &normal, float flDamage )
  265. {
  266. if ( UTIL_IsLowViolence() )
  267. return;
  268. static ConVar *violence_hblood = cvar->FindVar( "violence_hblood" );
  269. if ( violence_hblood && !violence_hblood->GetBool() )
  270. return;
  271. // Use the new particle system
  272. Vector dir = normal;/* * RandomVector( -0.05f, 0.05f )*/;
  273. Vector offset = origin + ( normal );
  274. QAngle vecAngles;
  275. VectorAngles( dir, vecAngles );
  276. const char *pEffectName;
  277. if ( flDamage > damage_impact_heavy.GetInt() )
  278. {
  279. pEffectName = "blood_impact_heavy";
  280. }
  281. else if ( flDamage >= damage_impact_medium.GetInt() )
  282. {
  283. pEffectName = "blood_impact_medium";
  284. }
  285. else if ( flDamage > 1 )
  286. {
  287. pEffectName = "blood_impact_light";
  288. }
  289. else
  290. {
  291. pEffectName = "blood_impact_light_headshot";
  292. }
  293. DispatchParticleEffect( pEffectName, offset, vecAngles );
  294. }
  295. //-----------------------------------------------------------------------------
  296. // Purpose:
  297. // Input : bloodtype -
  298. // r -
  299. // g -
  300. // b -
  301. //-----------------------------------------------------------------------------
  302. void GetBloodColorForTeam( int iTeam, unsigned char &r, unsigned char &g, unsigned char &b )
  303. {
  304. }
  305. //-----------------------------------------------------------------------------
  306. // Purpose: Intercepts the blood spray message.
  307. //-----------------------------------------------------------------------------
  308. void CSBloodSprayCallback( const CEffectData &data )
  309. {
  310. FX_CS_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flMagnitude );
  311. }
  312. DECLARE_CLIENT_EFFECT( csblood, CSBloodSprayCallback );