diff options
| author | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:31:46 -0800 |
|---|---|---|
| committer | Jørgen P. Tjernø <[email protected]> | 2013-12-02 19:46:31 -0800 |
| commit | f56bb35301836e56582a575a75864392a0177875 (patch) | |
| tree | de61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/fx_explosion.cpp | |
| parent | Mark some more files as text. (diff) | |
| download | source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip | |
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/fx_explosion.cpp')
| -rw-r--r-- | mp/src/game/client/fx_explosion.cpp | 2836 |
1 files changed, 1418 insertions, 1418 deletions
diff --git a/mp/src/game/client/fx_explosion.cpp b/mp/src/game/client/fx_explosion.cpp index 722c42f1..ef322e8c 100644 --- a/mp/src/game/client/fx_explosion.cpp +++ b/mp/src/game/client/fx_explosion.cpp @@ -1,1418 +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 );
+//========= 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 ); |