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.

1431 lines
44 KiB

  1. //========= Copyright Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose:
  4. //
  5. //=============================================================================//
  6. #include "cbase.h"
  7. #include "fx.h"
  8. #include "fx_sparks.h"
  9. #include "clienteffectprecachesystem.h"
  10. #include "particle_simple3d.h"
  11. #include "decals.h"
  12. #include "engine/IEngineSound.h"
  13. #include "c_te_particlesystem.h"
  14. #include "engine/ivmodelinfo.h"
  15. #include "particles_ez.h"
  16. #include "c_impact_effects.h"
  17. #include "engine/IStaticPropMgr.h"
  18. #include "tier0/vprof.h"
  19. #include "c_te_effect_dispatch.h"
  20. // memdbgon must be the last include file in a .cpp file!!!
  21. #include "tier0/memdbgon.h"
  22. //Precahce the effects
  23. CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectImpacts )
  24. CLIENTEFFECT_MATERIAL( "effects/fleck_cement1" )
  25. CLIENTEFFECT_MATERIAL( "effects/fleck_cement2" )
  26. CLIENTEFFECT_MATERIAL( "effects/fleck_antlion1" )
  27. CLIENTEFFECT_MATERIAL( "effects/fleck_antlion2" )
  28. CLIENTEFFECT_MATERIAL( "effects/fleck_wood1" )
  29. CLIENTEFFECT_MATERIAL( "effects/fleck_wood2" )
  30. CLIENTEFFECT_MATERIAL( "effects/blood" )
  31. CLIENTEFFECT_MATERIAL( "effects/blood2" )
  32. CLIENTEFFECT_MATERIAL( "sprites/bloodspray" )
  33. CLIENTEFFECT_MATERIAL( "particle/particle_noisesphere" )
  34. CLIENTEFFECT_REGISTER_END()
  35. // Cached handles to commonly used materials
  36. PMaterialHandle g_Mat_Fleck_Wood[2] = { NULL, NULL };
  37. PMaterialHandle g_Mat_Fleck_Cement[2] = { NULL, NULL };
  38. PMaterialHandle g_Mat_Fleck_Antlion[2] = { NULL, NULL };
  39. PMaterialHandle g_Mat_Fleck_Glass[2] = { NULL, NULL };
  40. PMaterialHandle g_Mat_Fleck_Tile[2] = { NULL, NULL };
  41. PMaterialHandle g_Mat_DustPuff[2] = { NULL, NULL };
  42. PMaterialHandle g_Mat_BloodPuff[2] = { NULL, NULL };
  43. PMaterialHandle g_Mat_SMG_Muzzleflash[4] = { NULL, NULL, NULL, NULL };
  44. PMaterialHandle g_Mat_Combine_Muzzleflash[3] = { NULL, NULL, NULL };
  45. static ConVar fx_drawimpactdebris( "fx_drawimpactdebris", "1", FCVAR_DEVELOPMENTONLY, "Draw impact debris effects." );
  46. static ConVar fx_drawimpactdust( "fx_drawimpactdust", "1", FCVAR_DEVELOPMENTONLY, "Draw impact dust effects." );
  47. void FX_CacheMaterialHandles( void )
  48. {
  49. g_Mat_Fleck_Wood[0] = ParticleMgr()->GetPMaterial( "effects/fleck_wood1" );
  50. g_Mat_Fleck_Wood[1] = ParticleMgr()->GetPMaterial( "effects/fleck_wood2" );
  51. g_Mat_Fleck_Cement[0] = ParticleMgr()->GetPMaterial( "effects/fleck_cement1");
  52. g_Mat_Fleck_Cement[1] = ParticleMgr()->GetPMaterial( "effects/fleck_cement2" );
  53. g_Mat_Fleck_Antlion[0] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion1" );
  54. g_Mat_Fleck_Antlion[1] = ParticleMgr()->GetPMaterial( "effects/fleck_antlion2" );
  55. g_Mat_Fleck_Glass[0] = ParticleMgr()->GetPMaterial( "effects/fleck_glass1" );
  56. g_Mat_Fleck_Glass[1] = ParticleMgr()->GetPMaterial( "effects/fleck_glass2" );
  57. g_Mat_Fleck_Tile[0] = ParticleMgr()->GetPMaterial( "effects/fleck_tile1" );
  58. g_Mat_Fleck_Tile[1] = ParticleMgr()->GetPMaterial( "effects/fleck_tile2" );
  59. g_Mat_DustPuff[0] = ParticleMgr()->GetPMaterial( "particle/particle_smokegrenade" );
  60. g_Mat_DustPuff[1] = ParticleMgr()->GetPMaterial( "particle/particle_noisesphere" );
  61. g_Mat_BloodPuff[0] = ParticleMgr()->GetPMaterial( "effects/blood" );
  62. g_Mat_BloodPuff[1] = ParticleMgr()->GetPMaterial( "effects/blood2" );
  63. #ifndef TF_CLIENT_DLL
  64. g_Mat_SMG_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/muzzleflash1" );
  65. g_Mat_SMG_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/muzzleflash2" );
  66. g_Mat_SMG_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/muzzleflash3" );
  67. g_Mat_SMG_Muzzleflash[3] = ParticleMgr()->GetPMaterial( "effects/muzzleflash4" );
  68. #ifndef CSTRIKE_DLL
  69. g_Mat_Combine_Muzzleflash[0] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle1" );
  70. g_Mat_Combine_Muzzleflash[1] = ParticleMgr()->GetPMaterial( "effects/combinemuzzle2" );
  71. g_Mat_Combine_Muzzleflash[2] = ParticleMgr()->GetPMaterial( "effects/strider_muzzle" );
  72. #endif
  73. #endif
  74. }
  75. extern PMaterialHandle g_Material_Spark;
  76. //-----------------------------------------------------------------------------
  77. // Purpose: Returns the color given trace information
  78. // Input : *trace - trace to get results for
  79. // *color - return color, gamma corrected (0.0f to 1.0f)
  80. //-----------------------------------------------------------------------------
  81. void GetColorForSurface( trace_t *trace, Vector *color )
  82. {
  83. Vector baseColor, diffuseColor;
  84. Vector end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f;
  85. if ( trace->DidHitWorld() )
  86. {
  87. if ( trace->hitbox == 0 )
  88. {
  89. // If we hit the world, then ask the world for the fleck color
  90. engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor );
  91. }
  92. else
  93. {
  94. // In this case we hit a static prop.
  95. staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor );
  96. }
  97. }
  98. else
  99. {
  100. // In this case, we hit an entity. Find out the model associated with it
  101. C_BaseEntity *pEnt = trace->m_pEnt;
  102. if ( !pEnt )
  103. {
  104. Msg("Couldn't find surface in GetColorForSurface()\n");
  105. color->x = 255;
  106. color->y = 255;
  107. color->z = 255;
  108. return;
  109. }
  110. ICollideable *pCollide = pEnt->GetCollideable();
  111. int modelIndex = pCollide->GetCollisionModelIndex();
  112. model_t* pModel = const_cast<model_t*>(modelinfo->GetModel( modelIndex ));
  113. // Ask the model info about what we need to know
  114. modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(),
  115. pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor );
  116. }
  117. //Get final light value
  118. color->x = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0];
  119. color->y = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1];
  120. color->z = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2];
  121. }
  122. //-----------------------------------------------------------------------------
  123. // This does the actual debris flecks
  124. //-----------------------------------------------------------------------------
  125. #define FLECK_MIN_SPEED 64.0f
  126. #define FLECK_MAX_SPEED 128.0f
  127. #define FLECK_GRAVITY 800.0f
  128. #define FLECK_DAMPEN 0.3f
  129. #define FLECK_ANGULAR_SPRAY 0.6f
  130. #ifndef _XBOX
  131. //
  132. // PC ONLY!
  133. //
  134. static void CreateFleckParticles( const Vector& origin, const Vector &color, trace_t *trace, char materialType, int iScale )
  135. {
  136. Vector spawnOffset = trace->endpos + ( trace->plane.normal * 1.0f );
  137. CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset, Vector(5,5,5) );
  138. if ( !fleckEmitter )
  139. return;
  140. // Handle increased scale
  141. float flMaxSpeed = FLECK_MAX_SPEED * iScale;
  142. float flAngularSpray = MAX( 0.2, FLECK_ANGULAR_SPRAY - ( (float)iScale * 0.2f) ); // More power makes the spray more controlled
  143. // Setup our collision information
  144. fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &trace->plane.normal, flAngularSpray, FLECK_MIN_SPEED, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );
  145. PMaterialHandle *hMaterial;
  146. switch ( materialType )
  147. {
  148. case CHAR_TEX_WOOD:
  149. hMaterial = g_Mat_Fleck_Wood;
  150. break;
  151. case CHAR_TEX_CONCRETE:
  152. case CHAR_TEX_TILE:
  153. default:
  154. hMaterial = g_Mat_Fleck_Cement;
  155. break;
  156. }
  157. Vector dir, end;
  158. float colorRamp;
  159. float fScale = g_pParticleSystemMgr->ParticleThrottleScaling() * (float)iScale;
  160. int numFlecks = (int)( 0.5f + fScale * (float)( random->RandomInt( 4, 16 ) ) );
  161. FleckParticle *pFleckParticle;
  162. //Dump out flecks
  163. int i;
  164. for ( i = 0; i < numFlecks; i++ )
  165. {
  166. pFleckParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterial[random->RandomInt(0,1)], spawnOffset );
  167. if ( pFleckParticle == NULL )
  168. break;
  169. pFleckParticle->m_flLifetime = 0.0f;
  170. pFleckParticle->m_flDieTime = 3.0f;
  171. dir[0] = trace->plane.normal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  172. dir[1] = trace->plane.normal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  173. dir[2] = trace->plane.normal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  174. pFleckParticle->m_uchSize = random->RandomInt( 1, 2 );
  175. pFleckParticle->m_vecVelocity = dir * ( random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed) * ( 3 - pFleckParticle->m_uchSize ) );
  176. pFleckParticle->m_flRoll = random->RandomFloat( 0, 360 );
  177. pFleckParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
  178. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  179. pFleckParticle->m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  180. pFleckParticle->m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  181. pFleckParticle->m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  182. }
  183. }
  184. #endif // _XBOX
  185. //-----------------------------------------------------------------------------
  186. // Purpose: Debris flecks caused by impacts
  187. // Input : origin - start
  188. // *trace - trace information
  189. // *materialName - material hit
  190. // materialType - type of material hit
  191. //-----------------------------------------------------------------------------
  192. void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int iScale, bool bNoFlecks )
  193. {
  194. VPROF_BUDGET( "FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  195. if ( !fx_drawimpactdebris.GetBool() )
  196. return;
  197. #ifdef _XBOX
  198. //
  199. // XBox version
  200. //
  201. Vector offset;
  202. float spread = 0.2f;
  203. CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
  204. pSimple->SetSortOrigin( origin );
  205. // Lock the bbox
  206. pSimple->GetBinding().SetBBox( origin - ( Vector( 16, 16, 16 ) * iScale ), origin + ( Vector( 16, 16, 16 ) * iScale ) );
  207. // Get the color of the surface we've impacted
  208. Vector color;
  209. float colorRamp;
  210. GetColorForSurface( tr, &color );
  211. int i;
  212. SimpleParticle *pParticle;
  213. for ( i = 0; i < 4; i++ )
  214. {
  215. if ( i == 3 )
  216. {
  217. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
  218. }
  219. else
  220. {
  221. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
  222. }
  223. if ( pParticle != NULL )
  224. {
  225. pParticle->m_flLifetime = 0.0f;
  226. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  227. pParticle->m_vecVelocity.Random( -spread, spread );
  228. pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
  229. VectorNormalize( pParticle->m_vecVelocity );
  230. float fForce = random->RandomFloat( 250, 500 ) * i * 0.5f;
  231. // scaled
  232. pParticle->m_vecVelocity *= fForce * iScale;
  233. // Ramp the color
  234. colorRamp = random->RandomFloat( 0.5f, 1.25f );
  235. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  236. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  237. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  238. // scaled
  239. pParticle->m_uchStartSize = (iScale*0.5f) * random->RandomInt( 3, 4 ) * (i+1);
  240. // scaled
  241. pParticle->m_uchEndSize = (iScale*0.5f) * pParticle->m_uchStartSize * 4;
  242. pParticle->m_uchStartAlpha = random->RandomInt( 200, 255 );
  243. pParticle->m_uchEndAlpha = 0;
  244. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  245. pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
  246. }
  247. }
  248. // Covers the impact spot with flecks
  249. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff2, origin );
  250. if ( pParticle != NULL )
  251. {
  252. offset = origin;
  253. offset[0] += random->RandomFloat( -8.0f, 8.0f );
  254. offset[1] += random->RandomFloat( -8.0f, 8.0f );
  255. pParticle->m_flLifetime = 0.0f;
  256. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  257. spread = 1.0f;
  258. pParticle->m_vecVelocity.Init();
  259. colorRamp = random->RandomFloat( 0.5f, 1.25f );
  260. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  261. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  262. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  263. pParticle->m_uchStartSize = random->RandomInt( 4, 8 );
  264. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  265. pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 );
  266. pParticle->m_uchEndAlpha = 0;
  267. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  268. pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f );
  269. }
  270. #else
  271. //
  272. // PC version
  273. //
  274. Vector color;
  275. GetColorForSurface( tr, &color );
  276. if ( !bNoFlecks )
  277. {
  278. CreateFleckParticles( origin, color, tr, materialType, iScale );
  279. }
  280. //
  281. // Dust trail
  282. //
  283. Vector offset = tr->endpos + ( tr->plane.normal * 2.0f );
  284. SimpleParticle newParticle;
  285. int i;
  286. for ( i = 0; i < 2; i++ )
  287. {
  288. newParticle.m_Pos = offset;
  289. newParticle.m_flLifetime = 0.0f;
  290. newParticle.m_flDieTime = 1.0f;
  291. Vector dir;
  292. dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
  293. dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
  294. dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
  295. newParticle.m_uchStartSize = random->RandomInt( 2, 4 ) * iScale;
  296. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8 * iScale;
  297. newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
  298. newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 32.0f )*(i+1);
  299. newParticle.m_uchStartAlpha = random->RandomInt( 100, 200 );
  300. newParticle.m_uchEndAlpha = 0;
  301. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  302. newParticle.m_flRollDelta = random->RandomFloat( -1, 1 );
  303. float colorRamp = random->RandomFloat( 0.5f, 1.25f );
  304. newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  305. newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  306. newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  307. AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
  308. }
  309. for ( i = 0; i < 4; i++ )
  310. {
  311. newParticle.m_Pos = offset;
  312. newParticle.m_flLifetime = 0.0f;
  313. newParticle.m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  314. Vector dir;
  315. dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
  316. dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
  317. dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
  318. newParticle.m_uchStartSize = random->RandomInt( 1, 4 );
  319. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4;
  320. newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 32.0f );
  321. newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 64.0f );
  322. newParticle.m_uchStartAlpha = 255;
  323. newParticle.m_uchEndAlpha = 0;
  324. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  325. newParticle.m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  326. float colorRamp = random->RandomFloat( 0.5f, 1.25f );
  327. newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  328. newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  329. newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  330. AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
  331. }
  332. //
  333. // Bullet hole capper
  334. //
  335. newParticle.m_Pos = offset;
  336. newParticle.m_flLifetime = 0.0f;
  337. newParticle.m_flDieTime = random->RandomFloat( 1.0f, 1.5f );
  338. Vector dir;
  339. dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
  340. dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
  341. dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
  342. newParticle.m_uchStartSize = random->RandomInt( 4, 8 );
  343. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f;
  344. newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f );
  345. newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );
  346. newParticle.m_uchStartAlpha = random->RandomInt( 100, 200 );
  347. newParticle.m_uchEndAlpha = 0;
  348. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  349. newParticle.m_flRollDelta = random->RandomFloat( -2, 2 );
  350. float colorRamp = random->RandomFloat( 0.5f, 1.25f );
  351. newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  352. newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  353. newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  354. AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
  355. #endif
  356. }
  357. #define GLASS_SHARD_MIN_LIFE 2.5f
  358. #define GLASS_SHARD_MAX_LIFE 5.0f
  359. #define GLASS_SHARD_NOISE 0.8
  360. #define GLASS_SHARD_GRAVITY 800
  361. #define GLASS_SHARD_DAMPING 0.3
  362. #define GLASS_SHARD_MIN_SPEED 1
  363. #define GLASS_SHARD_MAX_SPEED 300
  364. //-----------------------------------------------------------------------------
  365. // Purpose:
  366. //-----------------------------------------------------------------------------
  367. void FX_GlassImpact( const Vector &pos, const Vector &normal )
  368. {
  369. VPROF_BUDGET( "FX_GlassImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  370. CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "FX_GlassImpact" );
  371. pGlassEmitter->SetSortOrigin( pos );
  372. Vector vecColor;
  373. engine->ComputeLighting( pos, NULL, true, vecColor );
  374. // HACK: Blend a little toward white to match the materials...
  375. VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor );
  376. float flShardSize = random->RandomFloat( 2.0f, 6.0f );
  377. unsigned char color[3] = { 200, 200, 210 };
  378. // ---------------------
  379. // Create glass shards
  380. // ----------------------
  381. int numShards = random->RandomInt( 2, 4 );
  382. for ( int i = 0; i < numShards; i++ )
  383. {
  384. Particle3D *pParticle;
  385. pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos );
  386. if ( pParticle )
  387. {
  388. pParticle->m_flLifeRemaining = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE);
  389. pParticle->m_vecVelocity[0] = ( normal[0] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
  390. pParticle->m_vecVelocity[1] = ( normal[1] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
  391. pParticle->m_vecVelocity[2] = ( normal[2] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
  392. pParticle->m_uchSize = flShardSize + random->RandomFloat(-0.5*flShardSize,0.5*flShardSize);
  393. pParticle->m_vAngles = RandomAngle( 0, 360 );
  394. pParticle->m_flAngSpeed = random->RandomFloat(-800,800);
  395. pParticle->m_uchFrontColor[0] = (byte)(color[0] * vecColor.x);
  396. pParticle->m_uchFrontColor[1] = (byte)(color[1] * vecColor.y);
  397. pParticle->m_uchFrontColor[2] = (byte)(color[2] * vecColor.z);
  398. pParticle->m_uchBackColor[0] = (byte)(color[0] * vecColor.x);
  399. pParticle->m_uchBackColor[1] = (byte)(color[1] * vecColor.y);
  400. pParticle->m_uchBackColor[2] = (byte)(color[2] * vecColor.z);
  401. }
  402. }
  403. pGlassEmitter->m_ParticleCollision.Setup( pos, &normal, GLASS_SHARD_NOISE, GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING );
  404. color[0] = 64;
  405. color[1] = 64;
  406. color[2] = 92;
  407. // ---------------------------
  408. // Dust
  409. // ---------------------------
  410. Vector dir;
  411. Vector offset = pos + ( normal * 2.0f );
  412. float colorRamp;
  413. SimpleParticle newParticle;
  414. for ( int i = 0; i < 4; i++ )
  415. {
  416. newParticle.m_Pos = offset;
  417. newParticle.m_flLifetime= 0.0f;
  418. newParticle.m_flDieTime = random->RandomFloat( 0.1f, 0.25f );
  419. dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
  420. dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
  421. dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
  422. newParticle.m_uchStartSize = random->RandomInt( 1, 4 );
  423. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8;
  424. newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 16.0f )*(i+1);
  425. newParticle.m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1);
  426. newParticle.m_uchStartAlpha = random->RandomInt( 128, 255 );
  427. newParticle.m_uchEndAlpha = 0;
  428. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  429. newParticle.m_flRollDelta = random->RandomFloat( -1, 1 );
  430. colorRamp = random->RandomFloat( 0.5f, 1.25f );
  431. newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  432. newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  433. newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  434. AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
  435. }
  436. //
  437. // Bullet hole capper
  438. //
  439. newParticle.m_Pos = offset;
  440. newParticle.m_flLifetime = 0.0f;
  441. newParticle.m_flDieTime = random->RandomFloat( 1.0f, 1.5f );
  442. dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
  443. dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
  444. dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
  445. newParticle.m_uchStartSize = random->RandomInt( 4, 8 );
  446. newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f;
  447. newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 8.0f );
  448. newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );
  449. newParticle.m_uchStartAlpha = random->RandomInt( 32, 64 );
  450. newParticle.m_uchEndAlpha = 0;
  451. newParticle.m_flRoll = random->RandomFloat( 0, 360 );
  452. newParticle.m_flRollDelta = random->RandomFloat( -2, 2 );
  453. colorRamp = random->RandomFloat( 0.5f, 1.25f );
  454. newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  455. newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  456. newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  457. AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
  458. }
  459. void GlassImpactCallback( const CEffectData &data )
  460. {
  461. FX_GlassImpact( data.m_vOrigin, data.m_vNormal );
  462. }
  463. DECLARE_CLIENT_EFFECT( "GlassImpact", GlassImpactCallback );
  464. //-----------------------------------------------------------------------------
  465. // Purpose:
  466. // Input : &pos -
  467. // *tr -
  468. //-----------------------------------------------------------------------------
  469. void FX_AntlionImpact( const Vector &pos, trace_t *trace )
  470. {
  471. #if defined( _X360 )
  472. return;
  473. #endif // _X360
  474. VPROF_BUDGET( "FX_AntlionImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  475. CSmartPtr<CSimple3DEmitter> fleckEmitter = CSimple3DEmitter::Create( "FX_DebrisFlecks" );
  476. if ( fleckEmitter == NULL )
  477. return;
  478. Vector shotDir = ( trace->startpos - trace->endpos );
  479. VectorNormalize( shotDir );
  480. Vector spawnOffset = trace->endpos + ( shotDir * 2.0f );
  481. Vector vWorldMins, vWorldMaxs;
  482. if ( trace->m_pEnt )
  483. {
  484. float scale = trace->m_pEnt->CollisionProp()->BoundingRadius();
  485. vWorldMins[0] = spawnOffset[0] - scale;
  486. vWorldMins[1] = spawnOffset[1] - scale;
  487. vWorldMins[2] = spawnOffset[2] - scale;
  488. vWorldMaxs[0] = spawnOffset[0] + scale;
  489. vWorldMaxs[1] = spawnOffset[1] + scale;
  490. vWorldMaxs[2] = spawnOffset[2] + scale;
  491. }
  492. else
  493. {
  494. return;
  495. }
  496. fleckEmitter->SetSortOrigin( spawnOffset );
  497. fleckEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
  498. // Handle increased scale
  499. float flMaxSpeed = 256.0f;
  500. float flAngularSpray = 1.0f;
  501. // Setup our collision information
  502. fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &shotDir, flAngularSpray, 8.0f, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );
  503. Vector dir, end;
  504. Vector color = Vector( 1, 0.9, 0.75 );
  505. float colorRamp;
  506. int numFlecks = random->RandomInt( 8, 16 );
  507. Particle3D *pFleckParticle;
  508. // Dump out flecks
  509. int i;
  510. for ( i = 0; i < numFlecks; i++ )
  511. {
  512. pFleckParticle = (Particle3D *) fleckEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset );
  513. if ( pFleckParticle == NULL )
  514. break;
  515. pFleckParticle->m_flLifeRemaining = 3.0f;
  516. dir[0] = shotDir[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  517. dir[1] = shotDir[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  518. dir[2] = shotDir[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
  519. pFleckParticle->m_uchSize = random->RandomInt( 1, 6 );
  520. pFleckParticle->m_vecVelocity = dir * random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed);
  521. pFleckParticle->m_vAngles.Random( 0, 360 );
  522. pFleckParticle->m_flAngSpeed = random->RandomFloat(-800,800);
  523. pFleckParticle->m_uchFrontColor[0] = 255;
  524. pFleckParticle->m_uchFrontColor[1] = 255;
  525. pFleckParticle->m_uchFrontColor[2] = 255;
  526. pFleckParticle->m_uchBackColor[0] = 128;
  527. pFleckParticle->m_uchBackColor[1] = 128;
  528. pFleckParticle->m_uchBackColor[2] = 128;
  529. }
  530. //
  531. // Dust trail
  532. //
  533. SimpleParticle *pParticle;
  534. CSmartPtr<CSimpleEmitter> dustEmitter = CSimpleEmitter::Create( "FX_DebrisFlecks" );
  535. if ( !dustEmitter )
  536. return;
  537. Vector offset = trace->endpos + ( shotDir * 4.0f );
  538. dustEmitter->SetSortOrigin( offset );
  539. dustEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
  540. for ( i = 0; i < 4; i++ )
  541. {
  542. pParticle = (SimpleParticle *) dustEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], offset );
  543. if ( pParticle == NULL )
  544. break;
  545. pParticle->m_flLifetime = 0.0f;
  546. pParticle->m_flDieTime = 1.0f;
  547. dir[0] = shotDir[0] + random->RandomFloat( -0.8f, 0.8f );
  548. dir[1] = shotDir[1] + random->RandomFloat( -0.8f, 0.8f );
  549. dir[2] = shotDir[2] + random->RandomFloat( -0.8f, 0.8f );
  550. pParticle->m_uchStartSize = random->RandomInt( 8, 16 );
  551. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4.0f;
  552. pParticle->m_vecVelocity = dir * random->RandomFloat( 4.0f, 64.0f );
  553. pParticle->m_uchStartAlpha = random->RandomInt( 32, 64);
  554. pParticle->m_uchEndAlpha = 0;
  555. pParticle->m_flRoll = random->RandomFloat( 0, 2.0f*M_PI );
  556. pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
  557. colorRamp = random->RandomFloat( 0.5f, 1.0f );
  558. pParticle->m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
  559. pParticle->m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
  560. pParticle->m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
  561. }
  562. CLocalPlayerFilter filter;
  563. C_BaseEntity::EmitSound( filter, 0, "FX_AntlionImpact.ShellImpact", &trace->endpos );
  564. }
  565. //-----------------------------------------------------------------------------
  566. // Purpose: Spurt out bug blood
  567. // Input : &pos -
  568. // &dir -
  569. //-----------------------------------------------------------------------------
  570. #if defined( _XBOX )
  571. #define NUM_BUG_BLOOD 16
  572. #define NUM_BUG_BLOOD2 8
  573. #define NUM_BUG_SPLATS 8
  574. #else
  575. #define NUM_BUG_BLOOD 32
  576. #define NUM_BUG_BLOOD2 16
  577. #define NUM_BUG_SPLATS 16
  578. #endif
  579. void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMaxs )
  580. {
  581. VPROF_BUDGET( "FX_BugBlood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  582. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_BugBlood" );
  583. if ( !pSimple )
  584. return;
  585. pSimple->SetSortOrigin( pos );
  586. pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true );
  587. pSimple->GetBinding().SetBBox( pos-Vector(32,32,32), pos+Vector(32,32,32), true );
  588. Vector vDir;
  589. vDir[0] = dir[0] + random->RandomFloat( -2.0f, 2.0f );
  590. vDir[1] = dir[1] + random->RandomFloat( -2.0f, 2.0f );
  591. vDir[2] = dir[2] + random->RandomFloat( -2.0f, 2.0f );
  592. VectorNormalize( vDir );
  593. int i;
  594. for ( i = 0; i < NUM_BUG_BLOOD; i++ )
  595. {
  596. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
  597. if ( sParticle == NULL )
  598. return;
  599. sParticle->m_flLifetime = 0.0f;
  600. sParticle->m_flDieTime = 0.25f;
  601. float speed = random->RandomFloat( 32.0f, 150.0f );
  602. sParticle->m_vecVelocity = vDir * -speed;
  603. sParticle->m_vecVelocity[2] -= 32.0f;
  604. sParticle->m_uchColor[0] = 255;
  605. sParticle->m_uchColor[1] = 200;
  606. sParticle->m_uchColor[2] = 32;
  607. sParticle->m_uchStartAlpha = 255;
  608. sParticle->m_uchEndAlpha = 0;
  609. sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
  610. sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
  611. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  612. sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  613. }
  614. for ( i = 0; i < NUM_BUG_BLOOD2; i++ )
  615. {
  616. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
  617. if ( sParticle == NULL )
  618. {
  619. return;
  620. }
  621. sParticle->m_flLifetime = 0.0f;
  622. sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  623. float speed = random->RandomFloat( 8.0f, 255.0f );
  624. sParticle->m_vecVelocity = vDir * -speed;
  625. sParticle->m_vecVelocity[2] -= 16.0f;
  626. sParticle->m_uchColor[0] = 255;
  627. sParticle->m_uchColor[1] = 200;
  628. sParticle->m_uchColor[2] = 32;
  629. sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 );
  630. sParticle->m_uchEndAlpha = 0;
  631. sParticle->m_uchStartSize = random->RandomInt( 1, 3 );
  632. sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
  633. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  634. sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  635. }
  636. Vector offset;
  637. for ( i = 0; i < NUM_BUG_SPLATS; i++ )
  638. {
  639. offset.Random( -2, 2 );
  640. offset += pos;
  641. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], offset );
  642. if ( sParticle == NULL )
  643. {
  644. return;
  645. }
  646. sParticle->m_flLifetime = 0.0f;
  647. sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  648. float speed = 75.0f * ((i/(float)NUM_BUG_SPLATS)+1);
  649. sParticle->m_vecVelocity.Random( -16.0f, 16.0f );
  650. sParticle->m_vecVelocity += vDir * -speed;
  651. sParticle->m_vecVelocity[2] -= ( 64.0f * ((i/(float)NUM_BUG_SPLATS)+1) );
  652. sParticle->m_uchColor[0] = 255;
  653. sParticle->m_uchColor[1] = 200;
  654. sParticle->m_uchColor[2] = 32;
  655. sParticle->m_uchStartAlpha = 255;
  656. sParticle->m_uchEndAlpha = 0;
  657. sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
  658. sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
  659. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  660. sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  661. }
  662. }
  663. //-----------------------------------------------------------------------------
  664. // Purpose: Blood puff
  665. //-----------------------------------------------------------------------------
  666. void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a )
  667. {
  668. VPROF_BUDGET( "FX_Blood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  669. // Cloud
  670. CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Blood" );
  671. if ( !pSimple )
  672. return;
  673. pSimple->SetSortOrigin( pos );
  674. Vector vDir;
  675. vDir[0] = dir[0] + random->RandomFloat( -1.0f, 1.0f );
  676. vDir[1] = dir[1] + random->RandomFloat( -1.0f, 1.0f );
  677. vDir[2] = dir[2] + random->RandomFloat( -1.0f, 1.0f );
  678. VectorNormalize( vDir );
  679. int i;
  680. for ( i = 0; i < 2; i++ )
  681. {
  682. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
  683. if ( sParticle == NULL )
  684. {
  685. return;
  686. }
  687. sParticle->m_flLifetime = 0.0f;
  688. sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  689. float speed = random->RandomFloat( 2.0f, 8.0f );
  690. sParticle->m_vecVelocity = vDir * (speed*i);
  691. sParticle->m_vecVelocity[2] += random->RandomFloat( -32.0f, -16.0f );
  692. sParticle->m_uchColor[0] = r;
  693. sParticle->m_uchColor[1] = g;
  694. sParticle->m_uchColor[2] = b;
  695. sParticle->m_uchStartAlpha = a;
  696. sParticle->m_uchEndAlpha = 0;
  697. sParticle->m_uchStartSize = 2;
  698. sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
  699. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  700. sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  701. }
  702. for ( i = 0; i < 2; i++ )
  703. {
  704. SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
  705. if ( sParticle == NULL )
  706. {
  707. return;
  708. }
  709. sParticle->m_flLifetime = 0.0f;
  710. sParticle->m_flDieTime = 0.5f;
  711. float speed = random->RandomFloat( 4.0f, 16.0f );
  712. sParticle->m_vecVelocity = vDir * (speed*i);
  713. sParticle->m_uchColor[0] = r;
  714. sParticle->m_uchColor[1] = g;
  715. sParticle->m_uchColor[2] = b;
  716. sParticle->m_uchStartAlpha = 128;
  717. sParticle->m_uchEndAlpha = 0;
  718. sParticle->m_uchStartSize = 2;
  719. sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
  720. sParticle->m_flRoll = random->RandomInt( 0, 360 );
  721. sParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
  722. }
  723. }
  724. //-----------------------------------------------------------------------------
  725. // Purpose: Dust impact
  726. // Input : &origin - position
  727. // &tr - trace information
  728. //-----------------------------------------------------------------------------
  729. void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale )
  730. {
  731. if ( !fx_drawimpactdust.GetBool() )
  732. return;
  733. #ifdef _XBOX
  734. //
  735. // XBox version
  736. //
  737. VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  738. Vector offset;
  739. float spread = 0.2f;
  740. CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
  741. pSimple->SetSortOrigin( origin );
  742. pSimple->GetBinding().SetBBox( origin - ( Vector( 32, 32, 32 ) * iScale ), origin + ( Vector( 32, 32, 32 ) * iScale ) );
  743. Vector color;
  744. float colorRamp;
  745. GetColorForSurface( tr, &color );
  746. int i;
  747. SimpleParticle *pParticle;
  748. for ( i = 0; i < 4; i++ )
  749. {
  750. // Last puff is gritty (hides end)
  751. if ( i == 3 )
  752. {
  753. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
  754. }
  755. else
  756. {
  757. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
  758. }
  759. if ( pParticle != NULL )
  760. {
  761. pParticle->m_flLifetime = 0.0f;
  762. pParticle->m_vecVelocity.Random( -spread, spread );
  763. pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
  764. VectorNormalize( pParticle->m_vecVelocity );
  765. float fForce = random->RandomFloat( 250, 500 ) * i;
  766. // scaled
  767. pParticle->m_vecVelocity *= fForce * iScale;
  768. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  769. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  770. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  771. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  772. // scaled
  773. pParticle->m_uchStartSize = iScale * random->RandomInt( 3, 4 ) * (i+1);
  774. // scaled
  775. pParticle->m_uchEndSize = iScale * pParticle->m_uchStartSize * 4;
  776. pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 );
  777. pParticle->m_uchEndAlpha = 0;
  778. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  779. if ( i == 3 )
  780. {
  781. pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f );
  782. pParticle->m_flDieTime = 0.5f;
  783. }
  784. else
  785. {
  786. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  787. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  788. }
  789. }
  790. }
  791. //Impact hit
  792. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_DustPuff, origin );
  793. if ( pParticle != NULL )
  794. {
  795. offset = origin;
  796. offset[0] += random->RandomFloat( -8.0f, 8.0f );
  797. offset[1] += random->RandomFloat( -8.0f, 8.0f );
  798. pParticle->m_flLifetime = 0.0f;
  799. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  800. pParticle->m_vecVelocity.Init();
  801. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  802. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  803. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  804. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  805. pParticle->m_uchStartSize = random->RandomInt( 4, 8 );
  806. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  807. pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
  808. pParticle->m_uchEndAlpha = 0;
  809. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  810. pParticle->m_flRollDelta = random->RandomFloat( -1.0f, 1.0f );
  811. }
  812. #else
  813. FX_DustImpact( origin, tr, (float)iScale );
  814. #endif // _XBOX
  815. }
  816. void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale )
  817. {
  818. //
  819. // PC version
  820. //
  821. VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
  822. Vector offset;
  823. float spread = 0.2f;
  824. CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
  825. pSimple->SetSortOrigin( origin );
  826. // Three types of particle, ideally we want 4 of each.
  827. float fNumParticles = 4.0f * g_pParticleSystemMgr->ParticleThrottleScaling();
  828. int nParticles1 = (int)( 0.50f + fNumParticles );
  829. int nParticles2 = (int)( 0.83f + fNumParticles ); // <-- most visible particle type.
  830. int nParticles3 = (int)( 0.17f + fNumParticles );
  831. SimpleParticle *pParticle;
  832. Vector color;
  833. float colorRamp;
  834. GetColorForSurface( tr, &color );
  835. // To get a decent spread even when scaling down the number of particles...
  836. const static int nParticleIdArray[4] = {3,1,2,0};
  837. int i;
  838. for ( i = 0; i < nParticles1; i++ )
  839. {
  840. int nId = nParticleIdArray[i];
  841. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
  842. if ( pParticle != NULL )
  843. {
  844. pParticle->m_flLifetime = 0.0f;
  845. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  846. pParticle->m_vecVelocity.Random( -spread, spread );
  847. pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
  848. VectorNormalize( pParticle->m_vecVelocity );
  849. float fForce = random->RandomFloat( 250, 500 ) * nId;
  850. // scaled
  851. pParticle->m_vecVelocity *= fForce * flScale;
  852. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  853. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  854. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  855. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  856. // scaled
  857. pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (nId+1) );
  858. // scaled
  859. pParticle->m_uchEndSize = ( unsigned char )( flScale * pParticle->m_uchStartSize * 4 );
  860. pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 );
  861. pParticle->m_uchEndAlpha = 0;
  862. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  863. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  864. }
  865. }
  866. //Dust specs
  867. for ( i = 0; i < nParticles2; i++ )
  868. {
  869. int nId = nParticleIdArray[i];
  870. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
  871. if ( pParticle != NULL )
  872. {
  873. pParticle->m_flLifetime = 0.0f;
  874. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.75f );
  875. pParticle->m_vecVelocity.Random( -spread, spread );
  876. pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
  877. VectorNormalize( pParticle->m_vecVelocity );
  878. float fForce = random->RandomFloat( 250, 500 ) * nId;
  879. pParticle->m_vecVelocity *= fForce;
  880. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  881. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  882. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  883. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  884. pParticle->m_uchStartSize = random->RandomInt( 2, 4 ) * (nId+1);
  885. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
  886. pParticle->m_uchStartAlpha = 255;
  887. pParticle->m_uchEndAlpha = 0;
  888. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  889. pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  890. }
  891. }
  892. //Impact hit
  893. for ( i = 0; i < nParticles3; i++ )
  894. {
  895. //int nId = nParticleIdArray[i];
  896. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
  897. if ( pParticle != NULL )
  898. {
  899. offset = origin;
  900. offset[0] += random->RandomFloat( -8.0f, 8.0f );
  901. offset[1] += random->RandomFloat( -8.0f, 8.0f );
  902. pParticle->m_flLifetime = 0.0f;
  903. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  904. spread = 1.0f;
  905. pParticle->m_vecVelocity.Random( -spread, spread );
  906. pParticle->m_vecVelocity += tr->plane.normal;
  907. VectorNormalize( pParticle->m_vecVelocity );
  908. float fForce = random->RandomFloat( 0, 50 );
  909. pParticle->m_vecVelocity *= fForce;
  910. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  911. pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
  912. pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
  913. pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
  914. pParticle->m_uchStartSize = random->RandomInt( 1, 4 );
  915. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  916. pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
  917. pParticle->m_uchEndAlpha = 0;
  918. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  919. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  920. }
  921. }
  922. }
  923. #ifdef _XBOX
  924. extern PMaterialHandle g_Material_Spark;
  925. #endif // _XBOX
  926. //-----------------------------------------------------------------------------
  927. // Purpose:
  928. // Input : &pos -
  929. // &dir -
  930. // type -
  931. //-----------------------------------------------------------------------------
  932. void FX_GaussExplosion( const Vector &pos, const Vector &dir, int type )
  933. {
  934. Vector vDir;
  935. vDir[0] = dir[0] + random->RandomFloat( -1.0f, 1.0f );
  936. vDir[1] = dir[1] + random->RandomFloat( -1.0f, 1.0f );
  937. vDir[2] = dir[2] + random->RandomFloat( -1.0f, 1.0f );
  938. VectorNormalize( vDir );
  939. int i;
  940. #if defined(_XBOX) || defined(_X360)
  941. //
  942. // XBox version
  943. //
  944. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_GaussExplosion" );
  945. if ( pSparkEmitter == NULL )
  946. {
  947. Assert(0);
  948. return;
  949. }
  950. if ( g_Material_Spark == NULL )
  951. {
  952. g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
  953. }
  954. pSparkEmitter->SetSortOrigin( pos );
  955. pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
  956. pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  957. pSparkEmitter->GetBinding().SetBBox( pos - Vector( 32, 32, 32 ), pos + Vector( 32, 32, 32 ) );
  958. int numSparks = random->RandomInt( 8, 16 );
  959. TrailParticle *pParticle;
  960. // Dump out sparks
  961. for ( i = 0; i < numSparks; i++ )
  962. {
  963. pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );
  964. if ( pParticle == NULL )
  965. return;
  966. pParticle->m_flLifetime = 0.0f;
  967. vDir.Random( -0.6f, 0.6f );
  968. vDir += dir;
  969. VectorNormalize( vDir );
  970. pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f );
  971. pParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
  972. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
  973. pParticle->m_vecVelocity = vDir * random->RandomFloat( 128, 512 );
  974. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  975. }
  976. // End cap
  977. SimpleParticle particle;
  978. particle.m_Pos = pos;
  979. particle.m_flLifetime = 0.0f;
  980. particle.m_flDieTime = 0.1f;
  981. particle.m_vecVelocity.Init();
  982. particle.m_flRoll = random->RandomInt( 0, 360 );
  983. particle.m_flRollDelta = 0.0f;
  984. particle.m_uchColor[0] = 255;
  985. particle.m_uchColor[1] = 255;
  986. particle.m_uchColor[2] = 255;
  987. particle.m_uchStartAlpha = 255;
  988. particle.m_uchEndAlpha = 255;
  989. particle.m_uchStartSize = random->RandomInt( 24, 32 );
  990. particle.m_uchEndSize = 0;
  991. AddSimpleParticle( &particle, ParticleMgr()->GetPMaterial( "effects/yellowflare" ) );
  992. #else
  993. //
  994. // PC version
  995. //
  996. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_ElectricSpark" );
  997. if ( !pSparkEmitter )
  998. {
  999. Assert(0);
  1000. return;
  1001. }
  1002. PMaterialHandle hMaterial = pSparkEmitter->GetPMaterial( "effects/spark" );
  1003. pSparkEmitter->SetSortOrigin( pos );
  1004. pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
  1005. pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN|bitsPARTICLE_TRAIL_COLLIDE );
  1006. //Setup our collision information
  1007. pSparkEmitter->m_ParticleCollision.Setup( pos, &vDir, 0.8f, 128, 512, 800, 0.3f );
  1008. int numSparks = random->RandomInt( 16, 32 );
  1009. TrailParticle *pParticle;
  1010. // Dump out sparks
  1011. for ( i = 0; i < numSparks; i++ )
  1012. {
  1013. pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, pos );
  1014. if ( pParticle == NULL )
  1015. return;
  1016. pParticle->m_flLifetime = 0.0f;
  1017. vDir.Random( -0.6f, 0.6f );
  1018. vDir += dir;
  1019. VectorNormalize( vDir );
  1020. pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f );
  1021. pParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
  1022. pParticle->m_flDieTime = random->RandomFloat( 0.25f, 1.0f );
  1023. pParticle->m_vecVelocity = vDir * random->RandomFloat( 128, 512 );
  1024. Color32Init( pParticle->m_color, 255, 255, 255, 255 );
  1025. }
  1026. FX_ElectricSpark( pos, 1, 1, &vDir );
  1027. #endif
  1028. }
  1029. class C_TEGaussExplosion : public C_TEParticleSystem
  1030. {
  1031. public:
  1032. DECLARE_CLASS( C_TEGaussExplosion, C_TEParticleSystem );
  1033. DECLARE_CLIENTCLASS();
  1034. C_TEGaussExplosion();
  1035. virtual ~C_TEGaussExplosion();
  1036. public:
  1037. virtual void PostDataUpdate( DataUpdateType_t updateType );
  1038. virtual bool ShouldDraw() { return true; }
  1039. public:
  1040. int m_nType;
  1041. Vector m_vecDirection;
  1042. };
  1043. IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEGaussExplosion, DT_TEGaussExplosion, CTEGaussExplosion )
  1044. RecvPropInt(RECVINFO(m_nType)),
  1045. RecvPropVector(RECVINFO(m_vecDirection)),
  1046. END_RECV_TABLE()
  1047. //==================================================
  1048. // C_TEGaussExplosion
  1049. //==================================================
  1050. C_TEGaussExplosion::C_TEGaussExplosion()
  1051. {
  1052. }
  1053. C_TEGaussExplosion::~C_TEGaussExplosion()
  1054. {
  1055. }
  1056. //-----------------------------------------------------------------------------
  1057. // Purpose:
  1058. // Input : bNewEntity - whether or not to start a new entity
  1059. //-----------------------------------------------------------------------------
  1060. void C_TEGaussExplosion::PostDataUpdate( DataUpdateType_t updateType )
  1061. {
  1062. FX_GaussExplosion( m_vecOrigin, m_vecDirection, m_nType );
  1063. }
  1064. //-----------------------------------------------------------------------------
  1065. // Purpose:
  1066. // Input : filter -
  1067. // delay -
  1068. // &pos -
  1069. // &dir -
  1070. // type -
  1071. //-----------------------------------------------------------------------------
  1072. void TE_GaussExplosion( IRecipientFilter& filter, float delay, const Vector &pos, const Vector &dir, int type )
  1073. {
  1074. FX_GaussExplosion( pos, dir, type );
  1075. }