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.

604 lines
18 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: A blood spray effect, like a big exit wound, used when people are
  4. // violently impaled, skewered, eviscerated, etc.
  5. //
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "precache_register.h"
  9. #include "fx_sparks.h"
  10. #include "iefx.h"
  11. #include "c_te_effect_dispatch.h"
  12. #include "particles_ez.h"
  13. #include "decals.h"
  14. #include "engine/IEngineSound.h"
  15. #include "fx_quad.h"
  16. #include "engine/ivdebugoverlay.h"
  17. #include "shareddefs.h"
  18. #include "fx.h"
  19. #include "fx_blood.h"
  20. #include "effect_color_tables.h"
  21. #include "particle_simple3d.h"
  22. #include "particle_parse.h"
  23. // memdbgon must be the last include file in a .cpp file!!!
  24. #include "tier0/memdbgon.h"
  25. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectBloodSpray )
  26. PRECACHE( MATERIAL, "effects/blood_core" )
  27. PRECACHE( MATERIAL, "effects/blood_gore" )
  28. PRECACHE( MATERIAL, "effects/blood_drop" )
  29. PRECACHE( MATERIAL, "effects/blood_puff" )
  30. PRECACHE_REGISTER_END()
  31. // Cached material handles
  32. PMaterialHandle g_Blood_Core = NULL;
  33. PMaterialHandle g_Blood_Gore = NULL;
  34. PMaterialHandle g_Blood_Drops = NULL;
  35. //-----------------------------------------------------------------------------
  36. // Purpose:
  37. // Input : bloodtype -
  38. // r -
  39. // g -
  40. // b -
  41. //-----------------------------------------------------------------------------
  42. void GetBloodColor( int bloodtype, colorentry_t &color )
  43. {
  44. int i;
  45. for( i = 0 ; i < COLOR_TABLE_SIZE( bloodcolors ) ; i++ )
  46. {
  47. if( bloodcolors[i].index == bloodtype )
  48. {
  49. color = bloodcolors[ i ];
  50. return;
  51. }
  52. }
  53. // build a ridiculous default color
  54. color.r = 255;
  55. color.g = 0;
  56. color.b = 255;
  57. }
  58. //-----------------------------------------------------------------------------
  59. // Purpose:
  60. // Input : &origin -
  61. // &normal -
  62. // scale -
  63. // r -
  64. // g -
  65. // b -
  66. // flags -
  67. //-----------------------------------------------------------------------------
  68. void FX_BloodSpray( const Vector &origin, const Vector &normal, float scale, unsigned char r, unsigned char g, unsigned char b, int flags )
  69. {
  70. if ( UTIL_IsLowViolence() )
  71. return;
  72. //debugoverlay->AddLineOverlay( origin, origin + normal * 72, 255, 255, 255, true, 10 );
  73. Vector offset;
  74. float spread = 0.2f;
  75. //Find area ambient light color and use it to tint smoke
  76. Vector worldLight = WorldGetLightForPoint( origin, true );
  77. Vector color = Vector( (float)(worldLight[0] * r) / 255.0f, (float)(worldLight[1] * g) / 255.0f, (float)(worldLight[2] * b) / 255.0f );
  78. float colorRamp;
  79. int i;
  80. Vector offDir;
  81. Vector right;
  82. Vector up;
  83. if (normal != Vector(0, 0, 1) )
  84. {
  85. right = normal.Cross( Vector(0, 0, 1) );
  86. up = right.Cross( normal );
  87. }
  88. else
  89. {
  90. right = Vector(0, 0, 1);
  91. up = right.Cross( normal );
  92. }
  93. //
  94. // Dump out drops
  95. //
  96. if (flags & FX_BLOODSPRAY_DROPS)
  97. {
  98. TrailParticle *tParticle;
  99. CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" );
  100. if ( !pTrailEmitter )
  101. return;
  102. pTrailEmitter->SetSortOrigin( origin );
  103. // Partial gravity on blood drops.
  104. pTrailEmitter->SetGravity( 600.0 );
  105. pTrailEmitter->GetBinding().SetBBox( origin - Vector( 32, 32, 32 ), origin + Vector( 32, 32, 32 ) );
  106. pTrailEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  107. pTrailEmitter->SetVelocityDampen( 0.2f );
  108. PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_drop" );
  109. //
  110. // Long stringy drops of blood.
  111. //
  112. for ( i = 0; i < 14; i++ )
  113. {
  114. // Originate from within a circle 'scale' inches in diameter.
  115. offset = origin;
  116. offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
  117. offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
  118. tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  119. if ( tParticle == NULL )
  120. break;
  121. tParticle->m_flLifetime = 0.0f;
  122. offDir = normal + RandomVector( -0.3f, 0.3f );
  123. tParticle->m_vecVelocity = offDir * random->RandomFloat( 4.0f * scale, 40.0f * scale );
  124. tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale;
  125. tParticle->m_flWidth = random->RandomFloat( 0.125f, 0.275f ) * scale;
  126. tParticle->m_flLength = random->RandomFloat( 0.02f, 0.03f ) * scale;
  127. tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  128. FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f );
  129. }
  130. //
  131. // Shorter droplets.
  132. //
  133. for ( i = 0; i < 24; i++ )
  134. {
  135. // Originate from within a circle 'scale' inches in diameter.
  136. offset = origin;
  137. offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
  138. offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
  139. tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  140. if ( tParticle == NULL )
  141. break;
  142. tParticle->m_flLifetime = 0.0f;
  143. offDir = normal + RandomVector( -1.0f, 1.0f );
  144. offDir[2] += random->RandomFloat(0, 1.0f);
  145. tParticle->m_vecVelocity = offDir * random->RandomFloat( 2.0f * scale, 25.0f * scale );
  146. tParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f ) * scale;
  147. tParticle->m_flWidth = random->RandomFloat( 0.25f, 0.375f ) * scale;
  148. tParticle->m_flLength = random->RandomFloat( 0.0025f, 0.005f ) * scale;
  149. tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  150. FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f );
  151. }
  152. }
  153. if ((flags & FX_BLOODSPRAY_GORE) || (flags & FX_BLOODSPRAY_CLOUD))
  154. {
  155. CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" );
  156. if ( !pSimple )
  157. return;
  158. pSimple->SetSortOrigin( origin );
  159. pSimple->SetGravity( 0 );
  160. PMaterialHandle hMaterial;
  161. //
  162. // Tight blossom of blood at the center.
  163. //
  164. if (flags & FX_BLOODSPRAY_GORE)
  165. {
  166. hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_gore" );
  167. SimpleParticle *pParticle;
  168. for ( i = 0; i < 6; i++ )
  169. {
  170. // Originate from within a circle 'scale' inches in diameter.
  171. offset = origin + ( 0.5 * scale * normal );
  172. offset += right * random->RandomFloat( -0.5f, 0.5f ) * scale;
  173. offset += up * random->RandomFloat( -0.5f, 0.5f ) * scale;
  174. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
  175. if ( pParticle != NULL )
  176. {
  177. pParticle->m_flLifetime = 0.0f;
  178. pParticle->m_flDieTime = 0.3f;
  179. spread = 0.2f;
  180. pParticle->m_vecVelocity.Random( -spread, spread );
  181. pParticle->m_vecVelocity += normal * random->RandomInt( 10, 100 );
  182. //VectorNormalize( pParticle->m_vecVelocity );
  183. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  184. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  185. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  186. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  187. pParticle->m_uchStartSize = random->RandomFloat( scale * 0.25, scale );
  188. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
  189. pParticle->m_uchStartAlpha = random->RandomInt( 200, 255 );
  190. pParticle->m_uchEndAlpha = 0;
  191. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  192. pParticle->m_flRollDelta = 0.0f;
  193. }
  194. }
  195. }
  196. //
  197. // Diffuse cloud just in front of the exit wound.
  198. //
  199. if (flags & FX_BLOODSPRAY_CLOUD)
  200. {
  201. hMaterial = ParticleMgr()->GetPMaterial( "effects/blood_puff" );
  202. SimpleParticle *pParticle;
  203. for ( i = 0; i < 6; i++ )
  204. {
  205. // Originate from within a circle '2 * scale' inches in diameter.
  206. offset = origin + ( scale * normal );
  207. offset += right * random->RandomFloat( -1, 1 ) * scale;
  208. offset += up * random->RandomFloat( -1, 1 ) * scale;
  209. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, offset );
  210. if ( pParticle != NULL )
  211. {
  212. pParticle->m_flLifetime = 0.0f;
  213. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.8f);
  214. spread = 0.5f;
  215. pParticle->m_vecVelocity.Random( -spread, spread );
  216. pParticle->m_vecVelocity += normal * random->RandomInt( 100, 200 );
  217. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  218. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  219. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  220. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  221. pParticle->m_uchStartSize = random->RandomFloat( scale * 1.5f, scale * 2.0f );
  222. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  223. pParticle->m_uchStartAlpha = random->RandomInt( 80, 128 );
  224. pParticle->m_uchEndAlpha = 0;
  225. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  226. pParticle->m_flRollDelta = 0.0f;
  227. }
  228. }
  229. }
  230. }
  231. // TODO: Play a sound?
  232. //CLocalPlayerFilter filter;
  233. //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin );
  234. }
  235. //-----------------------------------------------------------------------------
  236. // Purpose: Used for bullets hitting bleeding surfaces
  237. // Input : origin -
  238. // normal -
  239. // scale - This parameter is not currently used
  240. //-----------------------------------------------------------------------------
  241. void FX_BloodBulletImpact( const Vector &origin, const Vector &normal, float scale /*NOTE: Unused!*/, unsigned char r, unsigned char g, unsigned char b )
  242. {
  243. if ( UTIL_IsLowViolence() )
  244. return;
  245. Vector offset;
  246. //Find area ambient light color and use it to tint smoke
  247. Vector worldLight = WorldGetLightForPoint( origin, true );
  248. if ( gpGlobals->maxClients > 1 )
  249. {
  250. worldLight = Vector( 1.0, 1.0, 1.0 );
  251. r = 96;
  252. g = 0;
  253. b = 10;
  254. }
  255. Vector color = Vector( (float)(worldLight[0] * r) / 255.0f, (float)(worldLight[1] * g) / 255.0f, (float)(worldLight[2] * b) / 255.0f );
  256. float colorRamp;
  257. Vector offDir;
  258. CSmartPtr<CBloodSprayEmitter> pSimple = CBloodSprayEmitter::Create( "bloodgore" );
  259. if ( !pSimple )
  260. return;
  261. pSimple->SetSortOrigin( origin );
  262. pSimple->SetGravity( 200 );
  263. // Setup a bounding box to contain the particles without (stops auto-updating)
  264. pSimple->GetBinding().SetBBox( origin - Vector( 16, 16, 16 ), origin + Vector( 16, 16, 16 ) );
  265. // Cache the material if we haven't already
  266. if ( g_Blood_Core == NULL )
  267. {
  268. g_Blood_Core = ParticleMgr()->GetPMaterial( "effects/blood_core" );
  269. }
  270. SimpleParticle *pParticle;
  271. Vector dir = normal * RandomVector( -0.5f, 0.5f );
  272. offset = origin + ( 2.0f * normal );
  273. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Blood_Core, offset );
  274. if ( pParticle != NULL )
  275. {
  276. pParticle->m_flLifetime = 0.0f;
  277. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f);
  278. pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f );
  279. pParticle->m_vecVelocity[2] -= random->RandomFloat( 8.0f, 16.0f );
  280. colorRamp = random->RandomFloat( 0.75f, 2.0f );
  281. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  282. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  283. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  284. pParticle->m_uchStartSize = random->RandomInt( 2, 4 );
  285. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8;
  286. pParticle->m_uchStartAlpha = 255;
  287. pParticle->m_uchEndAlpha = 0;
  288. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  289. pParticle->m_flRollDelta = 0.0f;
  290. }
  291. // Cache the material if we haven't already
  292. if ( g_Blood_Gore == NULL )
  293. {
  294. g_Blood_Gore = ParticleMgr()->GetPMaterial( "effects/blood_gore" );
  295. }
  296. for ( int i = 0; i < 4; i++ )
  297. {
  298. offset = origin + ( 2.0f * normal );
  299. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Blood_Gore, offset );
  300. if ( pParticle != NULL )
  301. {
  302. pParticle->m_flLifetime = 0.0f;
  303. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 0.75f);
  304. pParticle->m_vecVelocity = dir * random->RandomFloat( 16.0f, 32.0f )*(i+1);
  305. pParticle->m_vecVelocity[2] -= random->RandomFloat( 32.0f, 64.0f )*(i+1);
  306. colorRamp = random->RandomFloat( 0.75f, 2.0f );
  307. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  308. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  309. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  310. pParticle->m_uchStartSize = random->RandomInt( 2, 4 );
  311. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  312. pParticle->m_uchStartAlpha = 255;
  313. pParticle->m_uchEndAlpha = 0;
  314. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  315. pParticle->m_flRollDelta = 0.0f;
  316. }
  317. }
  318. //
  319. // Dump out drops
  320. //
  321. TrailParticle *tParticle;
  322. CSmartPtr<CTrailParticles> pTrailEmitter = CTrailParticles::Create( "blooddrops" );
  323. if ( !pTrailEmitter )
  324. return;
  325. pTrailEmitter->SetSortOrigin( origin );
  326. // Partial gravity on blood drops
  327. pTrailEmitter->SetGravity( 400.0 );
  328. // Enable simple collisions with nearby surfaces
  329. pTrailEmitter->Setup(origin, &normal, 1, 10, 100, 400, 0.2, 0 );
  330. if ( g_Blood_Drops == NULL )
  331. {
  332. g_Blood_Drops = ParticleMgr()->GetPMaterial( "effects/blood_drop" );
  333. }
  334. //
  335. // Shorter droplets
  336. //
  337. for ( int i = 0; i < 8; i++ )
  338. {
  339. // Originate from within a circle 'scale' inches in diameter
  340. offset = origin;
  341. tParticle = (TrailParticle *) pTrailEmitter->AddParticle( sizeof(TrailParticle), g_Blood_Drops, offset );
  342. if ( tParticle == NULL )
  343. break;
  344. tParticle->m_flLifetime = 0.0f;
  345. offDir = RandomVector( -1.0f, 1.0f );
  346. tParticle->m_vecVelocity = offDir * random->RandomFloat( 64.0f, 128.0f );
  347. tParticle->m_flWidth = random->RandomFloat( 0.5f, 2.0f );
  348. tParticle->m_flLength = random->RandomFloat( 0.05f, 0.15f );
  349. tParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  350. FloatToColor32( tParticle->m_color, color[0], color[1], color[2], 1.0f );
  351. }
  352. // TODO: Play a sound?
  353. //CLocalPlayerFilter filter;
  354. //C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, CHAN_VOICE, "Physics.WaterSplash", 1.0, ATTN_NORM, 0, 100, &origin );
  355. }
  356. // FIXME: This will be simplified when the initializer can take color parameters as an input
  357. // For now, we use different systems
  358. struct ParticleForBlood_t
  359. {
  360. int nColor;
  361. const char *lpszParticleSystemName;
  362. };
  363. ParticleForBlood_t bloodCallbacks[] =
  364. {
  365. { BLOOD_COLOR_RED, "blood_impact_red_01" },
  366. { BLOOD_COLOR_GREEN, "blood_impact_green_01" },
  367. { BLOOD_COLOR_YELLOW, "blood_impact_yellow_01" },
  368. #if defined( HL2_EPISODIC )
  369. { BLOOD_COLOR_ANTLION, "blood_impact_antlion_01" }, // FIXME: Move to Base HL2
  370. { BLOOD_COLOR_ZOMBIE, "blood_impact_zombie_01" }, // FIXME: Move to Base HL2
  371. { BLOOD_COLOR_ANTLION_WORKER, "blood_impact_antlion_worker_01" },
  372. { BLOOD_COLOR_BLOB, "blob_impact" },
  373. { BLOOD_COLOR_BLOB_FROZEN, "blob_impact_frozen" },
  374. #endif // HL2_EPISODIC
  375. };
  376. //-----------------------------------------------------------------------------
  377. // Purpose: Intercepts the blood spray message.
  378. //-----------------------------------------------------------------------------
  379. void BloodSprayCallback( const CEffectData &data )
  380. {
  381. colorentry_t color;
  382. GetBloodColor( data.m_nColor, color );
  383. FX_BloodSpray( data.m_vOrigin, data.m_vNormal, data.m_flScale, color.r, color.g, color.b, data.m_fFlags );
  384. }
  385. DECLARE_CLIENT_EFFECT( bloodspray, BloodSprayCallback );
  386. //-----------------------------------------------------------------------------
  387. //-----------------------------------------------------------------------------
  388. void BloodImpactCallback( const CEffectData & data )
  389. {
  390. bool bFoundBlood = false;
  391. // Find which sort of blood we are
  392. for ( int i = 0; i < ARRAYSIZE( bloodCallbacks ); i++ )
  393. {
  394. if ( bloodCallbacks[i].nColor == data.m_nColor )
  395. {
  396. QAngle vecAngles;
  397. VectorAngles( -data.m_vNormal, vecAngles );
  398. DispatchParticleEffect( bloodCallbacks[i].lpszParticleSystemName, data.m_vOrigin, vecAngles );
  399. bFoundBlood = true;
  400. break;
  401. }
  402. }
  403. if ( bFoundBlood == false )
  404. {
  405. Vector vecPosition;
  406. vecPosition = data.m_vOrigin;
  407. // Fetch the blood color.
  408. colorentry_t color;
  409. GetBloodColor( data.m_nColor, color );
  410. FX_BloodBulletImpact( vecPosition, data.m_vNormal, data.m_flScale, color.r, color.g, color.b );
  411. }
  412. }
  413. DECLARE_CLIENT_EFFECT_BEGIN( BloodImpact, BloodImpactCallback )
  414. PRECACHE( PARTICLE_SYSTEM, "blood_impact_red_01" )
  415. PRECACHE( PARTICLE_SYSTEM, "blood_impact_green_01" )
  416. PRECACHE( PARTICLE_SYSTEM, "blood_impact_yellow_01" )
  417. #if defined( HL2_EPISODIC )
  418. PRECACHE( PARTICLE_SYSTEM, "blood_impact_antlion_01" ) // FIXME: Move to Base HL2
  419. PRECACHE( PARTICLE_SYSTEM, "blood_impact_zombie_01" ) // FIXME: Move to Base HL2
  420. PRECACHE( PARTICLE_SYSTEM, "blood_impact_antlion_worker_01" )
  421. #endif
  422. DECLARE_CLIENT_EFFECT_END()
  423. //-----------------------------------------------------------------------------
  424. //-----------------------------------------------------------------------------
  425. void HunterDamageCallback( const CEffectData &data )
  426. {
  427. CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "HunterDamage" );
  428. if ( pGlassEmitter == NULL )
  429. return;
  430. pGlassEmitter->SetSortOrigin( data.m_vOrigin );
  431. // Handle increased scale
  432. const float flMaxSpeed = 400.0f;
  433. const float flMinSpeed = 50.0f;
  434. float flAngularSpray = 1.0f;
  435. // Setup our collision information
  436. pGlassEmitter->m_ParticleCollision.Setup( data.m_vOrigin, &data.m_vNormal, flAngularSpray, flMinSpeed, flMaxSpeed, 600.0f, 0.2f );
  437. Vector dir, end;
  438. int numFlecks = 32;
  439. Particle3D *pFleckParticle;
  440. Vector spawnOffset;
  441. //Dump out flecks
  442. for ( int i = 0; i < numFlecks; i++ )
  443. {
  444. spawnOffset = data.m_vOrigin + RandomVector( -32.0f, 32.0f );
  445. pFleckParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset );
  446. if ( pFleckParticle == NULL )
  447. break;
  448. pFleckParticle->m_flLifeRemaining = random->RandomFloat( 2.0f, 3.0f );
  449. dir[0] = data.m_vNormal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  450. dir[1] = data.m_vNormal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  451. dir[2] = data.m_vNormal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  452. pFleckParticle->m_uchSize = random->RandomInt( 3, 8 );
  453. pFleckParticle->m_vecVelocity = dir * random->RandomFloat( flMinSpeed, flMaxSpeed);
  454. pFleckParticle->m_vAngles = RandomAngle( 0, 360 );
  455. pFleckParticle->m_flAngSpeed = random->RandomFloat( -800, 800 );
  456. unsigned char color = 255;
  457. pFleckParticle->m_uchFrontColor[0] = color;
  458. pFleckParticle->m_uchFrontColor[1] = color;
  459. pFleckParticle->m_uchFrontColor[2] = color;
  460. pFleckParticle->m_uchBackColor[0] = color * 0.25f;
  461. pFleckParticle->m_uchBackColor[1] = color * 0.25f;
  462. pFleckParticle->m_uchBackColor[2] = color * 0.25f;
  463. }
  464. }
  465. DECLARE_CLIENT_EFFECT( HunterDamage, HunterDamageCallback );