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.

1428 lines
40 KiB

  1. //========= Copyright � 1996-2005, Valve Corporation, All rights reserved. ============//
  2. //
  3. // Purpose: Base explosion effect
  4. //
  5. // $NoKeywords: $
  6. //=============================================================================//
  7. #include "cbase.h"
  8. #include "fx_explosion.h"
  9. #include "precache_register.h"
  10. #include "fx_sparks.h"
  11. #include "dlight.h"
  12. #include "tempentity.h"
  13. #include "iefx.h"
  14. #include "engine/IEngineSound.h"
  15. #include "engine/ivdebugoverlay.h"
  16. #include "c_te_effect_dispatch.h"
  17. #include "fx.h"
  18. #include "fx_quad.h"
  19. #include "fx_line.h"
  20. #include "fx_water.h"
  21. // memdbgon must be the last include file in a .cpp file!!!
  22. #include "tier0/memdbgon.h"
  23. #define __EXPLOSION_DEBUG 0
  24. PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectExplosion )
  25. #ifndef DOTA_DLL
  26. PRECACHE( MATERIAL, "effects/fire_cloud1" )
  27. PRECACHE( MATERIAL, "effects/fire_cloud2" )
  28. PRECACHE( MATERIAL, "effects/fire_embers1" )
  29. PRECACHE( MATERIAL, "effects/fire_embers2" )
  30. PRECACHE( MATERIAL, "effects/fire_embers3" )
  31. PRECACHE( MATERIAL, "effects/splash3" )
  32. PRECACHE( MATERIAL, "effects/splashwake1" )
  33. PRECACHE( MATERIAL, "particle/particle_smokegrenade" )
  34. PRECACHE( MATERIAL, "particle/particle_smokegrenade1" )
  35. #endif
  36. PRECACHE_REGISTER_END()
  37. //
  38. // CExplosionParticle
  39. //
  40. class CExplosionParticle : public CSimpleEmitter
  41. {
  42. public:
  43. CExplosionParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  44. //Create
  45. static CExplosionParticle *Create( const char *pDebugName )
  46. {
  47. return new CExplosionParticle( pDebugName );
  48. }
  49. //Roll
  50. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  51. {
  52. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  53. pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
  54. //Cap the minimum roll
  55. if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
  56. {
  57. pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
  58. }
  59. return pParticle->m_flRoll;
  60. }
  61. //Velocity
  62. virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
  63. {
  64. Vector saveVelocity = pParticle->m_vecVelocity;
  65. //Decellerate
  66. //pParticle->m_vecVelocity += pParticle->m_vecVelocity * ( timeDelta * -20.0f );
  67. static float dtime;
  68. static float decay;
  69. if ( dtime != timeDelta )
  70. {
  71. dtime = timeDelta;
  72. float expected = 0.5;
  73. decay = exp( log( 0.0001f ) * dtime / expected );
  74. }
  75. pParticle->m_vecVelocity = pParticle->m_vecVelocity * decay;
  76. //Cap the minimum speed
  77. if ( pParticle->m_vecVelocity.LengthSqr() < (32.0f*32.0f) )
  78. {
  79. VectorNormalize( saveVelocity );
  80. pParticle->m_vecVelocity = saveVelocity * 32.0f;
  81. }
  82. }
  83. //Alpha
  84. virtual float UpdateAlpha( const SimpleParticle *pParticle )
  85. {
  86. float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
  87. float ramp = 1.0f - tLifetime;
  88. return Bias( ramp, 0.25f );
  89. }
  90. //Color
  91. virtual Vector UpdateColor( const SimpleParticle *pParticle )
  92. {
  93. Vector color;
  94. float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
  95. float ramp = Bias( 1.0f - tLifetime, 0.25f );
  96. color[0] = ( (float) pParticle->m_uchColor[0] * ramp ) / 255.0f;
  97. color[1] = ( (float) pParticle->m_uchColor[1] * ramp ) / 255.0f;
  98. color[2] = ( (float) pParticle->m_uchColor[2] * ramp ) / 255.0f;
  99. return color;
  100. }
  101. private:
  102. CExplosionParticle( const CExplosionParticle & );
  103. };
  104. //Singleton static member definition
  105. C_BaseExplosionEffect C_BaseExplosionEffect::m_instance;
  106. C_BaseExplosionEffect::C_BaseExplosionEffect( void ) : m_Material_Smoke( NULL ), m_Material_FireCloud( NULL )
  107. {
  108. m_Material_Embers[0] = NULL;
  109. m_Material_Embers[1] = NULL;
  110. }
  111. //Singleton accessor
  112. C_BaseExplosionEffect &BaseExplosionEffect( void )
  113. {
  114. return C_BaseExplosionEffect::Instance();
  115. }
  116. //-----------------------------------------------------------------------------
  117. // Purpose:
  118. // Input : &deviant -
  119. // &source -
  120. // Output : float
  121. //-----------------------------------------------------------------------------
  122. float C_BaseExplosionEffect::ScaleForceByDeviation( Vector &deviant, Vector &source, float spread, float *force )
  123. {
  124. if ( ( deviant == vec3_origin ) || ( source == vec3_origin ) )
  125. return 1.0f;
  126. float dot = source.Dot( deviant );
  127. dot = spread * fabs( dot );
  128. if ( force != NULL )
  129. {
  130. (*force) *= dot;
  131. }
  132. return dot;
  133. }
  134. //-----------------------------------------------------------------------------
  135. // Purpose:
  136. // Input : position -
  137. // force -
  138. // Output : virtual void
  139. //-----------------------------------------------------------------------------
  140. void C_BaseExplosionEffect::Create( const Vector &position, float force, float scale, int flags )
  141. {
  142. m_vecOrigin = position;
  143. m_fFlags = flags;
  144. //if explosion is an ice explosion skip all the other stuff and draw a particle system
  145. if ( m_fFlags & TE_EXPLFLAG_ICE )
  146. {
  147. QAngle vecAngles;
  148. //DispatchParticleEffect( "freeze_explosion", m_vecOrigin , vecAngles );
  149. PlaySound();
  150. return;
  151. }
  152. if ( m_fFlags & TE_EXPLFLAG_SCALEPARTICLES )
  153. {
  154. m_flScale = scale;
  155. }
  156. else
  157. {
  158. m_flScale = 1.0f;
  159. }
  160. //Find the force of the explosion
  161. GetForceDirection( m_vecOrigin, force, &m_vecDirection, &m_flForce );
  162. #if __EXPLOSION_DEBUG
  163. debugoverlay->AddBoxOverlay( m_vecOrigin, -Vector(32,32,32), Vector(32,32,32), vec3_angle, 255, 0, 0, 64, 5.0f );
  164. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin+(m_vecDirection*force*m_flForce), 0, 0, 255, false, 3 );
  165. #endif
  166. PlaySound();
  167. if ( scale != 0 )
  168. {
  169. // UNDONE: Make core size parametric to scale or remove scale?
  170. CreateCore();
  171. }
  172. CreateDebris();
  173. CreateDynamicLight();
  174. CreateMisc();
  175. }
  176. //-----------------------------------------------------------------------------
  177. // Purpose:
  178. //-----------------------------------------------------------------------------
  179. void C_BaseExplosionEffect::CreateCore( void )
  180. {
  181. if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
  182. return;
  183. if ( m_fFlags & TE_EXPLFLAG_ICE )
  184. return;
  185. Vector offset;
  186. int i;
  187. //Spread constricts as force rises
  188. float force = m_flForce;
  189. //Cap our force
  190. if ( force < EXPLOSION_FORCE_MIN )
  191. force = EXPLOSION_FORCE_MIN;
  192. if ( force > EXPLOSION_FORCE_MAX )
  193. force = EXPLOSION_FORCE_MAX;
  194. float spread = 1.0f - (0.15f*force);
  195. SimpleParticle *pParticle;
  196. CSmartPtr<CExplosionParticle> pSimple = CExplosionParticle::Create( "exp_smoke" );
  197. pSimple->SetSortOrigin( m_vecOrigin );
  198. pSimple->SetNearClip( 64, 128 );
  199. pSimple->GetBinding().SetBBox( m_vecOrigin - Vector( 128, 128, 128 ), m_vecOrigin + Vector( 128, 128, 128 ) );
  200. if ( m_Material_Smoke == NULL )
  201. {
  202. m_Material_Smoke = g_Mat_DustPuff[1];
  203. }
  204. //FIXME: Better sampling area
  205. offset = m_vecOrigin + ( m_vecDirection * 32.0f );
  206. //Find area ambient light color and use it to tint smoke
  207. Vector worldLight = WorldGetLightForPoint( offset, true );
  208. Vector tint;
  209. float luminosity;
  210. if ( worldLight == vec3_origin )
  211. {
  212. tint = vec3_origin;
  213. luminosity = 0.0f;
  214. }
  215. else
  216. {
  217. UTIL_GetNormalizedColorTintAndLuminosity( worldLight, &tint, &luminosity );
  218. }
  219. // We only take a portion of the tint
  220. tint = (tint * 0.25f)+(Vector(0.75f,0.75f,0.75f));
  221. // Rescale to a character range
  222. luminosity *= 255;
  223. if ( (m_fFlags & TE_EXPLFLAG_NOFIREBALLSMOKE) == 0 )
  224. {
  225. //
  226. // Smoke - basic internal filler
  227. //
  228. for ( i = 0; i < 4; i++ )
  229. {
  230. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, m_vecOrigin );
  231. if ( pParticle != NULL )
  232. {
  233. pParticle->m_flLifetime = 0.0f;
  234. #ifdef INVASION_CLIENT_DLL
  235. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  236. #endif
  237. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
  238. pParticle->m_vecVelocity.Random( -spread, spread );
  239. pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
  240. VectorNormalize( pParticle->m_vecVelocity );
  241. float fForce = random->RandomFloat( 1, 750 ) * force;
  242. //Scale the force down as we fall away from our main direction
  243. ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
  244. pParticle->m_vecVelocity *= fForce;
  245. pParticle->m_vecVelocity *= m_flScale;
  246. #if __EXPLOSION_DEBUG
  247. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  248. #endif
  249. int nColor = random->RandomInt( luminosity*0.5f, luminosity );
  250. pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
  251. pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
  252. pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
  253. pParticle->m_uchStartSize = 72 * m_flScale;
  254. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
  255. pParticle->m_uchStartAlpha = 255;
  256. pParticle->m_uchEndAlpha = 0;
  257. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  258. pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
  259. }
  260. }
  261. //
  262. // Inner core
  263. //
  264. for ( i = 0; i < 8; i++ )
  265. {
  266. offset.Random( -16.0f, 16.0f );
  267. offset *= m_flScale;
  268. offset += m_vecOrigin;
  269. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, offset );
  270. if ( pParticle != NULL )
  271. {
  272. pParticle->m_flLifetime = 0.0f;
  273. #ifdef INVASION_CLIENT_DLL
  274. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  275. #else
  276. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  277. #endif
  278. pParticle->m_vecVelocity.Random( -spread, spread );
  279. pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
  280. VectorNormalize( pParticle->m_vecVelocity );
  281. float fForce = random->RandomFloat( 1, 2000 ) * force;
  282. //Scale the force down as we fall away from our main direction
  283. ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
  284. pParticle->m_vecVelocity *= fForce;
  285. pParticle->m_vecVelocity *= m_flScale;
  286. #if __EXPLOSION_DEBUG
  287. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  288. #endif
  289. int nColor = random->RandomInt( luminosity*0.5f, luminosity );
  290. pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
  291. pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
  292. pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
  293. pParticle->m_uchStartSize = random->RandomInt( 32, 64 ) * m_flScale;
  294. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
  295. pParticle->m_uchStartAlpha = random->RandomFloat( 128, 255 );
  296. pParticle->m_uchEndAlpha = 0;
  297. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  298. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  299. }
  300. }
  301. //
  302. // Ground ring
  303. //
  304. Vector vRight, vUp;
  305. VectorVectors( m_vecDirection, vRight, vUp );
  306. Vector forward;
  307. #ifndef INVASION_CLIENT_DLL
  308. int numRingSprites = 32;
  309. float flIncr = (2*M_PI) / (float) numRingSprites; // Radians
  310. float flYaw = 0.0f;
  311. for ( i = 0; i < numRingSprites; i++ )
  312. {
  313. flYaw += flIncr;
  314. SinCos( flYaw, &forward.y, &forward.x );
  315. forward.z = 0.0f;
  316. offset = ( ( RandomVector( -4.0f, 4.0f ) * m_flScale ) + m_vecOrigin ) + ( m_flScale * forward * random->RandomFloat( 8.0f, 16.0f ) );
  317. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, offset );
  318. if ( pParticle != NULL )
  319. {
  320. pParticle->m_flLifetime = 0.0f;
  321. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.5f );
  322. pParticle->m_vecVelocity = forward;
  323. float fForce = random->RandomFloat( 500, 2000 ) * force;
  324. //Scale the force down as we fall away from our main direction
  325. ScaleForceByDeviation( pParticle->m_vecVelocity, pParticle->m_vecVelocity, spread, &fForce );
  326. pParticle->m_vecVelocity *= fForce;
  327. pParticle->m_vecVelocity *= m_flScale;
  328. #if __EXPLOSION_DEBUG
  329. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  330. #endif
  331. int nColor = random->RandomInt( luminosity*0.5f, luminosity );
  332. pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
  333. pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
  334. pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
  335. pParticle->m_uchStartSize = random->RandomInt( 16, 32 ) * m_flScale;
  336. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
  337. pParticle->m_uchStartAlpha = random->RandomFloat( 16, 32 );
  338. pParticle->m_uchEndAlpha = 0;
  339. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  340. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  341. }
  342. }
  343. #endif
  344. }
  345. //
  346. // Embers
  347. //
  348. if ( m_Material_Embers[0] == NULL )
  349. {
  350. m_Material_Embers[0] = pSimple->GetPMaterial( "effects/fire_embers1" );
  351. }
  352. if ( m_Material_Embers[1] == NULL )
  353. {
  354. m_Material_Embers[1] = pSimple->GetPMaterial( "effects/fire_embers2" );
  355. }
  356. for ( i = 0; i < 16; i++ )
  357. {
  358. offset.Random( -32.0f, 32.0f );
  359. offset *= m_flScale;
  360. offset += m_vecOrigin;
  361. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Embers[random->RandomInt(0,1)], offset );
  362. if ( pParticle != NULL )
  363. {
  364. pParticle->m_flLifetime = 0.0f;
  365. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
  366. pParticle->m_vecVelocity.Random( -spread*2, spread*2 );
  367. pParticle->m_vecVelocity += m_vecDirection;
  368. VectorNormalize( pParticle->m_vecVelocity );
  369. float fForce = random->RandomFloat( 1.0f, 400.0f );
  370. //Scale the force down as we fall away from our main direction
  371. float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
  372. pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
  373. pParticle->m_vecVelocity *= m_flScale;
  374. #if __EXPLOSION_DEBUG
  375. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  376. #endif
  377. int nColor = random->RandomInt( 192, 255 );
  378. pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
  379. pParticle->m_uchStartSize = random->RandomInt( 8, 16 ) * vDev;
  380. pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, 4, 32 ) * m_flScale;
  381. pParticle->m_uchEndSize = pParticle->m_uchStartSize;
  382. pParticle->m_uchStartAlpha = 255;
  383. pParticle->m_uchEndAlpha = 0;
  384. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  385. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  386. }
  387. }
  388. //
  389. // Fireballs
  390. //
  391. if ( m_Material_FireCloud == NULL )
  392. {
  393. m_Material_FireCloud = pSimple->GetPMaterial( "effects/fire_cloud2" );
  394. }
  395. int numFireballs = 32;
  396. for ( i = 0; i < numFireballs; i++ )
  397. {
  398. offset.Random( -48.0f, 48.0f );
  399. offset *= m_flScale;
  400. offset += m_vecOrigin;
  401. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_FireCloud, offset );
  402. if ( pParticle != NULL )
  403. {
  404. pParticle->m_flLifetime = 0.0f;
  405. pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
  406. pParticle->m_vecVelocity.Random( -spread*0.75f, spread*0.75f );
  407. pParticle->m_vecVelocity += m_vecDirection;
  408. VectorNormalize( pParticle->m_vecVelocity );
  409. float fForce = random->RandomFloat( 400.0f, 800.0f );
  410. //Scale the force down as we fall away from our main direction
  411. float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
  412. pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
  413. pParticle->m_vecVelocity *= m_flScale;
  414. #if __EXPLOSION_DEBUG
  415. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  416. #endif
  417. int nColor = random->RandomInt( 128, 255 );
  418. pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
  419. pParticle->m_uchStartSize = random->RandomInt( 32, 85 ) * vDev;
  420. pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, 32, 85 ) * m_flScale;
  421. pParticle->m_uchEndSize = (int)((float)pParticle->m_uchStartSize * 1.5f);
  422. pParticle->m_uchStartAlpha = 255;
  423. pParticle->m_uchEndAlpha = 0;
  424. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  425. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  426. }
  427. }
  428. }
  429. //-----------------------------------------------------------------------------
  430. // Purpose:
  431. //-----------------------------------------------------------------------------
  432. void C_BaseExplosionEffect::CreateDebris( void )
  433. {
  434. if ( m_fFlags & TE_EXPLFLAG_NOPARTICLES )
  435. return;
  436. //
  437. // Sparks
  438. //
  439. CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "CreateDebris 1" );
  440. if ( pSparkEmitter == NULL )
  441. {
  442. assert(0);
  443. return;
  444. }
  445. if ( m_Material_FireCloud == NULL )
  446. {
  447. m_Material_FireCloud = pSparkEmitter->GetPMaterial( "effects/fire_cloud2" );
  448. }
  449. pSparkEmitter->SetSortOrigin( m_vecOrigin );
  450. pSparkEmitter->m_ParticleCollision.SetGravity( 200.0f );
  451. pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  452. pSparkEmitter->SetVelocityDampen( 8.0f );
  453. // Set our bbox, don't auto-calculate it!
  454. pSparkEmitter->GetBinding().SetBBox( m_vecOrigin - Vector( 128, 128, 128 ), m_vecOrigin + Vector( 128, 128, 128 ) );
  455. int numSparks = random->RandomInt( 8, 16 );
  456. Vector dir;
  457. float spread = 1.0f;
  458. TrailParticle *tParticle;
  459. // Dump out sparks
  460. int i;
  461. for ( i = 0; i < numSparks; i++ )
  462. {
  463. tParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), m_Material_FireCloud, m_vecOrigin );
  464. if ( tParticle == NULL )
  465. break;
  466. tParticle->m_flLifetime = 0.0f;
  467. tParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.15f );
  468. dir.Random( -spread, spread );
  469. dir += m_vecDirection;
  470. VectorNormalize( dir );
  471. tParticle->m_flWidth = random->RandomFloat( 2.0f, 16.0f ) * m_flScale;
  472. tParticle->m_flLength = random->RandomFloat( 0.05f, 0.1f ) * m_flScale;
  473. tParticle->m_vecVelocity = dir * random->RandomFloat( 1500, 2500 );
  474. tParticle->m_vecVelocity *= m_flScale;
  475. Color32Init( tParticle->m_color, 255, 255, 255, 255 );
  476. }
  477. //
  478. // Chunks
  479. //
  480. Vector offset;
  481. CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "CreateDebris 2", m_vecOrigin, Vector(128,128,128) * m_flScale );
  482. if ( !fleckEmitter )
  483. return;
  484. // Setup our collision information
  485. fleckEmitter->m_ParticleCollision.Setup( m_vecOrigin, &m_vecDirection, 0.9f, 512, 1024, 800, 0.5f );
  486. int numFlecks = random->RandomInt( 16, 32 );
  487. // Dump out flecks
  488. for ( i = 0; i < numFlecks; i++ )
  489. {
  490. offset = ( m_vecDirection * 16.0f );
  491. offset[0] += random->RandomFloat( -8.0f, 8.0f );
  492. offset[1] += random->RandomFloat( -8.0f, 8.0f );
  493. offset[2] += random->RandomFloat( -8.0f, 8.0f );
  494. offset *= m_flScale;
  495. offset += m_vecOrigin;
  496. FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset );
  497. if ( pParticle == NULL )
  498. break;
  499. pParticle->m_flLifetime = 0.0f;
  500. pParticle->m_flDieTime = 3.0f;
  501. dir[0] = m_vecDirection[0] + random->RandomFloat( -1.0f, 1.0f );
  502. dir[1] = m_vecDirection[1] + random->RandomFloat( -1.0f, 1.0f );
  503. dir[2] = m_vecDirection[2] + random->RandomFloat( -1.0f, 1.0f );
  504. pParticle->m_uchSize = random->RandomInt( 1, 3 ) * m_flScale;
  505. VectorNormalize( dir );
  506. float fForce = ( random->RandomFloat( 64, 256 ) * ( 4 - pParticle->m_uchSize ) );
  507. float fDev = ScaleForceByDeviation( dir, m_vecDirection, 0.8f );
  508. pParticle->m_vecVelocity = dir * ( fForce * ( 16.0f * (fDev*fDev*0.5f) ) );
  509. pParticle->m_vecVelocity *= m_flScale;
  510. pParticle->m_flRoll = random->RandomFloat( 0, 360 );
  511. pParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
  512. float colorRamp = random->RandomFloat( 0.5f, 1.5f );
  513. pParticle->m_uchColor[0] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
  514. pParticle->m_uchColor[1] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
  515. pParticle->m_uchColor[2] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
  516. }
  517. }
  518. //-----------------------------------------------------------------------------
  519. // Purpose:
  520. //-----------------------------------------------------------------------------
  521. void C_BaseExplosionEffect::CreateMisc( void )
  522. {
  523. }
  524. //-----------------------------------------------------------------------------
  525. // Purpose:
  526. //-----------------------------------------------------------------------------
  527. void C_BaseExplosionEffect::CreateDynamicLight( void )
  528. {
  529. if ( m_fFlags & TE_EXPLFLAG_DLIGHT )
  530. {
  531. dlight_t *dl = effects->CL_AllocDlight( 0 );
  532. VectorCopy (m_vecOrigin, dl->origin);
  533. dl->decay = 200;
  534. dl->radius = 255 * m_flScale;
  535. dl->color.r = 255;
  536. dl->color.g = 220;
  537. dl->color.b = 128;
  538. dl->die = gpGlobals->curtime + 0.1f;
  539. }
  540. }
  541. //-----------------------------------------------------------------------------
  542. // Purpose:
  543. //-----------------------------------------------------------------------------
  544. void C_BaseExplosionEffect::PlaySound( void )
  545. {
  546. if ( m_fFlags & TE_EXPLFLAG_NOSOUND )
  547. return;
  548. CLocalPlayerFilter filter;
  549. if ( m_fFlags & TE_EXPLFLAG_ICE )
  550. {
  551. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "explode_3", &m_vecOrigin );
  552. return;
  553. }
  554. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "BaseExplosionEffect.Sound", &m_vecOrigin );
  555. }
  556. //-----------------------------------------------------------------------------
  557. // Purpose:
  558. // Input : origin -
  559. // &m_vecDirection -
  560. // strength -
  561. // Output : float
  562. //-----------------------------------------------------------------------------
  563. float C_BaseExplosionEffect::Probe( const Vector &origin, Vector *vecDirection, float strength )
  564. {
  565. //Press out
  566. Vector endpos = origin + ( (*vecDirection) * strength );
  567. //Trace into the world
  568. trace_t tr;
  569. UTIL_TraceLine( origin, endpos, CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
  570. //Push back a proportional amount to the probe
  571. (*vecDirection) = -(*vecDirection) * (1.0f-tr.fraction);
  572. #if __EXPLOSION_DEBUG
  573. debugoverlay->AddLineOverlay( m_vecOrigin, endpos, (255*(1.0f-tr.fraction)), (255*tr.fraction), 0, false, 3 );
  574. #endif
  575. assert(( 1.0f - tr.fraction ) >= 0.0f );
  576. //Return the impacted proportion of the probe
  577. return (1.0f-tr.fraction);
  578. }
  579. //-----------------------------------------------------------------------------
  580. // Purpose:
  581. // Input : origin -
  582. // &m_vecDirection -
  583. // &m_flForce -
  584. //-----------------------------------------------------------------------------
  585. void C_BaseExplosionEffect::GetForceDirection( const Vector &origin, float magnitude, Vector *resultDirection, float *resultForce )
  586. {
  587. Vector d[6];
  588. //All cardinal directions
  589. d[0] = Vector( 1, 0, 0 );
  590. d[1] = Vector( -1, 0, 0 );
  591. d[2] = Vector( 0, 1, 0 );
  592. d[3] = Vector( 0, -1, 0 );
  593. d[4] = Vector( 0, 0, 1 );
  594. d[5] = Vector( 0, 0, -1 );
  595. //Init the results
  596. (*resultDirection).Init();
  597. (*resultForce) = 1.0f;
  598. //Get the aggregate force vector
  599. for ( int i = 0; i < 6; i++ )
  600. {
  601. (*resultForce) += Probe( origin, &d[i], magnitude );
  602. (*resultDirection) += d[i];
  603. }
  604. //If we've hit nothing, then point up
  605. if ( (*resultDirection) == vec3_origin )
  606. {
  607. (*resultDirection) = Vector( 0, 0, 1 );
  608. (*resultForce) = EXPLOSION_FORCE_MIN;
  609. }
  610. //Just return the direction
  611. VectorNormalize( (*resultDirection) );
  612. }
  613. //-----------------------------------------------------------------------------
  614. // Purpose: Intercepts the water explosion dispatch effect
  615. //-----------------------------------------------------------------------------
  616. void ExplosionCallback( const CEffectData &data )
  617. {
  618. BaseExplosionEffect().Create( data.m_vOrigin, data.m_flMagnitude, data.m_flScale, data.m_fFlags );
  619. }
  620. DECLARE_CLIENT_EFFECT( Explosion, ExplosionCallback );
  621. //===============================================================================================================
  622. // Water Explosion
  623. //===============================================================================================================
  624. //
  625. // CExplosionParticle
  626. //
  627. class CWaterExplosionParticle : public CSimpleEmitter
  628. {
  629. public:
  630. CWaterExplosionParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
  631. //Create
  632. static CWaterExplosionParticle *Create( const char *pDebugName )
  633. {
  634. return new CWaterExplosionParticle( pDebugName );
  635. }
  636. //Roll
  637. virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
  638. {
  639. pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
  640. pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
  641. //Cap the minimum roll
  642. if ( fabs( pParticle->m_flRollDelta ) < 0.25f )
  643. {
  644. pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.25f : -0.25f;
  645. }
  646. return pParticle->m_flRoll;
  647. }
  648. //Velocity
  649. virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
  650. {
  651. Vector saveVelocity = pParticle->m_vecVelocity;
  652. //Decellerate
  653. //pParticle->m_vecVelocity += pParticle->m_vecVelocity * ( timeDelta * -20.0f );
  654. static float dtime;
  655. static float decay;
  656. if ( dtime != timeDelta )
  657. {
  658. dtime = timeDelta;
  659. float expected = 0.5;
  660. decay = exp( log( 0.0001f ) * dtime / expected );
  661. }
  662. pParticle->m_vecVelocity = pParticle->m_vecVelocity * decay;
  663. //Cap the minimum speed
  664. if ( pParticle->m_vecVelocity.LengthSqr() < (8.0f*8.0f) )
  665. {
  666. VectorNormalize( saveVelocity );
  667. pParticle->m_vecVelocity = saveVelocity * 8.0f;
  668. }
  669. }
  670. //Alpha
  671. virtual float UpdateAlpha( const SimpleParticle *pParticle )
  672. {
  673. float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
  674. float ramp = 1.0f - tLifetime;
  675. //Non-linear fade
  676. if ( ramp < 0.75f )
  677. ramp *= ramp;
  678. return ramp;
  679. }
  680. private:
  681. CWaterExplosionParticle( const CWaterExplosionParticle & );
  682. };
  683. //Singleton static member definition
  684. C_WaterExplosionEffect C_WaterExplosionEffect::m_waterinstance;
  685. //Singleton accessor
  686. C_WaterExplosionEffect &WaterExplosionEffect( void )
  687. {
  688. return C_WaterExplosionEffect::Instance();
  689. }
  690. #define MAX_WATER_SURFACE_DISTANCE 512
  691. //-----------------------------------------------------------------------------
  692. // Purpose:
  693. //-----------------------------------------------------------------------------
  694. void C_WaterExplosionEffect::Create( const Vector &position, float force, float scale, int flags )
  695. {
  696. m_vecOrigin = position;
  697. // Find our water surface by tracing up till we're out of the water
  698. trace_t tr;
  699. Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
  700. UTIL_TraceLine( m_vecOrigin, m_vecOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  701. // If we didn't start in water, we're above it
  702. if ( tr.startsolid == false )
  703. {
  704. // Look downward to find the surface
  705. vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
  706. UTIL_TraceLine( m_vecOrigin, m_vecOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
  707. // If we hit it, setup the explosion
  708. if ( tr.fraction < 1.0f )
  709. {
  710. m_vecWaterSurface = tr.endpos;
  711. m_flDepth = 0.0f;
  712. }
  713. else
  714. {
  715. //NOTENOTE: We somehow got into a water explosion without being near water?
  716. Assert( 0 );
  717. m_vecWaterSurface = m_vecOrigin;
  718. m_flDepth = 0.0f;
  719. }
  720. }
  721. else if ( tr.fractionleftsolid )
  722. {
  723. // Otherwise we came out of the water at this point
  724. m_vecWaterSurface = m_vecOrigin + (vecTrace * tr.fractionleftsolid);
  725. m_flDepth = MAX_WATER_SURFACE_DISTANCE * tr.fractionleftsolid;
  726. }
  727. else
  728. {
  729. // Use default values, we're really deep
  730. m_vecWaterSurface = m_vecOrigin;
  731. m_flDepth = MAX_WATER_SURFACE_DISTANCE;
  732. }
  733. // Get our lighting information
  734. FX_GetSplashLighting( m_vecOrigin + Vector( 0, 0, 32 ), &m_vecColor, &m_flLuminosity );
  735. BaseClass::Create( position, force, scale, flags );
  736. }
  737. //-----------------------------------------------------------------------------
  738. // Purpose:
  739. //-----------------------------------------------------------------------------
  740. void C_WaterExplosionEffect::CreateCore( void )
  741. {
  742. if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
  743. return;
  744. // Get our lighting information for the water surface
  745. Vector color;
  746. float luminosity;
  747. FX_GetSplashLighting( m_vecWaterSurface + Vector( 0, 0, 8 ), &color, &luminosity );
  748. float lifetime = random->RandomFloat( 0.8f, 1.0f );
  749. // Ground splash
  750. FX_AddQuad( m_vecWaterSurface + Vector(0,0,2),
  751. Vector(0,0,1),
  752. 64,
  753. 64 * 4.0f,
  754. 0.85f,
  755. luminosity,
  756. 0.0f,
  757. 0.25f,
  758. random->RandomInt( 0, 360 ),
  759. random->RandomFloat( -4, 4 ),
  760. color,
  761. 2.0f,
  762. "effects/splashwake1",
  763. (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
  764. Vector vRight, vUp;
  765. VectorVectors( Vector(0,0,1) , vRight, vUp );
  766. Vector start, end;
  767. float radius = 50.0f;
  768. unsigned int flags = 0;
  769. // Base vertical shaft
  770. FXLineData_t lineData;
  771. start = m_vecWaterSurface;
  772. end = start + ( Vector( 0, 0, 1 ) * random->RandomFloat( radius, radius*1.5f ) );
  773. if ( random->RandomInt( 0, 1 ) )
  774. {
  775. flags |= FXSTATICLINE_FLIP_HORIZONTAL;
  776. }
  777. else
  778. {
  779. flags = 0;
  780. }
  781. lineData.m_flDieTime = lifetime * 0.5f;
  782. lineData.m_flStartAlpha= luminosity;
  783. lineData.m_flEndAlpha = 0.0f;
  784. lineData.m_flStartScale = radius*0.5f;
  785. lineData.m_flEndScale = radius*2;
  786. lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );
  787. lineData.m_vecStart = start;
  788. lineData.m_vecStartVelocity = vec3_origin;
  789. lineData.m_vecEnd = end;
  790. lineData.m_vecEndVelocity = Vector(0,0,random->RandomFloat( 650, 750 ));
  791. FX_AddLine( lineData );
  792. // Inner filler shaft
  793. start = m_vecWaterSurface;
  794. end = start + ( Vector(0,0,1) * random->RandomFloat( 32, 64 ) );
  795. if ( random->RandomInt( 0, 1 ) )
  796. {
  797. flags |= FXSTATICLINE_FLIP_HORIZONTAL;
  798. }
  799. else
  800. {
  801. flags = 0;
  802. }
  803. lineData.m_flDieTime = lifetime * 0.5f;
  804. lineData.m_flStartAlpha= luminosity;
  805. lineData.m_flEndAlpha = 0.0f;
  806. lineData.m_flStartScale = radius;
  807. lineData.m_flEndScale = radius*2;
  808. lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );
  809. lineData.m_vecStart = start;
  810. lineData.m_vecStartVelocity = vec3_origin;
  811. lineData.m_vecEnd = end;
  812. lineData.m_vecEndVelocity = Vector(0,0,1) * random->RandomFloat( 64, 128 );
  813. FX_AddLine( lineData );
  814. }
  815. //-----------------------------------------------------------------------------
  816. // Purpose:
  817. //-----------------------------------------------------------------------------
  818. void C_WaterExplosionEffect::CreateDebris( void )
  819. {
  820. if ( m_fFlags & TE_EXPLFLAG_NOPARTICLES )
  821. return;
  822. // Must be in deep enough water
  823. if ( m_flDepth <= 128 )
  824. return;
  825. Vector offset;
  826. int i;
  827. //Spread constricts as force rises
  828. float force = m_flForce;
  829. //Cap our force
  830. if ( force < EXPLOSION_FORCE_MIN )
  831. force = EXPLOSION_FORCE_MIN;
  832. if ( force > EXPLOSION_FORCE_MAX )
  833. force = EXPLOSION_FORCE_MAX;
  834. float spread = 1.0f - (0.15f*force);
  835. SimpleParticle *pParticle;
  836. CSmartPtr<CWaterExplosionParticle> pSimple = CWaterExplosionParticle::Create( "waterexp_bubbles" );
  837. pSimple->SetSortOrigin( m_vecOrigin );
  838. pSimple->SetNearClip( 64, 128 );
  839. //FIXME: Better sampling area
  840. offset = m_vecOrigin + ( m_vecDirection * 64.0f );
  841. //Find area ambient light color and use it to tint bubbles
  842. Vector worldLight;
  843. FX_GetSplashLighting( offset, &worldLight, NULL );
  844. //
  845. // Smoke
  846. //
  847. CParticleSubTexture *pMaterial[2];
  848. pMaterial[0] = pSimple->GetPMaterial( "effects/splash1" );
  849. pMaterial[1] = pSimple->GetPMaterial( "effects/splash2" );
  850. for ( i = 0; i < 16; i++ )
  851. {
  852. offset.Random( -32.0f, 32.0f );
  853. offset += m_vecOrigin;
  854. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pMaterial[random->RandomInt(0,1)], offset );
  855. if ( pParticle != NULL )
  856. {
  857. pParticle->m_flLifetime = 0.0f;
  858. #ifdef INVASION_CLIENT_DLL
  859. pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  860. #else
  861. pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
  862. #endif
  863. pParticle->m_vecVelocity.Random( -spread, spread );
  864. pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
  865. VectorNormalize( pParticle->m_vecVelocity );
  866. float fForce = 1500 * force;
  867. //Scale the force down as we fall away from our main direction
  868. ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
  869. pParticle->m_vecVelocity *= fForce;
  870. #if __EXPLOSION_DEBUG
  871. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  872. #endif
  873. pParticle->m_uchColor[0] = m_vecColor.x * 255;
  874. pParticle->m_uchColor[1] = m_vecColor.y * 255;
  875. pParticle->m_uchColor[2] = m_vecColor.z * 255;
  876. pParticle->m_uchStartSize = random->RandomInt( 32, 64 );
  877. pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
  878. pParticle->m_uchStartAlpha = m_flLuminosity;
  879. pParticle->m_uchEndAlpha = 0;
  880. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  881. pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
  882. }
  883. }
  884. }
  885. //-----------------------------------------------------------------------------
  886. // Purpose:
  887. //-----------------------------------------------------------------------------
  888. void C_WaterExplosionEffect::CreateMisc( void )
  889. {
  890. Vector offset;
  891. float colorRamp;
  892. int i;
  893. float flScale = 2.0f;
  894. PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" );
  895. int numDrops = 32;
  896. float length = 0.1f;
  897. Vector vForward, vRight, vUp;
  898. Vector offDir;
  899. TrailParticle *tParticle;
  900. CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" );
  901. if ( !sparkEmitter )
  902. return;
  903. sparkEmitter->SetSortOrigin( m_vecWaterSurface );
  904. sparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
  905. sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
  906. sparkEmitter->SetVelocityDampen( 2.0f );
  907. //Dump out drops
  908. for ( i = 0; i < numDrops; i++ )
  909. {
  910. offset = m_vecWaterSurface;
  911. offset[0] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
  912. offset[1] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
  913. tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  914. if ( tParticle == NULL )
  915. break;
  916. tParticle->m_flLifetime = 0.0f;
  917. tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  918. offDir = Vector(0,0,1) + RandomVector( -1.0f, 1.0f );
  919. tParticle->m_vecVelocity = offDir * random->RandomFloat( 50.0f * flScale * 2.0f, 100.0f * flScale * 2.0f );
  920. tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 128.0f ) * flScale;
  921. tParticle->m_flWidth = clamp( random->RandomFloat( 1.0f, 3.0f ) * flScale, 0.1f, 4.0f );
  922. tParticle->m_flLength = random->RandomFloat( length*0.25f, length )/* * flScale*/;
  923. colorRamp = random->RandomFloat( 1.5f, 2.0f );
  924. FloatToColor32( tParticle->m_color, MIN( 1.0f, m_vecColor[0] * colorRamp ), MIN( 1.0f, m_vecColor[1] * colorRamp ), MIN( 1.0f, m_vecColor[2] * colorRamp ), m_flLuminosity );
  925. }
  926. //Dump out drops
  927. for ( i = 0; i < 4; i++ )
  928. {
  929. offset = m_vecWaterSurface;
  930. offset[0] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
  931. offset[1] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
  932. tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
  933. if ( tParticle == NULL )
  934. break;
  935. tParticle->m_flLifetime = 0.0f;
  936. tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
  937. offDir = Vector(0,0,1) + RandomVector( -0.2f, 0.2f );
  938. tParticle->m_vecVelocity = offDir * random->RandomFloat( 50 * flScale * 3.0f, 100 * flScale * 3.0f );
  939. tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 128.0f ) * flScale;
  940. tParticle->m_flWidth = clamp( random->RandomFloat( 2.0f, 3.0f ) * flScale, 0.1f, 4.0f );
  941. tParticle->m_flLength = random->RandomFloat( length*0.25f, length )/* * flScale*/;
  942. colorRamp = random->RandomFloat( 1.5f, 2.0f );
  943. FloatToColor32( tParticle->m_color, MIN( 1.0f, m_vecColor[0] * colorRamp ), MIN( 1.0f, m_vecColor[1] * colorRamp ), MIN( 1.0f, m_vecColor[2] * colorRamp ), m_flLuminosity );
  944. }
  945. CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
  946. pSimple->SetSortOrigin( m_vecWaterSurface );
  947. pSimple->SetClipHeight( m_vecWaterSurface.z );
  948. pSimple->GetBinding().SetBBox( m_vecWaterSurface-(Vector(32.0f, 32.0f, 32.0f)*flScale), m_vecWaterSurface+(Vector(32.0f, 32.0f, 32.0f)*flScale) );
  949. SimpleParticle *pParticle;
  950. for ( i = 0; i < 16; i++ )
  951. {
  952. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, m_vecWaterSurface );
  953. if ( pParticle == NULL )
  954. break;
  955. pParticle->m_flLifetime = 0.0f;
  956. pParticle->m_flDieTime = 2.0f; //NOTENOTE: We use a clip plane to realistically control our lifespan
  957. pParticle->m_vecVelocity.Random( -0.2f, 0.2f );
  958. pParticle->m_vecVelocity += ( Vector( 0, 0, random->RandomFloat( 4.0f, 6.0f ) ) );
  959. VectorNormalize( pParticle->m_vecVelocity );
  960. pParticle->m_vecVelocity *= 50 * flScale * (8-i);
  961. colorRamp = random->RandomFloat( 0.75f, 1.25f );
  962. pParticle->m_uchColor[0] = MIN( 1.0f, m_vecColor[0] * colorRamp ) * 255.0f;
  963. pParticle->m_uchColor[1] = MIN( 1.0f, m_vecColor[1] * colorRamp ) * 255.0f;
  964. pParticle->m_uchColor[2] = MIN( 1.0f, m_vecColor[2] * colorRamp ) * 255.0f;
  965. pParticle->m_uchStartSize = 24 * flScale * RemapValClamped( i, 7, 0, 1, 0.5f );
  966. pParticle->m_uchEndSize = MIN( 255, pParticle->m_uchStartSize * 2 );
  967. pParticle->m_uchStartAlpha = RemapValClamped( i, 7, 0, 255, 32 ) * m_flLuminosity;
  968. pParticle->m_uchEndAlpha = 0;
  969. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  970. pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
  971. }
  972. }
  973. //-----------------------------------------------------------------------------
  974. // Purpose:
  975. //-----------------------------------------------------------------------------
  976. void C_WaterExplosionEffect::PlaySound( void )
  977. {
  978. if ( m_fFlags & TE_EXPLFLAG_NOSOUND )
  979. return;
  980. CLocalPlayerFilter filter;
  981. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Physics.WaterSplash", &m_vecWaterSurface );
  982. if ( m_flDepth > 128 )
  983. {
  984. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "WaterExplosionEffect.Sound", &m_vecOrigin );
  985. }
  986. else
  987. {
  988. C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "BaseExplosionEffect.Sound", &m_vecOrigin );
  989. }
  990. }
  991. //-----------------------------------------------------------------------------
  992. // Purpose: Intercepts the water explosion dispatch effect
  993. //-----------------------------------------------------------------------------
  994. void WaterSurfaceExplosionCallback( const CEffectData &data )
  995. {
  996. WaterExplosionEffect().Create( data.m_vOrigin, data.m_flMagnitude, data.m_flScale, data.m_fFlags );
  997. }
  998. DECLARE_CLIENT_EFFECT( WaterSurfaceExplosion, WaterSurfaceExplosionCallback );
  999. //Singleton static member definition
  1000. C_MegaBombExplosionEffect C_MegaBombExplosionEffect::m_megainstance;
  1001. //Singleton accessor
  1002. C_MegaBombExplosionEffect &MegaBombExplosionEffect( void )
  1003. {
  1004. return C_MegaBombExplosionEffect::Instance();
  1005. }
  1006. //-----------------------------------------------------------------------------
  1007. // Purpose:
  1008. //-----------------------------------------------------------------------------
  1009. void C_MegaBombExplosionEffect::CreateCore( void )
  1010. {
  1011. if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
  1012. return;
  1013. Vector offset;
  1014. int i;
  1015. //Spread constricts as force rises
  1016. float force = m_flForce;
  1017. //Cap our force
  1018. if ( force < EXPLOSION_FORCE_MIN )
  1019. force = EXPLOSION_FORCE_MIN;
  1020. if ( force > EXPLOSION_FORCE_MAX )
  1021. force = EXPLOSION_FORCE_MAX;
  1022. float spread = 1.0f - (0.15f*force);
  1023. CSmartPtr<CExplosionParticle> pSimple = CExplosionParticle::Create( "exp_smoke" );
  1024. pSimple->SetSortOrigin( m_vecOrigin );
  1025. pSimple->SetNearClip( 32, 64 );
  1026. SimpleParticle *pParticle;
  1027. if ( m_Material_FireCloud == NULL )
  1028. {
  1029. m_Material_FireCloud = pSimple->GetPMaterial( "effects/fire_cloud2" );
  1030. }
  1031. //
  1032. // Fireballs
  1033. //
  1034. for ( i = 0; i < 32; i++ )
  1035. {
  1036. offset.Random( -48.0f, 48.0f );
  1037. offset += m_vecOrigin;
  1038. pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_FireCloud, offset );
  1039. if ( pParticle != NULL )
  1040. {
  1041. pParticle->m_flLifetime = 0.0f;
  1042. pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
  1043. pParticle->m_vecVelocity.Random( -spread*0.75f, spread*0.75f );
  1044. pParticle->m_vecVelocity += m_vecDirection;
  1045. VectorNormalize( pParticle->m_vecVelocity );
  1046. float fForce = random->RandomFloat( 400.0f, 800.0f );
  1047. //Scale the force down as we fall away from our main direction
  1048. float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
  1049. pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
  1050. #if __EXPLOSION_DEBUG
  1051. debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
  1052. #endif
  1053. int nColor = random->RandomInt( 128, 255 );
  1054. pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
  1055. pParticle->m_uchStartSize = random->RandomInt( 32, 85 ) * vDev;
  1056. pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, 32, 85 );
  1057. pParticle->m_uchEndSize = (int)((float)pParticle->m_uchStartSize * 1.5f);
  1058. pParticle->m_uchStartAlpha = 255;
  1059. pParticle->m_uchEndAlpha = 0;
  1060. pParticle->m_flRoll = random->RandomInt( 0, 360 );
  1061. pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
  1062. }
  1063. }
  1064. }
  1065. //-----------------------------------------------------------------------------
  1066. // Purpose:
  1067. // Input : &data -
  1068. //-----------------------------------------------------------------------------
  1069. void HelicopterMegaBombCallback( const CEffectData &data )
  1070. {
  1071. C_MegaBombExplosionEffect().Create( data.m_vOrigin, 1.0f, 1.0f, 0 );
  1072. }
  1073. DECLARE_CLIENT_EFFECT_BEGIN( HelicopterMegaBomb, HelicopterMegaBombCallback )
  1074. //PRECACHE( PARTICLE_SYSTEM, "freeze_explosion" )
  1075. DECLARE_CLIENT_EFFECT_END()