aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/fx_explosion.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /mp/src/game/client/fx_explosion.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'mp/src/game/client/fx_explosion.cpp')
-rw-r--r--mp/src/game/client/fx_explosion.cpp1418
1 files changed, 1418 insertions, 0 deletions
diff --git a/mp/src/game/client/fx_explosion.cpp b/mp/src/game/client/fx_explosion.cpp
new file mode 100644
index 00000000..722c42f1
--- /dev/null
+++ b/mp/src/game/client/fx_explosion.cpp
@@ -0,0 +1,1418 @@
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose: Base explosion effect
+//
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "fx_explosion.h"
+#include "clienteffectprecachesystem.h"
+#include "fx_sparks.h"
+#include "dlight.h"
+#include "tempentity.h"
+#include "iefx.h"
+#include "engine/IEngineSound.h"
+#include "engine/ivdebugoverlay.h"
+#include "c_te_effect_dispatch.h"
+#include "fx.h"
+#include "fx_quad.h"
+#include "fx_line.h"
+#include "fx_water.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+#define __EXPLOSION_DEBUG 0
+
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectExplosion )
+CLIENTEFFECT_MATERIAL( "effects/fire_cloud1" )
+CLIENTEFFECT_MATERIAL( "effects/fire_cloud2" )
+CLIENTEFFECT_MATERIAL( "effects/fire_embers1" )
+CLIENTEFFECT_MATERIAL( "effects/fire_embers2" )
+CLIENTEFFECT_MATERIAL( "effects/fire_embers3" )
+CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade" )
+CLIENTEFFECT_MATERIAL( "particle/particle_smokegrenade1" )
+CLIENTEFFECT_MATERIAL( "effects/splash3" )
+CLIENTEFFECT_MATERIAL( "effects/splashwake1" )
+CLIENTEFFECT_REGISTER_END()
+
+//
+// CExplosionParticle
+//
+
+class CExplosionParticle : public CSimpleEmitter
+{
+public:
+
+ CExplosionParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
+
+ //Create
+ static CExplosionParticle *Create( const char *pDebugName )
+ {
+ return new CExplosionParticle( pDebugName );
+ }
+
+ //Roll
+ virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
+ {
+ pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
+
+ pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
+
+ //Cap the minimum roll
+ if ( fabs( pParticle->m_flRollDelta ) < 0.5f )
+ {
+ pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.5f : -0.5f;
+ }
+
+ return pParticle->m_flRoll;
+ }
+
+ //Velocity
+ virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
+ {
+ Vector saveVelocity = pParticle->m_vecVelocity;
+
+ //Decellerate
+ //pParticle->m_vecVelocity += pParticle->m_vecVelocity * ( timeDelta * -20.0f );
+ static float dtime;
+ static float decay;
+
+ if ( dtime != timeDelta )
+ {
+ dtime = timeDelta;
+ float expected = 0.5;
+ decay = exp( log( 0.0001f ) * dtime / expected );
+ }
+
+ pParticle->m_vecVelocity = pParticle->m_vecVelocity * decay;
+
+
+ //Cap the minimum speed
+ if ( pParticle->m_vecVelocity.LengthSqr() < (32.0f*32.0f) )
+ {
+ VectorNormalize( saveVelocity );
+ pParticle->m_vecVelocity = saveVelocity * 32.0f;
+ }
+ }
+
+ //Alpha
+ virtual float UpdateAlpha( const SimpleParticle *pParticle )
+ {
+ float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
+ float ramp = 1.0f - tLifetime;
+
+ return Bias( ramp, 0.25f );
+ }
+
+ //Color
+ virtual Vector UpdateColor( const SimpleParticle *pParticle )
+ {
+ Vector color;
+
+ float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
+ float ramp = Bias( 1.0f - tLifetime, 0.25f );
+
+ color[0] = ( (float) pParticle->m_uchColor[0] * ramp ) / 255.0f;
+ color[1] = ( (float) pParticle->m_uchColor[1] * ramp ) / 255.0f;
+ color[2] = ( (float) pParticle->m_uchColor[2] * ramp ) / 255.0f;
+
+ return color;
+ }
+
+private:
+ CExplosionParticle( const CExplosionParticle & );
+};
+
+//Singleton static member definition
+C_BaseExplosionEffect C_BaseExplosionEffect::m_instance;
+
+C_BaseExplosionEffect::C_BaseExplosionEffect( void ) : m_Material_Smoke( NULL ), m_Material_FireCloud( NULL )
+{
+ m_Material_Embers[0] = NULL;
+ m_Material_Embers[1] = NULL;
+}
+
+//Singleton accessor
+C_BaseExplosionEffect &BaseExplosionEffect( void )
+{
+ return C_BaseExplosionEffect::Instance();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &deviant -
+// &source -
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseExplosionEffect::ScaleForceByDeviation( Vector &deviant, Vector &source, float spread, float *force )
+{
+ if ( ( deviant == vec3_origin ) || ( source == vec3_origin ) )
+ return 1.0f;
+
+ float dot = source.Dot( deviant );
+
+ dot = spread * fabs( dot );
+
+ if ( force != NULL )
+ {
+ (*force) *= dot;
+ }
+
+ return dot;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : position -
+// force -
+// Output : virtual void
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::Create( const Vector &position, float force, float scale, int flags )
+{
+ m_vecOrigin = position;
+ m_fFlags = flags;
+
+ //Find the force of the explosion
+ GetForceDirection( m_vecOrigin, force, &m_vecDirection, &m_flForce );
+
+#if __EXPLOSION_DEBUG
+ debugoverlay->AddBoxOverlay( m_vecOrigin, -Vector(32,32,32), Vector(32,32,32), vec3_angle, 255, 0, 0, 64, 5.0f );
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin+(m_vecDirection*force*m_flForce), 0, 0, 255, false, 3 );
+#endif
+
+ PlaySound();
+
+ if ( scale != 0 )
+ {
+ // UNDONE: Make core size parametric to scale or remove scale?
+ CreateCore();
+ }
+
+ CreateDebris();
+ //FIXME: CreateDynamicLight();
+ CreateMisc();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::CreateCore( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
+ return;
+
+ Vector offset;
+ int i;
+
+ //Spread constricts as force rises
+ float force = m_flForce;
+
+ //Cap our force
+ if ( force < EXPLOSION_FORCE_MIN )
+ force = EXPLOSION_FORCE_MIN;
+
+ if ( force > EXPLOSION_FORCE_MAX )
+ force = EXPLOSION_FORCE_MAX;
+
+ float spread = 1.0f - (0.15f*force);
+
+ SimpleParticle *pParticle;
+
+ CSmartPtr<CExplosionParticle> pSimple = CExplosionParticle::Create( "exp_smoke" );
+ pSimple->SetSortOrigin( m_vecOrigin );
+ pSimple->SetNearClip( 64, 128 );
+
+ pSimple->GetBinding().SetBBox( m_vecOrigin - Vector( 128, 128, 128 ), m_vecOrigin + Vector( 128, 128, 128 ) );
+
+ if ( m_Material_Smoke == NULL )
+ {
+ m_Material_Smoke = g_Mat_DustPuff[1];
+ }
+
+ //FIXME: Better sampling area
+ offset = m_vecOrigin + ( m_vecDirection * 32.0f );
+
+ //Find area ambient light color and use it to tint smoke
+ Vector worldLight = WorldGetLightForPoint( offset, true );
+
+ Vector tint;
+ float luminosity;
+ if ( worldLight == vec3_origin )
+ {
+ tint = vec3_origin;
+ luminosity = 0.0f;
+ }
+ else
+ {
+ UTIL_GetNormalizedColorTintAndLuminosity( worldLight, &tint, &luminosity );
+ }
+
+ // We only take a portion of the tint
+ tint = (tint * 0.25f)+(Vector(0.75f,0.75f,0.75f));
+
+ // Rescale to a character range
+ luminosity *= 255;
+
+ if ( (m_fFlags & TE_EXPLFLAG_NOFIREBALLSMOKE) == 0 )
+ {
+ //
+ // Smoke - basic internal filler
+ //
+
+ for ( i = 0; i < 4; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, m_vecOrigin );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+
+ #ifdef INVASION_CLIENT_DLL
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+ #endif
+ #ifdef _XBOX
+ pParticle->m_flDieTime = 1.0f;
+ #else
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+ #endif
+
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = random->RandomFloat( 1, 750 ) * force;
+
+ //Scale the force down as we fall away from our main direction
+ ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
+
+ pParticle->m_vecVelocity *= fForce;
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( luminosity*0.5f, luminosity );
+ pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
+ pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
+ pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
+
+ pParticle->m_uchStartSize = 72;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
+ }
+ }
+
+
+ //
+ // Inner core
+ //
+
+#ifndef _XBOX
+
+ for ( i = 0; i < 8; i++ )
+ {
+ offset.Random( -16.0f, 16.0f );
+ offset += m_vecOrigin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+
+ #ifdef INVASION_CLIENT_DLL
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+ #else
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+ #endif
+
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = random->RandomFloat( 1, 2000 ) * force;
+
+ //Scale the force down as we fall away from our main direction
+ ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
+
+ pParticle->m_vecVelocity *= fForce;
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( luminosity*0.5f, luminosity );
+ pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
+ pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
+ pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
+
+ pParticle->m_uchStartSize = random->RandomInt( 32, 64 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
+
+ pParticle->m_uchStartAlpha = random->RandomFloat( 128, 255 );
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
+ }
+ }
+#endif // !_XBOX
+
+ //
+ // Ground ring
+ //
+
+ Vector vRight, vUp;
+ VectorVectors( m_vecDirection, vRight, vUp );
+
+ Vector forward;
+
+#ifndef INVASION_CLIENT_DLL
+
+#ifndef _XBOX
+ int numRingSprites = 32;
+#else
+ int numRingSprites = 8;
+#endif
+
+ float flIncr = (2*M_PI) / (float) numRingSprites; // Radians
+ float flYaw = 0.0f;
+
+ for ( i = 0; i < numRingSprites; i++ )
+ {
+ flYaw += flIncr;
+ SinCos( flYaw, &forward.y, &forward.x );
+ forward.z = 0.0f;
+
+ offset = ( RandomVector( -4.0f, 4.0f ) + m_vecOrigin ) + ( forward * random->RandomFloat( 8.0f, 16.0f ) );
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Smoke, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.5f );
+
+ pParticle->m_vecVelocity = forward;
+
+ float fForce = random->RandomFloat( 500, 2000 ) * force;
+
+ //Scale the force down as we fall away from our main direction
+ ScaleForceByDeviation( pParticle->m_vecVelocity, pParticle->m_vecVelocity, spread, &fForce );
+
+ pParticle->m_vecVelocity *= fForce;
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( luminosity*0.5f, luminosity );
+ pParticle->m_uchColor[0] = ( worldLight[0] * nColor );
+ pParticle->m_uchColor[1] = ( worldLight[1] * nColor );
+ pParticle->m_uchColor[2] = ( worldLight[2] * nColor );
+
+ pParticle->m_uchStartSize = random->RandomInt( 16, 32 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
+
+ pParticle->m_uchStartAlpha = random->RandomFloat( 16, 32 );
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
+ }
+ }
+#endif
+ }
+
+#ifndef _XBOX
+
+ //
+ // Embers
+ //
+
+ if ( m_Material_Embers[0] == NULL )
+ {
+ m_Material_Embers[0] = pSimple->GetPMaterial( "effects/fire_embers1" );
+ }
+
+ if ( m_Material_Embers[1] == NULL )
+ {
+ m_Material_Embers[1] = pSimple->GetPMaterial( "effects/fire_embers2" );
+ }
+
+ for ( i = 0; i < 16; i++ )
+ {
+ offset.Random( -32.0f, 32.0f );
+ offset += m_vecOrigin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Embers[random->RandomInt(0,1)], offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+
+ pParticle->m_vecVelocity.Random( -spread*2, spread*2 );
+ pParticle->m_vecVelocity += m_vecDirection;
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = random->RandomFloat( 1.0f, 400.0f );
+
+ //Scale the force down as we fall away from our main direction
+ float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
+
+ pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( 192, 255 );
+ pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
+
+ pParticle->m_uchStartSize = random->RandomInt( 8, 16 ) * vDev;
+
+ pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, (uint8) 4, (uint8) 32 );
+
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
+ }
+ }
+#endif // !_XBOX
+
+ //
+ // Fireballs
+ //
+
+ if ( m_Material_FireCloud == NULL )
+ {
+ m_Material_FireCloud = pSimple->GetPMaterial( "effects/fire_cloud2" );
+ }
+
+#ifndef _XBOX
+ int numFireballs = 32;
+#else
+ int numFireballs = 16;
+#endif
+
+ for ( i = 0; i < numFireballs; i++ )
+ {
+ offset.Random( -48.0f, 48.0f );
+ offset += m_vecOrigin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_FireCloud, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
+
+ pParticle->m_vecVelocity.Random( -spread*0.75f, spread*0.75f );
+ pParticle->m_vecVelocity += m_vecDirection;
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = random->RandomFloat( 400.0f, 800.0f );
+
+ //Scale the force down as we fall away from our main direction
+ float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
+
+ pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( 128, 255 );
+ pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
+
+ pParticle->m_uchStartSize = random->RandomInt( 32, 85 ) * vDev;
+
+ pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, (uint8) 32, (uint8) 85 );
+
+ pParticle->m_uchEndSize = (int)((float)pParticle->m_uchStartSize * 1.5f);
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::CreateDebris( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOPARTICLES )
+ return;
+
+ //
+ // Sparks
+ //
+
+ CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "CreateDebris 1" );
+ if ( pSparkEmitter == NULL )
+ {
+ assert(0);
+ return;
+ }
+
+ if ( m_Material_FireCloud == NULL )
+ {
+ m_Material_FireCloud = pSparkEmitter->GetPMaterial( "effects/fire_cloud2" );
+ }
+
+ pSparkEmitter->SetSortOrigin( m_vecOrigin );
+
+ pSparkEmitter->m_ParticleCollision.SetGravity( 200.0f );
+ pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
+ pSparkEmitter->SetVelocityDampen( 8.0f );
+
+ // Set our bbox, don't auto-calculate it!
+ pSparkEmitter->GetBinding().SetBBox( m_vecOrigin - Vector( 128, 128, 128 ), m_vecOrigin + Vector( 128, 128, 128 ) );
+
+#ifndef _XBOX
+ int numSparks = random->RandomInt( 8, 16 );
+#else
+ int numSparks = random->RandomInt( 2, 4 );
+#endif
+
+ Vector dir;
+ float spread = 1.0f;
+ TrailParticle *tParticle;
+
+ // Dump out sparks
+ int i;
+ for ( i = 0; i < numSparks; i++ )
+ {
+ tParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), m_Material_FireCloud, m_vecOrigin );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+ tParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.15f );
+
+ dir.Random( -spread, spread );
+ dir += m_vecDirection;
+ VectorNormalize( dir );
+
+ tParticle->m_flWidth = random->RandomFloat( 2.0f, 16.0f );
+ tParticle->m_flLength = random->RandomFloat( 0.05f, 0.1f );
+
+ tParticle->m_vecVelocity = dir * random->RandomFloat( 1500, 2500 );
+
+ Color32Init( tParticle->m_color, 255, 255, 255, 255 );
+ }
+
+#ifndef _XBOX
+ //
+ // Chunks
+ //
+
+ Vector offset;
+ CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "CreateDebris 2", m_vecOrigin, Vector(128,128,128) );
+ if ( !fleckEmitter )
+ return;
+
+ // Setup our collision information
+ fleckEmitter->m_ParticleCollision.Setup( m_vecOrigin, &m_vecDirection, 0.9f, 512, 1024, 800, 0.5f );
+
+
+#ifdef _XBOX
+ int numFlecks = random->RandomInt( 8, 16 );
+#else
+ int numFlecks = random->RandomInt( 16, 32 );
+#endif // _XBOX
+
+
+ // Dump out flecks
+ for ( i = 0; i < numFlecks; i++ )
+ {
+ offset = m_vecOrigin + ( m_vecDirection * 16.0f );
+
+ offset[0] += random->RandomFloat( -8.0f, 8.0f );
+ offset[1] += random->RandomFloat( -8.0f, 8.0f );
+ offset[2] += random->RandomFloat( -8.0f, 8.0f );
+
+ FleckParticle *pParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), g_Mat_Fleck_Cement[random->RandomInt(0,1)], offset );
+
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 3.0f;
+
+ dir[0] = m_vecDirection[0] + random->RandomFloat( -1.0f, 1.0f );
+ dir[1] = m_vecDirection[1] + random->RandomFloat( -1.0f, 1.0f );
+ dir[2] = m_vecDirection[2] + random->RandomFloat( -1.0f, 1.0f );
+
+ pParticle->m_uchSize = random->RandomInt( 1, 3 );
+
+ VectorNormalize( dir );
+
+ float fForce = ( random->RandomFloat( 64, 256 ) * ( 4 - pParticle->m_uchSize ) );
+
+ float fDev = ScaleForceByDeviation( dir, m_vecDirection, 0.8f );
+
+ pParticle->m_vecVelocity = dir * ( fForce * ( 16.0f * (fDev*fDev*0.5f) ) );
+
+ pParticle->m_flRoll = random->RandomFloat( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
+
+ float colorRamp = random->RandomFloat( 0.5f, 1.5f );
+ pParticle->m_uchColor[0] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
+ pParticle->m_uchColor[1] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, 0.25f*colorRamp )*255.0f;
+ }
+#endif // !_XBOX
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::CreateMisc( void )
+{
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::CreateDynamicLight( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NODLIGHTS )
+ return;
+
+ dlight_t *dl = effects->CL_AllocDlight( 0 );
+
+ VectorCopy (m_vecOrigin, dl->origin);
+
+ dl->decay = 200;
+ dl->radius = 255;
+ dl->color.r = 255;
+ dl->color.g = 220;
+ dl->color.b = 128;
+ dl->die = gpGlobals->curtime + 0.1f;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::PlaySound( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOSOUND )
+ return;
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "BaseExplosionEffect.Sound", &m_vecOrigin );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : origin -
+// &m_vecDirection -
+// strength -
+// Output : float
+//-----------------------------------------------------------------------------
+float C_BaseExplosionEffect::Probe( const Vector &origin, Vector *vecDirection, float strength )
+{
+ //Press out
+ Vector endpos = origin + ( (*vecDirection) * strength );
+
+ //Trace into the world
+ trace_t tr;
+ UTIL_TraceLine( origin, endpos, CONTENTS_SOLID, NULL, COLLISION_GROUP_NONE, &tr );
+
+ //Push back a proportional amount to the probe
+ (*vecDirection) = -(*vecDirection) * (1.0f-tr.fraction);
+
+#if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, endpos, (255*(1.0f-tr.fraction)), (255*tr.fraction), 0, false, 3 );
+#endif
+
+ assert(( 1.0f - tr.fraction ) >= 0.0f );
+
+ //Return the impacted proportion of the probe
+ return (1.0f-tr.fraction);
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : origin -
+// &m_vecDirection -
+// &m_flForce -
+//-----------------------------------------------------------------------------
+void C_BaseExplosionEffect::GetForceDirection( const Vector &origin, float magnitude, Vector *resultDirection, float *resultForce )
+{
+ Vector d[6];
+
+ //All cardinal directions
+ d[0] = Vector( 1, 0, 0 );
+ d[1] = Vector( -1, 0, 0 );
+ d[2] = Vector( 0, 1, 0 );
+ d[3] = Vector( 0, -1, 0 );
+ d[4] = Vector( 0, 0, 1 );
+ d[5] = Vector( 0, 0, -1 );
+
+ //Init the results
+ (*resultDirection).Init();
+ (*resultForce) = 1.0f;
+
+ //Get the aggregate force vector
+ for ( int i = 0; i < 6; i++ )
+ {
+ (*resultForce) += Probe( origin, &d[i], magnitude );
+ (*resultDirection) += d[i];
+ }
+
+ //If we've hit nothing, then point up
+ if ( (*resultDirection) == vec3_origin )
+ {
+ (*resultDirection) = Vector( 0, 0, 1 );
+ (*resultForce) = EXPLOSION_FORCE_MIN;
+ }
+
+ //Just return the direction
+ VectorNormalize( (*resultDirection) );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Intercepts the water explosion dispatch effect
+//-----------------------------------------------------------------------------
+void ExplosionCallback( const CEffectData &data )
+{
+ BaseExplosionEffect().Create( data.m_vOrigin, data.m_flMagnitude, data.m_flScale, data.m_fFlags );
+}
+
+DECLARE_CLIENT_EFFECT( "Explosion", ExplosionCallback );
+
+
+//===============================================================================================================
+// Water Explosion
+//===============================================================================================================
+//
+// CExplosionParticle
+//
+
+class CWaterExplosionParticle : public CSimpleEmitter
+{
+public:
+
+ CWaterExplosionParticle( const char *pDebugName ) : CSimpleEmitter( pDebugName ) {}
+
+ //Create
+ static CWaterExplosionParticle *Create( const char *pDebugName )
+ {
+ return new CWaterExplosionParticle( pDebugName );
+ }
+
+ //Roll
+ virtual float UpdateRoll( SimpleParticle *pParticle, float timeDelta )
+ {
+ pParticle->m_flRoll += pParticle->m_flRollDelta * timeDelta;
+
+ pParticle->m_flRollDelta += pParticle->m_flRollDelta * ( timeDelta * -8.0f );
+
+ //Cap the minimum roll
+ if ( fabs( pParticle->m_flRollDelta ) < 0.25f )
+ {
+ pParticle->m_flRollDelta = ( pParticle->m_flRollDelta > 0.0f ) ? 0.25f : -0.25f;
+ }
+
+ return pParticle->m_flRoll;
+ }
+
+ //Velocity
+ virtual void UpdateVelocity( SimpleParticle *pParticle, float timeDelta )
+ {
+ Vector saveVelocity = pParticle->m_vecVelocity;
+
+ //Decellerate
+ //pParticle->m_vecVelocity += pParticle->m_vecVelocity * ( timeDelta * -20.0f );
+ static float dtime;
+ static float decay;
+
+ if ( dtime != timeDelta )
+ {
+ dtime = timeDelta;
+ float expected = 0.5;
+ decay = exp( log( 0.0001f ) * dtime / expected );
+ }
+
+ pParticle->m_vecVelocity = pParticle->m_vecVelocity * decay;
+
+
+ //Cap the minimum speed
+ if ( pParticle->m_vecVelocity.LengthSqr() < (8.0f*8.0f) )
+ {
+ VectorNormalize( saveVelocity );
+ pParticle->m_vecVelocity = saveVelocity * 8.0f;
+ }
+ }
+
+ //Alpha
+ virtual float UpdateAlpha( const SimpleParticle *pParticle )
+ {
+ float tLifetime = pParticle->m_flLifetime / pParticle->m_flDieTime;
+ float ramp = 1.0f - tLifetime;
+
+ //Non-linear fade
+ if ( ramp < 0.75f )
+ ramp *= ramp;
+
+ return ramp;
+ }
+
+private:
+ CWaterExplosionParticle( const CWaterExplosionParticle & );
+};
+
+//Singleton static member definition
+C_WaterExplosionEffect C_WaterExplosionEffect::m_waterinstance;
+
+//Singleton accessor
+C_WaterExplosionEffect &WaterExplosionEffect( void )
+{
+ return C_WaterExplosionEffect::Instance();
+}
+
+#define MAX_WATER_SURFACE_DISTANCE 512
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WaterExplosionEffect::Create( const Vector &position, float force, float scale, int flags )
+{
+ m_vecOrigin = position;
+
+ // Find our water surface by tracing up till we're out of the water
+ trace_t tr;
+ Vector vecTrace( 0, 0, MAX_WATER_SURFACE_DISTANCE );
+ UTIL_TraceLine( m_vecOrigin, m_vecOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
+
+ // If we didn't start in water, we're above it
+ if ( tr.startsolid == false )
+ {
+ // Look downward to find the surface
+ vecTrace.Init( 0, 0, -MAX_WATER_SURFACE_DISTANCE );
+ UTIL_TraceLine( m_vecOrigin, m_vecOrigin + vecTrace, MASK_WATER, NULL, COLLISION_GROUP_NONE, &tr );
+
+ // If we hit it, setup the explosion
+ if ( tr.fraction < 1.0f )
+ {
+ m_vecWaterSurface = tr.endpos;
+ m_flDepth = 0.0f;
+ }
+ else
+ {
+ //NOTENOTE: We somehow got into a water explosion without being near water?
+ Assert( 0 );
+ m_vecWaterSurface = m_vecOrigin;
+ m_flDepth = 0.0f;
+ }
+ }
+ else if ( tr.fractionleftsolid )
+ {
+ // Otherwise we came out of the water at this point
+ m_vecWaterSurface = m_vecOrigin + (vecTrace * tr.fractionleftsolid);
+ m_flDepth = MAX_WATER_SURFACE_DISTANCE * tr.fractionleftsolid;
+ }
+ else
+ {
+ // Use default values, we're really deep
+ m_vecWaterSurface = m_vecOrigin;
+ m_flDepth = MAX_WATER_SURFACE_DISTANCE;
+ }
+
+ // Get our lighting information
+ FX_GetSplashLighting( m_vecOrigin + Vector( 0, 0, 32 ), &m_vecColor, &m_flLuminosity );
+
+ BaseClass::Create( position, force, scale, flags );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WaterExplosionEffect::CreateCore( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
+ return;
+
+ // Get our lighting information for the water surface
+ Vector color;
+ float luminosity;
+ FX_GetSplashLighting( m_vecWaterSurface + Vector( 0, 0, 8 ), &color, &luminosity );
+
+ float lifetime = random->RandomFloat( 0.8f, 1.0f );
+
+ // Ground splash
+ FX_AddQuad( m_vecWaterSurface + Vector(0,0,2),
+ Vector(0,0,1),
+ 64,
+ 64 * 4.0f,
+ 0.85f,
+ luminosity,
+ 0.0f,
+ 0.25f,
+ random->RandomInt( 0, 360 ),
+ random->RandomFloat( -4, 4 ),
+ color,
+ 2.0f,
+ "effects/splashwake1",
+ (FXQUAD_BIAS_SCALE|FXQUAD_BIAS_ALPHA) );
+
+ Vector vRight, vUp;
+ VectorVectors( Vector(0,0,1) , vRight, vUp );
+
+ Vector start, end;
+
+ float radius = 50.0f;
+
+ unsigned int flags = 0;
+
+ // Base vertical shaft
+ FXLineData_t lineData;
+
+ start = m_vecWaterSurface;
+ end = start + ( Vector( 0, 0, 1 ) * random->RandomFloat( radius, radius*1.5f ) );
+
+ if ( random->RandomInt( 0, 1 ) )
+ {
+ flags |= FXSTATICLINE_FLIP_HORIZONTAL;
+ }
+ else
+ {
+ flags = 0;
+ }
+
+ lineData.m_flDieTime = lifetime * 0.5f;
+
+ lineData.m_flStartAlpha= luminosity;
+ lineData.m_flEndAlpha = 0.0f;
+
+ lineData.m_flStartScale = radius*0.5f;
+ lineData.m_flEndScale = radius*2;
+
+ lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );
+
+ lineData.m_vecStart = start;
+ lineData.m_vecStartVelocity = vec3_origin;
+
+ lineData.m_vecEnd = end;
+ lineData.m_vecEndVelocity = Vector(0,0,random->RandomFloat( 650, 750 ));
+
+ FX_AddLine( lineData );
+
+ // Inner filler shaft
+ start = m_vecWaterSurface;
+ end = start + ( Vector(0,0,1) * random->RandomFloat( 32, 64 ) );
+
+ if ( random->RandomInt( 0, 1 ) )
+ {
+ flags |= FXSTATICLINE_FLIP_HORIZONTAL;
+ }
+ else
+ {
+ flags = 0;
+ }
+
+ lineData.m_flDieTime = lifetime * 0.5f;
+
+ lineData.m_flStartAlpha= luminosity;
+ lineData.m_flEndAlpha = 0.0f;
+
+ lineData.m_flStartScale = radius;
+ lineData.m_flEndScale = radius*2;
+
+ lineData.m_pMaterial = materials->FindMaterial( "effects/splash3", 0, 0 );
+
+ lineData.m_vecStart = start;
+ lineData.m_vecStartVelocity = vec3_origin;
+
+ lineData.m_vecEnd = end;
+ lineData.m_vecEndVelocity = Vector(0,0,1) * random->RandomFloat( 64, 128 );
+
+ FX_AddLine( lineData );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WaterExplosionEffect::CreateDebris( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOPARTICLES )
+ return;
+
+ // Must be in deep enough water
+ if ( m_flDepth <= 128 )
+ return;
+
+ Vector offset;
+ int i;
+
+ //Spread constricts as force rises
+ float force = m_flForce;
+
+ //Cap our force
+ if ( force < EXPLOSION_FORCE_MIN )
+ force = EXPLOSION_FORCE_MIN;
+
+ if ( force > EXPLOSION_FORCE_MAX )
+ force = EXPLOSION_FORCE_MAX;
+
+ float spread = 1.0f - (0.15f*force);
+
+ SimpleParticle *pParticle;
+
+ CSmartPtr<CWaterExplosionParticle> pSimple = CWaterExplosionParticle::Create( "waterexp_bubbles" );
+ pSimple->SetSortOrigin( m_vecOrigin );
+ pSimple->SetNearClip( 64, 128 );
+
+ //FIXME: Better sampling area
+ offset = m_vecOrigin + ( m_vecDirection * 64.0f );
+
+ //Find area ambient light color and use it to tint bubbles
+ Vector worldLight;
+ FX_GetSplashLighting( offset, &worldLight, NULL );
+
+ //
+ // Smoke
+ //
+
+ CParticleSubTexture *pMaterial[2];
+
+ pMaterial[0] = pSimple->GetPMaterial( "effects/splash1" );
+ pMaterial[1] = pSimple->GetPMaterial( "effects/splash2" );
+
+ for ( i = 0; i < 16; i++ )
+ {
+ offset.Random( -32.0f, 32.0f );
+ offset += m_vecOrigin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pMaterial[random->RandomInt(0,1)], offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+
+#ifdef INVASION_CLIENT_DLL
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+#else
+ pParticle->m_flDieTime = random->RandomFloat( 2.0f, 3.0f );
+#endif
+
+ pParticle->m_vecVelocity.Random( -spread, spread );
+ pParticle->m_vecVelocity += ( m_vecDirection * random->RandomFloat( 1.0f, 6.0f ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = 1500 * force;
+
+ //Scale the force down as we fall away from our main direction
+ ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread, &fForce );
+
+ pParticle->m_vecVelocity *= fForce;
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ pParticle->m_uchColor[0] = m_vecColor.x * 255;
+ pParticle->m_uchColor[1] = m_vecColor.y * 255;
+ pParticle->m_uchColor[2] = m_vecColor.z * 255;
+
+ pParticle->m_uchStartSize = random->RandomInt( 32, 64 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
+
+ pParticle->m_uchStartAlpha = m_flLuminosity;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WaterExplosionEffect::CreateMisc( void )
+{
+ Vector offset;
+ float colorRamp;
+
+ int i;
+ float flScale = 2.0f;
+
+ PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/splash2" );
+
+#ifndef _XBOX
+
+ int numDrops = 32;
+ float length = 0.1f;
+ Vector vForward, vRight, vUp;
+ Vector offDir;
+
+ TrailParticle *tParticle;
+
+ CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" );
+
+ if ( !sparkEmitter )
+ return;
+
+ sparkEmitter->SetSortOrigin( m_vecWaterSurface );
+ sparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
+ sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
+ sparkEmitter->SetVelocityDampen( 2.0f );
+
+ //Dump out drops
+ for ( i = 0; i < numDrops; i++ )
+ {
+ offset = m_vecWaterSurface;
+ offset[0] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+ offset[1] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+
+ tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+ tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+
+ offDir = Vector(0,0,1) + RandomVector( -1.0f, 1.0f );
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( 50.0f * flScale * 2.0f, 100.0f * flScale * 2.0f );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 128.0f ) * flScale;
+
+ tParticle->m_flWidth = clamp( random->RandomFloat( 1.0f, 3.0f ) * flScale, 0.1f, 4.0f );
+ tParticle->m_flLength = random->RandomFloat( length*0.25f, length )/* * flScale*/;
+
+ colorRamp = random->RandomFloat( 1.5f, 2.0f );
+
+ 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 );
+ }
+
+ //Dump out drops
+ for ( i = 0; i < 4; i++ )
+ {
+ offset = m_vecWaterSurface;
+ offset[0] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+ offset[1] += random->RandomFloat( -16.0f, 16.0f ) * flScale;
+
+ tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset );
+
+ if ( tParticle == NULL )
+ break;
+
+ tParticle->m_flLifetime = 0.0f;
+ tParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+
+ offDir = Vector(0,0,1) + RandomVector( -0.2f, 0.2f );
+
+ tParticle->m_vecVelocity = offDir * random->RandomFloat( 50 * flScale * 3.0f, 100 * flScale * 3.0f );
+ tParticle->m_vecVelocity[2] += random->RandomFloat( 32.0f, 128.0f ) * flScale;
+
+ tParticle->m_flWidth = clamp( random->RandomFloat( 2.0f, 3.0f ) * flScale, 0.1f, 4.0f );
+ tParticle->m_flLength = random->RandomFloat( length*0.25f, length )/* * flScale*/;
+
+ colorRamp = random->RandomFloat( 1.5f, 2.0f );
+
+ 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 );
+ }
+
+#endif
+
+ CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" );
+ pSimple->SetSortOrigin( m_vecWaterSurface );
+ pSimple->SetClipHeight( m_vecWaterSurface.z );
+ pSimple->GetBinding().SetBBox( m_vecWaterSurface-(Vector(32.0f, 32.0f, 32.0f)*flScale), m_vecWaterSurface+(Vector(32.0f, 32.0f, 32.0f)*flScale) );
+
+ SimpleParticle *pParticle;
+
+ for ( i = 0; i < 16; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, m_vecWaterSurface );
+
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 2.0f; //NOTENOTE: We use a clip plane to realistically control our lifespan
+
+ pParticle->m_vecVelocity.Random( -0.2f, 0.2f );
+ pParticle->m_vecVelocity += ( Vector( 0, 0, random->RandomFloat( 4.0f, 6.0f ) ) );
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ pParticle->m_vecVelocity *= 50 * flScale * (8-i);
+
+ colorRamp = random->RandomFloat( 0.75f, 1.25f );
+
+ pParticle->m_uchColor[0] = MIN( 1.0f, m_vecColor[0] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[1] = MIN( 1.0f, m_vecColor[1] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, m_vecColor[2] * colorRamp ) * 255.0f;
+
+ pParticle->m_uchStartSize = 24 * flScale * RemapValClamped( i, 7, 0, 1, 0.5f );
+ pParticle->m_uchEndSize = MIN( 255, pParticle->m_uchStartSize * 2 );
+
+ pParticle->m_uchStartAlpha = RemapValClamped( i, 7, 0, 255, 32 ) * m_flLuminosity;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_WaterExplosionEffect::PlaySound( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOSOUND )
+ return;
+
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "Physics.WaterSplash", &m_vecWaterSurface );
+
+ if ( m_flDepth > 128 )
+ {
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "WaterExplosionEffect.Sound", &m_vecOrigin );
+ }
+ else
+ {
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "BaseExplosionEffect.Sound", &m_vecOrigin );
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Intercepts the water explosion dispatch effect
+//-----------------------------------------------------------------------------
+void WaterSurfaceExplosionCallback( const CEffectData &data )
+{
+ WaterExplosionEffect().Create( data.m_vOrigin, data.m_flMagnitude, data.m_flScale, data.m_fFlags );
+}
+
+DECLARE_CLIENT_EFFECT( "WaterSurfaceExplosion", WaterSurfaceExplosionCallback );
+
+//Singleton static member definition
+C_MegaBombExplosionEffect C_MegaBombExplosionEffect::m_megainstance;
+
+//Singleton accessor
+C_MegaBombExplosionEffect &MegaBombExplosionEffect( void )
+{
+ return C_MegaBombExplosionEffect::Instance();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void C_MegaBombExplosionEffect::CreateCore( void )
+{
+ if ( m_fFlags & TE_EXPLFLAG_NOFIREBALL )
+ return;
+
+ Vector offset;
+ int i;
+
+ //Spread constricts as force rises
+ float force = m_flForce;
+
+ //Cap our force
+ if ( force < EXPLOSION_FORCE_MIN )
+ force = EXPLOSION_FORCE_MIN;
+
+ if ( force > EXPLOSION_FORCE_MAX )
+ force = EXPLOSION_FORCE_MAX;
+
+ float spread = 1.0f - (0.15f*force);
+
+ CSmartPtr<CExplosionParticle> pSimple = CExplosionParticle::Create( "exp_smoke" );
+ pSimple->SetSortOrigin( m_vecOrigin );
+ pSimple->SetNearClip( 32, 64 );
+
+ SimpleParticle *pParticle;
+
+ if ( m_Material_FireCloud == NULL )
+ {
+ m_Material_FireCloud = pSimple->GetPMaterial( "effects/fire_cloud2" );
+ }
+
+ //
+ // Fireballs
+ //
+
+ for ( i = 0; i < 32; i++ )
+ {
+ offset.Random( -48.0f, 48.0f );
+ offset += m_vecOrigin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_FireCloud, offset );
+
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
+
+ pParticle->m_vecVelocity.Random( -spread*0.75f, spread*0.75f );
+ pParticle->m_vecVelocity += m_vecDirection;
+
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ float fForce = random->RandomFloat( 400.0f, 800.0f );
+
+ //Scale the force down as we fall away from our main direction
+ float vDev = ScaleForceByDeviation( pParticle->m_vecVelocity, m_vecDirection, spread );
+
+ pParticle->m_vecVelocity *= fForce * ( 16.0f * (vDev*vDev*0.5f) );
+
+ #if __EXPLOSION_DEBUG
+ debugoverlay->AddLineOverlay( m_vecOrigin, m_vecOrigin + pParticle->m_vecVelocity, 255, 0, 0, false, 3 );
+ #endif
+
+ int nColor = random->RandomInt( 128, 255 );
+ pParticle->m_uchColor[0] = pParticle->m_uchColor[1] = pParticle->m_uchColor[2] = nColor;
+
+ pParticle->m_uchStartSize = random->RandomInt( 32, 85 ) * vDev;
+
+ pParticle->m_uchStartSize = clamp( pParticle->m_uchStartSize, (uint8) 32, (uint8) 85 );
+
+ pParticle->m_uchEndSize = (int)((float)pParticle->m_uchStartSize * 1.5f);
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 0;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
+ }
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &data -
+//-----------------------------------------------------------------------------
+void HelicopterMegaBombCallback( const CEffectData &data )
+{
+ C_MegaBombExplosionEffect().Create( data.m_vOrigin, 1.0f, 1.0f, 0 );
+}
+
+DECLARE_CLIENT_EFFECT( "HelicopterMegaBomb", HelicopterMegaBombCallback );