From f56bb35301836e56582a575a75864392a0177875 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B8rgen=20P=2E=20Tjern=C3=B8?= Date: Mon, 2 Dec 2013 19:31:46 -0800 Subject: Fix line endings. WHAMMY. --- mp/src/game/client/fx_explosion.cpp | 2836 +++++++++++++++++------------------ 1 file changed, 1418 insertions(+), 1418 deletions(-) (limited to 'mp/src/game/client/fx_explosion.cpp') 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 ); -- cgit v1.2.3