aboutsummaryrefslogtreecommitdiff
path: root/mp/src/game/client/fx.cpp
diff options
context:
space:
mode:
authorJørgen P. Tjernø <[email protected]>2013-12-02 19:31:46 -0800
committerJørgen P. Tjernø <[email protected]>2013-12-02 19:46:31 -0800
commitf56bb35301836e56582a575a75864392a0177875 (patch)
treede61ddd39de3e7df52759711950b4c288592f0dc /mp/src/game/client/fx.cpp
parentMark some more files as text. (diff)
downloadsource-sdk-2013-f56bb35301836e56582a575a75864392a0177875.tar.xz
source-sdk-2013-f56bb35301836e56582a575a75864392a0177875.zip
Fix line endings. WHAMMY.
Diffstat (limited to 'mp/src/game/client/fx.cpp')
-rw-r--r--mp/src/game/client/fx.cpp2656
1 files changed, 1328 insertions, 1328 deletions
diff --git a/mp/src/game/client/fx.cpp b/mp/src/game/client/fx.cpp
index 41a75c9a..b7f12cbd 100644
--- a/mp/src/game/client/fx.cpp
+++ b/mp/src/game/client/fx.cpp
@@ -1,1328 +1,1328 @@
-//========= Copyright Valve Corporation, All rights reserved. ============//
-//
-// Purpose:
-//
-// $Workfile: $
-// $NoKeywords: $
-//=============================================================================//
-#include "cbase.h"
-#include "engine/IEngineSound.h"
-#include "particles_simple.h"
-#include "particles_localspace.h"
-#include "dlight.h"
-#include "iefx.h"
-#include "clientsideeffects.h"
-#include "clienteffectprecachesystem.h"
-#include "glow_overlay.h"
-#include "effect_dispatch_data.h"
-#include "c_te_effect_dispatch.h"
-#include "tier0/vprof.h"
-#include "tier1/KeyValues.h"
-#include "effect_color_tables.h"
-#include "iviewrender_beams.h"
-#include "view.h"
-#include "IEffects.h"
-#include "fx.h"
-#include "c_te_legacytempents.h"
-#include "toolframework_client.h"
-
-// memdbgon must be the last include file in a .cpp file!!!
-#include "tier0/memdbgon.h"
-
-//Precahce the effects
-#ifndef TF_CLIENT_DLL
-CLIENTEFFECT_REGISTER_BEGIN( PrecacheMuzzleFlash )
-CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" )
-CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" )
-CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" )
-CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" )
-#ifndef CSTRIKE_DLL
-CLIENTEFFECT_MATERIAL( "effects/bluemuzzle" )
-CLIENTEFFECT_MATERIAL( "effects/gunshipmuzzle" )
-CLIENTEFFECT_MATERIAL( "effects/gunshiptracer" )
-#ifndef HL2MP
-CLIENTEFFECT_MATERIAL( "effects/huntertracer" )
-#endif
-CLIENTEFFECT_MATERIAL( "sprites/physcannon_bluelight2" )
-CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" )
-CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" )
-CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" )
-#endif
-CLIENTEFFECT_REGISTER_END()
-#endif
-
-//Whether or not we should emit a dynamic light
-ConVar muzzleflash_light( "muzzleflash_light", "1", FCVAR_ARCHIVE );
-
-extern void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType );
-
-
-//===================================================================
-//===================================================================
-class CImpactOverlay : public CWarpOverlay
-{
-public:
-
- virtual bool Update( void )
- {
- m_flLifetime += gpGlobals->frametime;
-
- const float flTotalLifetime = 0.1f;
-
- if ( m_flLifetime < flTotalLifetime )
- {
- float flColorScale = 1.0f - ( m_flLifetime / flTotalLifetime );
-
- for( int i=0; i < m_nSprites; i++ )
- {
- m_Sprites[i].m_vColor = m_vBaseColors[i] * flColorScale;
-
- m_Sprites[i].m_flHorzSize += 1.0f * gpGlobals->frametime;
- m_Sprites[i].m_flVertSize += 1.0f * gpGlobals->frametime;
- }
-
- return true;
- }
-
- return false;
- }
-
-public:
-
- float m_flLifetime;
- Vector m_vBaseColors[MAX_SUN_LAYERS];
-
-};
-
-//-----------------------------------------------------------------------------
-// Purpose: Play random ricochet sound
-// Input : *pos -
-//-----------------------------------------------------------------------------
-void FX_RicochetSound( const Vector& pos )
-{
- Vector org = pos;
- CLocalPlayerFilter filter;
- C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "FX_RicochetSound.Ricochet", &org );
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : entityIndex -
-// attachmentIndex -
-// *origin -
-// *angles -
-// Output : Returns true on success, false on failure.
-//-----------------------------------------------------------------------------
-bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, Vector *origin, QAngle *angles )
-{
- // Validate our input
- if ( ( hEntity == INVALID_EHANDLE_INDEX ) || ( attachmentIndex < 1 ) )
- {
- if ( origin != NULL )
- {
- *origin = vec3_origin;
- }
-
- if ( angles != NULL )
- {
- *angles = QAngle(0,0,0);
- }
-
- return false;
- }
-
- // Get the actual entity
- IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( hEntity );
- if ( pRenderable )
- {
- Vector attachOrigin;
- QAngle attachAngles;
-
- // Find the attachment's matrix
- pRenderable->GetAttachment( attachmentIndex, attachOrigin, attachAngles );
-
- if ( origin != NULL )
- {
- *origin = attachOrigin;
- }
-
- if ( angles != NULL )
- {
- *angles = attachAngles;
- }
-
- return true;
- }
-
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : entityIndex -
-// attachmentIndex -
-// &transform -
-//-----------------------------------------------------------------------------
-bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, matrix3x4_t &transform )
-{
- Vector origin;
- QAngle angles;
-
- if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles ) )
- {
- AngleMatrix( angles, origin, transform );
- return true;
- }
-
- // Entity doesn't exist
- SetIdentityMatrix( transform );
- return false;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void FX_MuzzleEffect(
- const Vector &origin,
- const QAngle &angles,
- float scale,
- ClientEntityHandle_t hEntity,
- unsigned char *pFlashColor,
- bool bOneFrame )
-{
- VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
-
- CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
- pSimple->SetSortOrigin( origin );
-
- SimpleParticle *pParticle;
- Vector forward, offset;
-
- AngleVectors( angles, &forward );
- float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
-
- if ( flScale < 0.5f )
- {
- flScale = 0.5f;
- }
- else if ( flScale > 8.0f )
- {
- flScale = 8.0f;
- }
-
- //
- // Flash
- //
-
- int i;
- for ( i = 1; i < 9; i++ )
- {
- offset = origin + (forward * (i*2.0f*scale));
-
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
-
- if ( pParticle == NULL )
- return;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = /*bOneFrame ? 0.0001f : */0.1f;
-
- pParticle->m_vecVelocity.Init();
-
- if ( !pFlashColor )
- {
- pParticle->m_uchColor[0] = 255;
- pParticle->m_uchColor[1] = 255;
- pParticle->m_uchColor[2] = 255;
- }
- else
- {
- pParticle->m_uchColor[0] = pFlashColor[0];
- pParticle->m_uchColor[1] = pFlashColor[1];
- pParticle->m_uchColor[2] = pFlashColor[2];
- }
-
- pParticle->m_uchStartAlpha = 255;
- pParticle->m_uchEndAlpha = 128;
-
- pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
- pParticle->m_uchEndSize = pParticle->m_uchStartSize;
- pParticle->m_flRoll = random->RandomInt( 0, 360 );
- pParticle->m_flRollDelta = 0.0f;
- }
-
- //
- // Smoke
- //
-
- /*
- for ( i = 0; i < 4; i++ )
- {
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_smokegrenade" ), origin );
-
- if ( pParticle == NULL )
- return;
-
- alpha = random->RandomInt( 32, 84 );
- color = random->RandomInt( 64, 164 );
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
-
- pParticle->m_vecVelocity.Random( -0.5f, 0.5f );
- pParticle->m_vecVelocity += forward;
- VectorNormalize( pParticle->m_vecVelocity );
-
- pParticle->m_vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
- pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
-
- pParticle->m_uchColor[0] = color;
- pParticle->m_uchColor[1] = color;
- pParticle->m_uchColor[2] = color;
- pParticle->m_uchStartAlpha = alpha;
- pParticle->m_uchEndAlpha = 0;
- pParticle->m_uchStartSize = random->RandomInt( 4, 8 ) * flScale;
- pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
- pParticle->m_flRoll = random->RandomInt( 0, 360 );
- pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
- }
- */
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : scale -
-// attachmentIndex -
-// bOneFrame -
-//-----------------------------------------------------------------------------
-void FX_MuzzleEffectAttached(
- float scale,
- ClientEntityHandle_t hEntity,
- int attachmentIndex,
- unsigned char *pFlashColor,
- bool bOneFrame )
-{
- VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
-
- // If the material isn't available, let's not do anything.
- if ( g_Mat_SMG_Muzzleflash[0] == NULL )
- {
- return;
- }
-
- CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex );
- Assert( pSimple );
- if ( pSimple == NULL )
- return;
-
- // Lock our bounding box
- pSimple->GetBinding().SetBBox( -( Vector( 16, 16, 16 ) * scale ), ( Vector( 16, 16, 16 ) * scale ) );
-
- SimpleParticle *pParticle;
- Vector forward(1,0,0), offset;
-
- float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
-
- if ( flScale < 0.5f )
- {
- flScale = 0.5f;
- }
- else if ( flScale > 8.0f )
- {
- flScale = 8.0f;
- }
-
- //
- // Flash
- //
-
- int i;
- for ( i = 1; i < 9; i++ )
- {
- offset = (forward * (i*2.0f*scale));
-
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[random->RandomInt(0,3)], offset );
-
- if ( pParticle == NULL )
- return;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = bOneFrame ? 0.0001f : 0.1f;
-
- pParticle->m_vecVelocity.Init();
-
- if ( !pFlashColor )
- {
- pParticle->m_uchColor[0] = 255;
- pParticle->m_uchColor[1] = 255;
- pParticle->m_uchColor[2] = 255;
- }
- else
- {
- pParticle->m_uchColor[0] = pFlashColor[0];
- pParticle->m_uchColor[1] = pFlashColor[1];
- pParticle->m_uchColor[2] = pFlashColor[2];
- }
-
- pParticle->m_uchStartAlpha = 255;
- pParticle->m_uchEndAlpha = 128;
-
- pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
- pParticle->m_uchEndSize = pParticle->m_uchStartSize;
- pParticle->m_flRoll = random->RandomInt( 0, 360 );
- pParticle->m_flRollDelta = 0.0f;
- }
-
-
- if ( !ToolsEnabled() )
- return;
-
- if ( !clienttools->IsInRecordingMode() )
- return;
-
- C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
- if ( pEnt )
- {
- pEnt->RecordToolMessage();
- }
-
- // NOTE: Particle system destruction message will be sent by the particle effect itself.
- int nId = pSimple->AllocateToolParticleEffectId();
-
- KeyValues *msg = new KeyValues( "OldParticleSystem_Create" );
- msg->SetString( "name", "FX_MuzzleEffectAttached" );
- msg->SetInt( "id", nId );
- msg->SetFloat( "time", gpGlobals->curtime );
-
- KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true );
- pEmitter->SetInt( "count", 9 );
- pEmitter->SetFloat( "duration", 0 );
- pEmitter->SetString( "material", "effects/muzzleflash2" ); // FIXME - create DmeMultiMaterialSpriteEmitter to support the 4 materials of muzzleflash
- pEmitter->SetInt( "active", true );
-
- KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
-
- KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true );
- pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
- pPosition->SetInt( "attachmentIndex", attachmentIndex );
- pPosition->SetFloat( "linearOffsetX", 2.0f * scale );
-
- // TODO - create a DmeConstantLifetimeInitializer
- KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
- pLifetime->SetFloat( "minLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
- pLifetime->SetFloat( "maxLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
-
- KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
- pVelocity->SetFloat( "velocityX", 0.0f );
- pVelocity->SetFloat( "velocityY", 0.0f );
- pVelocity->SetFloat( "velocityZ", 0.0f );
-
- KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
- pRoll->SetFloat( "minRoll", 0.0f );
- pRoll->SetFloat( "maxRoll", 360.0f );
-
- // TODO - create a DmeConstantRollSpeedInitializer
- KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
- pRollSpeed->SetFloat( "minRollSpeed", 0.0f );
- pRollSpeed->SetFloat( "maxRollSpeed", 0.0f );
-
- // TODO - create a DmeConstantColorInitializer
- KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
- Color color( pFlashColor ? pFlashColor[ 0 ] : 255, pFlashColor ? pFlashColor[ 1 ] : 255, pFlashColor ? pFlashColor[ 2 ] : 255, 255 );
- pColor->SetColor( "color1", color );
- pColor->SetColor( "color2", color );
-
- // TODO - create a DmeConstantAlphaInitializer
- KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
- pAlpha->SetInt( "minStartAlpha", 255 );
- pAlpha->SetInt( "maxStartAlpha", 255 );
- pAlpha->SetInt( "minEndAlpha", 128 );
- pAlpha->SetInt( "maxEndAlpha", 128 );
-
- // size = rand(6..9) * indexed(12/9..4/9) * flScale = rand(6..9) * ( 4f + f * i )
- KeyValues *pSize = pInitializers->FindKey( "DmeMuzzleFlashSizeInitializer", true );
- float f = flScale / 9.0f;
- pSize->SetFloat( "indexedBase", 4.0f * f );
- pSize->SetFloat( "indexedDelta", f );
- pSize->SetFloat( "minRandomFactor", 6.0f );
- pSize->SetFloat( "maxRandomFactor", 9.0f );
-
-/*
- KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
-
- pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
- pUpdaters->FindKey( "DmeRollUpdater", true );
- pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
- pUpdaters->FindKey( "DmeSizeUpdater", true );
-*/
- ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
- msg->deleteThis();
-}
-
-//-----------------------------------------------------------------------------
-// Old-style muzzle flashes
-//-----------------------------------------------------------------------------
-void MuzzleFlashCallback( const CEffectData &data )
-{
- Vector vecOrigin = data.m_vOrigin;
- QAngle vecAngles = data.m_vAngles;
- if ( data.entindex() > 0 )
- {
- IClientRenderable *pRenderable = data.GetRenderable();
- if ( !pRenderable )
- return;
-
- if ( data.m_nAttachmentIndex )
- {
- //FIXME: We also need to allocate these particles into an attachment space setup
- pRenderable->GetAttachment( data.m_nAttachmentIndex, vecOrigin, vecAngles );
- }
- else
- {
- vecOrigin = pRenderable->GetRenderOrigin();
- vecAngles = pRenderable->GetRenderAngles();
- }
- }
-
- tempents->MuzzleFlash( vecOrigin, vecAngles, data.m_fFlags & (~MUZZLEFLASH_FIRSTPERSON), data.m_hEntity, (data.m_fFlags & MUZZLEFLASH_FIRSTPERSON) != 0 );
-}
-
-DECLARE_CLIENT_EFFECT( "MuzzleFlash", MuzzleFlashCallback );
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : &origin -
-// &velocity -
-// scale -
-// numParticles -
-// *pColor -
-// iAlpha -
-// *pMaterial -
-// flRoll -
-// flRollDelta -
-//-----------------------------------------------------------------------------
-CSmartPtr<CSimpleEmitter> FX_Smoke( const Vector &origin, const Vector &velocity, float scale, int numParticles, float flDietime, unsigned char *pColor, int iAlpha, const char *pMaterial, float flRoll, float flRollDelta )
-{
- VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Smoke" );
- pSimple->SetSortOrigin( origin );
-
- SimpleParticle *pParticle;
-
- // Smoke
- for ( int i = 0; i < numParticles; i++ )
- {
- PMaterialHandle hMaterial = pSimple->GetPMaterial( pMaterial );
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
- if ( pParticle == NULL )
- return NULL;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = flDietime;
- pParticle->m_vecVelocity = velocity;
- for( int i = 0; i < 3; ++i )
- {
- pParticle->m_uchColor[i] = pColor[i];
- }
- pParticle->m_uchStartAlpha = iAlpha;
- pParticle->m_uchEndAlpha = 0;
- pParticle->m_uchStartSize = scale;
- pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
- pParticle->m_flRoll = flRoll;
- pParticle->m_flRollDelta = flRollDelta;
- }
-
- return pSimple;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Smoke puffs
-//-----------------------------------------------------------------------------
-void FX_Smoke( const Vector &origin, const QAngle &angles, float scale, int numParticles, unsigned char *pColor, int iAlpha )
-{
- VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- Vector vecVelocity;
- Vector vecForward;
-
- // Smoke
- for ( int i = 0; i < numParticles; i++ )
- {
- // Velocity
- AngleVectors( angles, &vecForward );
- vecVelocity.Random( -0.5f, 0.5f );
- vecVelocity += vecForward;
- VectorNormalize( vecVelocity );
- vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
- vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
-
- // Color
- unsigned char particlecolor[3];
- if ( !pColor )
- {
- int color = random->RandomInt( 64, 164 );
- particlecolor[0] = color;
- particlecolor[1] = color;
- particlecolor[2] = color;
- }
- else
- {
- particlecolor[0] = pColor[0];
- particlecolor[1] = pColor[1];
- particlecolor[2] = pColor[2];
- }
-
- // Alpha
- int alpha = iAlpha;
- if ( alpha == -1 )
- {
- alpha = random->RandomInt( 10, 25 );
- }
-
- // Scale
- int iSize = random->RandomInt( 4, 8 ) * scale;
-
- // Roll
- float flRoll = random->RandomInt( 0, 360 );
- float flRollDelta = random->RandomFloat( -4.0f, 4.0f );
-
- //pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
-
- FX_Smoke( origin, vecVelocity, iSize, 1, random->RandomFloat( 0.5f, 1.0f ), particlecolor, alpha, "particle/particle_smokegrenade", flRoll, flRollDelta );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Smoke Emitter
-// This is an emitter that keeps spitting out particles for its lifetime
-// It won't create particles if it's not in view, so it's best when short lived
-//-----------------------------------------------------------------------------
-class CSmokeEmitter : public CSimpleEmitter
-{
- typedef CSimpleEmitter BaseClass;
-public:
- CSmokeEmitter( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName ) : CSimpleEmitter( pDebugName )
- {
- m_hEntity = hEntity;
- m_nAttachmentIndex = nAttachment;
- m_flDeathTime = 0;
- m_flLastParticleSpawnTime = 0;
- }
-
- // Create
- static CSmokeEmitter *Create( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName="smoke" )
- {
- return new CSmokeEmitter( hEntity, nAttachment, pDebugName );
- }
-
- void SetLifeTime( float flTime )
- {
- m_flDeathTime = gpGlobals->curtime + flTime;
- }
-
- void SetSpurtAngle( QAngle &vecAngles )
- {
- AngleVectors( vecAngles, &m_vecSpurtForward );
- }
-
- void SetSpurtColor( const Vector4D &pColor )
- {
- for ( int i = 0; i <= 3; i++ )
- {
- m_SpurtColor[i] = pColor[i];
- }
- }
-
- void SetSpawnRate( float flRate )
- {
- m_flSpawnRate = flRate;
- }
-
- void CreateSpurtParticles( void )
- {
- SimpleParticle *pParticle;
- // PMaterialHandle hMaterial = GetPMaterial( "particle/particle_smokegrenade" );
-
- Vector vecOrigin = m_vSortOrigin;
- IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle(m_hEntity);
- if ( pRenderable && m_nAttachmentIndex )
- {
- QAngle tmp;
- pRenderable->GetAttachment( m_nAttachmentIndex, vecOrigin, tmp );
- SetSortOrigin( vecOrigin );
- }
-
- // Smoke
- int numParticles = RandomInt( 1,2 );
- for ( int i = 0; i < numParticles; i++ )
- {
- pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], vecOrigin );
- if ( pParticle == NULL )
- break;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = RandomFloat( 0.5, 1.0 );
-
- // Random velocity around the angles forward
- Vector vecVelocity;
- vecVelocity.Random( -0.1f, 0.1f );
- vecVelocity += m_vecSpurtForward;
- VectorNormalize( vecVelocity );
- vecVelocity *= RandomFloat( 160.0f, 640.0f );
- pParticle->m_vecVelocity = vecVelocity;
-
- // Randomize the color a little
- int color[3][2];
- for( int i = 0; i < 3; ++i )
- {
- color[i][0] = MAX( 0, m_SpurtColor[i] - 64 );
- color[i][1] = MIN( 255, m_SpurtColor[i] + 64 );
- }
- pParticle->m_uchColor[0] = random->RandomInt( color[0][0], color[0][1] );
- pParticle->m_uchColor[1] = random->RandomInt( color[1][0], color[1][1] );
- pParticle->m_uchColor[2] = random->RandomInt( color[2][0], color[2][1] );
-
- pParticle->m_uchStartAlpha = m_SpurtColor[3];
- pParticle->m_uchEndAlpha = 0;
- pParticle->m_uchStartSize = RandomInt( 50, 60 );
- pParticle->m_uchEndSize = pParticle->m_uchStartSize*3;
- pParticle->m_flRoll = RandomFloat( 0, 360 );
- pParticle->m_flRollDelta = RandomFloat( -4.0f, 4.0f );
- }
-
- m_flLastParticleSpawnTime = gpGlobals->curtime + m_flSpawnRate;
- }
-
- virtual void SimulateParticles( CParticleSimulateIterator *pIterator )
- {
- Particle *pParticle = pIterator->GetFirst();
- while ( pParticle )
- {
- // If our lifetime isn't up, create more particles
- if ( m_flDeathTime > gpGlobals->curtime )
- {
- if ( m_flLastParticleSpawnTime <= gpGlobals->curtime )
- {
- CreateSpurtParticles();
- }
- }
-
- pParticle = pIterator->GetNext();
- }
-
- BaseClass::SimulateParticles( pIterator );
- }
-
-
-private:
- float m_flDeathTime;
- float m_flLastParticleSpawnTime;
- float m_flSpawnRate;
- Vector m_vecSpurtForward;
- Vector4D m_SpurtColor;
- ClientEntityHandle_t m_hEntity;
- int m_nAttachmentIndex;
-
- CSmokeEmitter( const CSmokeEmitter & ); // not defined, not accessible
-};
-
-//-----------------------------------------------------------------------------
-// Purpose: Small hose gas spurt
-//-----------------------------------------------------------------------------
-void FX_BuildSmoke( Vector &vecOrigin, QAngle &vecAngles, ClientEntityHandle_t hEntity, int nAttachment, float flLifeTime, const Vector4D &pColor )
-{
- CSmartPtr<CSmokeEmitter> pSimple = CSmokeEmitter::Create( hEntity, nAttachment, "FX_Smoke" );
- pSimple->SetSortOrigin( vecOrigin );
- pSimple->SetLifeTime( flLifeTime );
- pSimple->SetSpurtAngle( vecAngles );
- pSimple->SetSpurtColor( pColor );
- pSimple->SetSpawnRate( 0.03 );
- pSimple->CreateSpurtParticles();
-}
-
-//-----------------------------------------------------------------------------
-// Purpose: Green hose gas spurt
-//-----------------------------------------------------------------------------
-void SmokeCallback( const CEffectData &data )
-{
- Vector vecOrigin = data.m_vOrigin;
- QAngle vecAngles = data.m_vAngles;
-
- Vector4D color( 50,50,50,255 );
- FX_BuildSmoke( vecOrigin, vecAngles, data.m_hEntity, data.m_nAttachmentIndex, 100.0, color );
-}
-
-DECLARE_CLIENT_EFFECT( "Smoke", SmokeCallback );
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Shockwave for gunship bullet impacts!
-// Input : &pos -
-//
-// NOTES: -Don't draw this effect when the viewer is very far away.
-//-----------------------------------------------------------------------------
-void FX_GunshipImpact( const Vector &pos, const Vector &normal, float r, float g, float b )
-{
- VPROF_BUDGET( "FX_GunshipImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- if ( CImpactOverlay *pOverlay = new CImpactOverlay )
- {
- pOverlay->m_flLifetime = 0;
- VectorMA( pos, 1.0f, normal, pOverlay->m_vPos ); // Doesn't show up on terrain if you don't do this(sjb)
- pOverlay->m_nSprites = 1;
-
- pOverlay->m_vBaseColors[0].Init( r, g, b );
-
- pOverlay->m_Sprites[0].m_flHorzSize = 0.01f;
- pOverlay->m_Sprites[0].m_flVertSize = 0.01f;
-
- pOverlay->Activate();
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : data -
-//-----------------------------------------------------------------------------
-void GunshipImpactCallback( const CEffectData & data )
-{
- Vector vecPosition;
-
- vecPosition = data.m_vOrigin;
-
- FX_GunshipImpact( vecPosition, Vector( 0, 0, 1 ), 100, 0, 200 );
-}
-DECLARE_CLIENT_EFFECT( "GunshipImpact", GunshipImpactCallback );
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void CommandPointerCallback( const CEffectData & data )
-{
- int size = COLOR_TABLE_SIZE( commandercolors );
-
- for( int i = 0 ; i < size ; i++ )
- {
- if( commandercolors[ i ].index == data.m_nColor )
- {
- FX_GunshipImpact( data.m_vOrigin, Vector( 0, 0, 1 ), commandercolors[ i ].r, commandercolors[ i ].g, commandercolors[ i ].b );
- return;
- }
- }
-}
-
-DECLARE_CLIENT_EFFECT( "CommandPointer", CommandPointerCallback );
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-//-----------------------------------------------------------------------------
-void FX_GunshipMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
-{
- VPROF_BUDGET( "FX_GunshipMuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
- pSimple->SetSortOrigin( origin );
-
- SimpleParticle *pParticle;
- Vector forward, offset;
-
- AngleVectors( angles, &forward );
-
- //
- // Flash
- //
- offset = origin;
-
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/gunshipmuzzle" ), offset );
-
- if ( pParticle == NULL )
- return;
-
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = 0.15f;
-
- pParticle->m_vecVelocity.Init();
-
- pParticle->m_uchStartSize = random->RandomFloat( 40.0, 50.0 );
- pParticle->m_uchEndSize = pParticle->m_uchStartSize;
-
- pParticle->m_flRoll = random->RandomInt( 0, 360 );
- pParticle->m_flRollDelta = 0.15f;
-
- pParticle->m_uchColor[0] = 255;
- pParticle->m_uchColor[1] = 255;
- pParticle->m_uchColor[2] = 255;
-
- pParticle->m_uchStartAlpha = 255;
- pParticle->m_uchEndAlpha = 255;
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : start -
-// end -
-// velocity -
-// makeWhiz -
-//-----------------------------------------------------------------------------
-void FX_GunshipTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
-{
- VPROF_BUDGET( "FX_GunshipTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- Vector vNear, dStart, dEnd, shotDir;
- float totalDist;
-
- //Get out shot direction and length
- VectorSubtract( end, start, shotDir );
- totalDist = VectorNormalize( shotDir );
-
- //Don't make small tracers
- if ( totalDist <= 256 )
- return;
-
- float length = random->RandomFloat( 128.0f, 256.0f );
- float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
-
- //Add it
- FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 5.0f, life, "effects/gunshiptracer" );
-
- if( makeWhiz )
- {
- FX_TracerSound( start, end, TRACER_TYPE_GUNSHIP );
- }
-}
-
-//-----------------------------------------------------------------------------
-//-----------------------------------------------------------------------------
-void FX_StriderMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
-{
- Vector vecDir;
- AngleVectors( angles, &vecDir );
-
- float life = 0.3f;
- float speed = 100.0f;
-
- for( int i = 0 ; i < 5 ; i++ )
- {
- FX_AddDiscreetLine( origin, vecDir, speed, 32, speed * life, 5.0f, life, "effects/bluespark" );
- speed *= 1.5f;
- }
-}
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : start -
-// end -
-// velocity -
-// makeWhiz -
-//-----------------------------------------------------------------------------
-void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
-{
- VPROF_BUDGET( "FX_StriderTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- Vector vNear, dStart, dEnd, shotDir;
- float totalDist;
-
- //Get out shot direction and length
- VectorSubtract( end, start, shotDir );
- totalDist = VectorNormalize( shotDir );
-
- //Don't make small tracers
- if ( totalDist <= 256 )
- return;
-
- float length = random->RandomFloat( 64.0f, 128.0f );
- float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
-
- //Add it
- FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 2.5f, life, "effects/gunshiptracer" );
-
- if( makeWhiz )
- {
- FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : start -
-// end -
-// velocity -
-// makeWhiz -
-//-----------------------------------------------------------------------------
-void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
-{
- VPROF_BUDGET( "FX_HunterTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- Vector vNear, dStart, dEnd, shotDir;
- float totalDist;
-
- // Get out shot direction and length
- VectorSubtract( end, start, shotDir );
- totalDist = VectorNormalize( shotDir );
-
- // Make short tracers in close quarters
- // float flMinLength = MIN( totalDist, 128.0f );
- // float flMaxLength = MIN( totalDist, 128.0f );
-
- float length = 128.0f;//random->RandomFloat( flMinLength, flMaxLength );
- float life = ( totalDist + length ) / velocity; // NOTENOTE: We want the tail to finish its run as well
-
- // Add it
- FX_AddDiscreetLine( start, shotDir, velocity*0.5f, length, totalDist, 2.0f, life, "effects/huntertracer" );
-
- if( makeWhiz )
- {
- FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose:
-// Input : start -
-// end -
-// velocity -
-// makeWhiz -
-//-----------------------------------------------------------------------------
-void FX_GaussTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
-{
- VPROF_BUDGET( "FX_GaussTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
- Vector vNear, dStart, dEnd, shotDir;
- float totalDist;
-
- //Get out shot direction and length
- VectorSubtract( end, start, shotDir );
- totalDist = VectorNormalize( shotDir );
-
- //Don't make small tracers
- if ( totalDist <= 256 )
- return;
-
- float length = random->RandomFloat( 250.0f, 500.0f );
- float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
-
- //Add it
- FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, random->RandomFloat( 5.0f, 8.0f ), life, "effects/spark" );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Create a tesla effect between two points
-//-----------------------------------------------------------------------------
-void FX_BuildTesla(
- C_BaseEntity *pEntity,
- const Vector &vecOrigin,
- const Vector &vecEnd,
- const char *pModelName,
- float flBeamWidth,
- const Vector &vColor,
- int nFlags,
- float flTimeVisible )
-{
- BeamInfo_t beamInfo;
- beamInfo.m_nType = TE_BEAMTESLA;
- beamInfo.m_vecStart = vecOrigin;
- beamInfo.m_vecEnd = vecEnd;
- beamInfo.m_pszModelName = pModelName;
- beamInfo.m_flHaloScale = 0.0;
- beamInfo.m_flLife = flTimeVisible;
- beamInfo.m_flWidth = flBeamWidth;
- beamInfo.m_flEndWidth = 1;
- beamInfo.m_flFadeLength = 0.3;
- beamInfo.m_flAmplitude = 16;
- beamInfo.m_flBrightness = 200.0;
- beamInfo.m_flSpeed = 0.0;
- beamInfo.m_nStartFrame = 0.0;
- beamInfo.m_flFrameRate = 1.0;
- beamInfo.m_flRed = vColor.x * 255.0;
- beamInfo.m_flGreen = vColor.y * 255.0;
- beamInfo.m_flBlue = vColor.z * 255.0;
- beamInfo.m_nSegments = 20;
- beamInfo.m_bRenderable = true;
- beamInfo.m_nFlags = nFlags;
-
- beams->CreateBeamPoints( beamInfo );
-}
-
-void FX_Tesla( const CTeslaInfo &teslaInfo )
-{
- C_BaseEntity *pEntity = ClientEntityList().GetEnt( teslaInfo.m_nEntIndex );
-
- // Send out beams around us
- int iNumBeamsAround = (teslaInfo.m_nBeams * 2) / 3; // (2/3 of the beams are placed around in a circle)
- int iNumRandomBeams = teslaInfo.m_nBeams - iNumBeamsAround;
- int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
- float flYawOffset = RandomFloat(0,360);
- for ( int i = 0; i < iTotalBeams; i++ )
- {
- // Make a couple of tries at it
- int iTries = -1;
- Vector vecForward;
- trace_t tr;
- do
- {
- iTries++;
-
- // Some beams are deliberatly aimed around the point, the rest are random.
- if ( i < iNumBeamsAround )
- {
- QAngle vecTemp = teslaInfo.m_vAngles;
- vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
- AngleVectors( vecTemp, &vecForward );
-
- // Randomly angle it up or down
- vecForward.z = RandomFloat( -1, 1 );
- }
- else
- {
- vecForward = RandomVector( -1, 1 );
- }
- VectorNormalize( vecForward );
-
- UTIL_TraceLine( teslaInfo.m_vPos, teslaInfo.m_vPos + (vecForward * teslaInfo.m_flRadius), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
- } while ( tr.fraction >= 1.0 && iTries < 3 );
-
- Vector vecEnd = tr.endpos - (vecForward * 8);
-
- // Only spark & glow if we hit something
- if ( tr.fraction < 1.0 )
- {
- if ( !EffectOccluded( tr.endpos, 0 ) )
- {
- // Move it towards the camera
- Vector vecFlash = tr.endpos;
- Vector vecForward;
- AngleVectors( MainViewAngles(), &vecForward );
- vecFlash -= (vecForward * 8);
-
- g_pEffects->EnergySplash( vecFlash, -vecForward, false );
-
- // End glow
- CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
- pSimple->SetSortOrigin( vecFlash );
- SimpleParticle *pParticle;
- pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
- if ( pParticle != NULL )
- {
- pParticle->m_flLifetime = 0.0f;
- pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
- pParticle->m_vecVelocity = vec3_origin;
- Vector color( 1,1,1 );
- float colorRamp = RandomFloat( 0.75f, 1.25f );
- pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
- pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
- pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
- pParticle->m_uchStartSize = RandomFloat( 6,13 );
- pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
- pParticle->m_uchStartAlpha = 255;
- pParticle->m_uchEndAlpha = 10;
- pParticle->m_flRoll = RandomFloat( 0,360 );
- pParticle->m_flRollDelta = 0;
- }
- }
- }
-
- // Build the tesla
- FX_BuildTesla( pEntity, teslaInfo.m_vPos, tr.endpos, teslaInfo.m_pszSpriteName, teslaInfo.m_flBeamWidth, teslaInfo.m_vColor, FBEAM_ONLYNOISEONCE, teslaInfo.m_flTimeVisible );
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Tesla effect
-//-----------------------------------------------------------------------------
-void BuildTeslaCallback( const CEffectData &data )
-{
- if ( data.entindex() < 0 )
- return;
-
- CTeslaInfo teslaInfo;
-
- teslaInfo.m_vPos = data.m_vOrigin;
- teslaInfo.m_vAngles = data.m_vAngles;
- teslaInfo.m_nEntIndex = data.entindex();
- teslaInfo.m_flBeamWidth = 5;
- teslaInfo.m_vColor.Init( 1, 1, 1 );
- teslaInfo.m_flTimeVisible = 0.3;
- teslaInfo.m_flRadius = 192;
- teslaInfo.m_nBeams = 6;
- teslaInfo.m_pszSpriteName = "sprites/physbeam.vmt";
-
- FX_Tesla( teslaInfo );
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Tesla hitbox
-//-----------------------------------------------------------------------------
-void FX_BuildTeslaHitbox(
- C_BaseEntity *pEntity,
- int nStartAttachment,
- int nEndAttachment,
- float flBeamWidth,
- const Vector &vColor,
- float flTimeVisible )
-{
- // One along the body
- BeamInfo_t beamInfo;
- beamInfo.m_nType = TE_BEAMTESLA;
- beamInfo.m_vecStart = vec3_origin;
- beamInfo.m_vecEnd = vec3_origin;
- beamInfo.m_pszModelName = "sprites/lgtning.vmt";
- beamInfo.m_flHaloScale = 8.0f;
- beamInfo.m_flLife = 0.01f;
- beamInfo.m_flWidth = random->RandomFloat( 3.0f, 6.0f );
- beamInfo.m_flEndWidth = 0.0f;
- beamInfo.m_flFadeLength = 0.0f;
- beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
- beamInfo.m_flBrightness = 255.0f;
- beamInfo.m_flSpeed = 32.0;
- beamInfo.m_nStartFrame = 0.0;
- beamInfo.m_flFrameRate = 30.0;
- beamInfo.m_flRed = vColor.x * 255.0;
- beamInfo.m_flGreen = vColor.y * 255.0;
- beamInfo.m_flBlue = vColor.z * 255.0;
- beamInfo.m_nSegments = 32;
- beamInfo.m_bRenderable = true;
- beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
-
- beamInfo.m_nFlags = (FBEAM_USE_HITBOXES);
-
- beamInfo.m_pStartEnt = pEntity;
- beamInfo.m_nStartAttachment = nStartAttachment;
- beamInfo.m_pEndEnt = pEntity;
- beamInfo.m_nEndAttachment = nEndAttachment;
-
- beams->CreateBeamEntPoint( beamInfo );
-
- // One out to the world
- trace_t tr;
- Vector randomDir;
-
- randomDir = RandomVector( -1.0f, 1.0f );
- VectorNormalize( randomDir );
-
- UTIL_TraceLine( pEntity->WorldSpaceCenter(), pEntity->WorldSpaceCenter() + ( randomDir * 100 ), MASK_SOLID_BRUSHONLY, pEntity, COLLISION_GROUP_NONE, &tr );
-
- if ( tr.fraction < 1.0f )
- {
- beamInfo.m_nType = TE_BEAMTESLA;
- beamInfo.m_vecStart = vec3_origin;
- beamInfo.m_vecEnd = tr.endpos;
- beamInfo.m_pszModelName = "sprites/lgtning.vmt";
- beamInfo.m_flHaloScale = 8.0f;
- beamInfo.m_flLife = 0.05f;
- beamInfo.m_flWidth = random->RandomFloat( 2.0f, 6.0f );
- beamInfo.m_flEndWidth = 0.0f;
- beamInfo.m_flFadeLength = 0.0f;
- beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
- beamInfo.m_flBrightness = 255.0f;
- beamInfo.m_flSpeed = 32.0;
- beamInfo.m_nStartFrame = 0.0;
- beamInfo.m_flFrameRate = 30.0;
- beamInfo.m_flRed = vColor.x * 255.0;
- beamInfo.m_flGreen = vColor.y * 255.0;
- beamInfo.m_flBlue = vColor.z * 255.0;
- beamInfo.m_nSegments = 32;
- beamInfo.m_bRenderable = true;
- beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
-
- beamInfo.m_pStartEnt = pEntity;
- beamInfo.m_nStartAttachment = nStartAttachment;
-
- beams->CreateBeamEntPoint( beamInfo );
- }
-
- // Create an elight to illuminate the target
- if ( pEntity != NULL )
- {
- dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_TE_DYNAMIC + pEntity->entindex() );
-
- // Randomly place it
- el->origin = pEntity->WorldSpaceCenter() + RandomVector( -32, 32 );
-
- el->color.r = 235;
- el->color.g = 235;
- el->color.b = 255;
- el->color.exponent = 4;
-
- el->radius = random->RandomInt( 32, 128 );
- el->decay = el->radius / 0.1f;
- el->die = gpGlobals->curtime + 0.1f;
- }
-}
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Tesla effect
-//-----------------------------------------------------------------------------
-void FX_BuildTeslaHitbox( const CEffectData &data )
-{
- Vector vColor( 1, 1, 1 );
-
- C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.entindex() );
- C_BaseAnimating *pAnimating = pEntity ? pEntity->GetBaseAnimating() : NULL;
- if (!pAnimating)
- return;
-
- studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
- if (!pStudioHdr)
- return;
-
- mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
- if ( !set )
- return;
-
- matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
- if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
- return;
-
- int nBeamCount = (int)(data.m_flMagnitude + 0.5f);
- for ( int i = 0; i < nBeamCount; ++i )
- {
- int nStartHitBox = random->RandomInt( 1, set->numhitboxes );
- int nEndHitBox = random->RandomInt( 1, set->numhitboxes );
- FX_BuildTeslaHitbox( pEntity, nStartHitBox, nEndHitBox, data.m_flScale, vColor, random->RandomFloat( 0.05f, 0.2f ) );
- }
-}
-
-DECLARE_CLIENT_EFFECT( "TeslaHitboxes", FX_BuildTeslaHitbox );
-
-
-//-----------------------------------------------------------------------------
-// Purpose: Tesla effect
-//-----------------------------------------------------------------------------
-void FX_BuildTeslaZap( const CEffectData &data )
-{
- // Build the tesla, only works on entities
- C_BaseEntity *pEntity = data.GetEntity();
- if ( !pEntity )
- return;
-
- Vector vColor( 1, 1, 1 );
-
- BeamInfo_t beamInfo;
- beamInfo.m_nType = TE_BEAMTESLA;
- beamInfo.m_pStartEnt = pEntity;
- beamInfo.m_nStartAttachment = data.m_nAttachmentIndex;
- beamInfo.m_pEndEnt = NULL;
- beamInfo.m_vecEnd = data.m_vOrigin;
- beamInfo.m_pszModelName = "sprites/physbeam.vmt";
- beamInfo.m_flHaloScale = 0.0;
- beamInfo.m_flLife = 0.3f;
- beamInfo.m_flWidth = data.m_flScale;
- beamInfo.m_flEndWidth = 1;
- beamInfo.m_flFadeLength = 0.3;
- beamInfo.m_flAmplitude = 16;
- beamInfo.m_flBrightness = 200.0;
- beamInfo.m_flSpeed = 0.0;
- beamInfo.m_nStartFrame = 0.0;
- beamInfo.m_flFrameRate = 1.0;
- beamInfo.m_flRed = vColor.x * 255.0;
- beamInfo.m_flGreen = vColor.y * 255.0;
- beamInfo.m_flBlue = vColor.z * 255.0;
- beamInfo.m_nSegments = 20;
- beamInfo.m_bRenderable = true;
- beamInfo.m_nFlags = 0;
-
- beams->CreateBeamEntPoint( beamInfo );
-}
-
-DECLARE_CLIENT_EFFECT( "TeslaZap", FX_BuildTeslaZap );
-
+//========= Copyright Valve Corporation, All rights reserved. ============//
+//
+// Purpose:
+//
+// $Workfile: $
+// $NoKeywords: $
+//=============================================================================//
+#include "cbase.h"
+#include "engine/IEngineSound.h"
+#include "particles_simple.h"
+#include "particles_localspace.h"
+#include "dlight.h"
+#include "iefx.h"
+#include "clientsideeffects.h"
+#include "clienteffectprecachesystem.h"
+#include "glow_overlay.h"
+#include "effect_dispatch_data.h"
+#include "c_te_effect_dispatch.h"
+#include "tier0/vprof.h"
+#include "tier1/KeyValues.h"
+#include "effect_color_tables.h"
+#include "iviewrender_beams.h"
+#include "view.h"
+#include "IEffects.h"
+#include "fx.h"
+#include "c_te_legacytempents.h"
+#include "toolframework_client.h"
+
+// memdbgon must be the last include file in a .cpp file!!!
+#include "tier0/memdbgon.h"
+
+//Precahce the effects
+#ifndef TF_CLIENT_DLL
+CLIENTEFFECT_REGISTER_BEGIN( PrecacheMuzzleFlash )
+CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" )
+CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" )
+CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" )
+CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" )
+#ifndef CSTRIKE_DLL
+CLIENTEFFECT_MATERIAL( "effects/bluemuzzle" )
+CLIENTEFFECT_MATERIAL( "effects/gunshipmuzzle" )
+CLIENTEFFECT_MATERIAL( "effects/gunshiptracer" )
+#ifndef HL2MP
+CLIENTEFFECT_MATERIAL( "effects/huntertracer" )
+#endif
+CLIENTEFFECT_MATERIAL( "sprites/physcannon_bluelight2" )
+CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" )
+CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" )
+CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_nocull" )
+#endif
+CLIENTEFFECT_REGISTER_END()
+#endif
+
+//Whether or not we should emit a dynamic light
+ConVar muzzleflash_light( "muzzleflash_light", "1", FCVAR_ARCHIVE );
+
+extern void FX_TracerSound( const Vector &start, const Vector &end, int iTracerType );
+
+
+//===================================================================
+//===================================================================
+class CImpactOverlay : public CWarpOverlay
+{
+public:
+
+ virtual bool Update( void )
+ {
+ m_flLifetime += gpGlobals->frametime;
+
+ const float flTotalLifetime = 0.1f;
+
+ if ( m_flLifetime < flTotalLifetime )
+ {
+ float flColorScale = 1.0f - ( m_flLifetime / flTotalLifetime );
+
+ for( int i=0; i < m_nSprites; i++ )
+ {
+ m_Sprites[i].m_vColor = m_vBaseColors[i] * flColorScale;
+
+ m_Sprites[i].m_flHorzSize += 1.0f * gpGlobals->frametime;
+ m_Sprites[i].m_flVertSize += 1.0f * gpGlobals->frametime;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+
+public:
+
+ float m_flLifetime;
+ Vector m_vBaseColors[MAX_SUN_LAYERS];
+
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Play random ricochet sound
+// Input : *pos -
+//-----------------------------------------------------------------------------
+void FX_RicochetSound( const Vector& pos )
+{
+ Vector org = pos;
+ CLocalPlayerFilter filter;
+ C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, "FX_RicochetSound.Ricochet", &org );
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : entityIndex -
+// attachmentIndex -
+// *origin -
+// *angles -
+// Output : Returns true on success, false on failure.
+//-----------------------------------------------------------------------------
+bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, Vector *origin, QAngle *angles )
+{
+ // Validate our input
+ if ( ( hEntity == INVALID_EHANDLE_INDEX ) || ( attachmentIndex < 1 ) )
+ {
+ if ( origin != NULL )
+ {
+ *origin = vec3_origin;
+ }
+
+ if ( angles != NULL )
+ {
+ *angles = QAngle(0,0,0);
+ }
+
+ return false;
+ }
+
+ // Get the actual entity
+ IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( hEntity );
+ if ( pRenderable )
+ {
+ Vector attachOrigin;
+ QAngle attachAngles;
+
+ // Find the attachment's matrix
+ pRenderable->GetAttachment( attachmentIndex, attachOrigin, attachAngles );
+
+ if ( origin != NULL )
+ {
+ *origin = attachOrigin;
+ }
+
+ if ( angles != NULL )
+ {
+ *angles = attachAngles;
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : entityIndex -
+// attachmentIndex -
+// &transform -
+//-----------------------------------------------------------------------------
+bool FX_GetAttachmentTransform( ClientEntityHandle_t hEntity, int attachmentIndex, matrix3x4_t &transform )
+{
+ Vector origin;
+ QAngle angles;
+
+ if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles ) )
+ {
+ AngleMatrix( angles, origin, transform );
+ return true;
+ }
+
+ // Entity doesn't exist
+ SetIdentityMatrix( transform );
+ return false;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void FX_MuzzleEffect(
+ const Vector &origin,
+ const QAngle &angles,
+ float scale,
+ ClientEntityHandle_t hEntity,
+ unsigned char *pFlashColor,
+ bool bOneFrame )
+{
+ VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
+ pSimple->SetSortOrigin( origin );
+
+ SimpleParticle *pParticle;
+ Vector forward, offset;
+
+ AngleVectors( angles, &forward );
+ float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
+
+ if ( flScale < 0.5f )
+ {
+ flScale = 0.5f;
+ }
+ else if ( flScale > 8.0f )
+ {
+ flScale = 8.0f;
+ }
+
+ //
+ // Flash
+ //
+
+ int i;
+ for ( i = 1; i < 9; i++ )
+ {
+ offset = origin + (forward * (i*2.0f*scale));
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/muzzleflash%d", random->RandomInt(1,4) ) ), offset );
+
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = /*bOneFrame ? 0.0001f : */0.1f;
+
+ pParticle->m_vecVelocity.Init();
+
+ if ( !pFlashColor )
+ {
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+ }
+ else
+ {
+ pParticle->m_uchColor[0] = pFlashColor[0];
+ pParticle->m_uchColor[1] = pFlashColor[1];
+ pParticle->m_uchColor[2] = pFlashColor[2];
+ }
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 128;
+
+ pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = 0.0f;
+ }
+
+ //
+ // Smoke
+ //
+
+ /*
+ for ( i = 0; i < 4; i++ )
+ {
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "particle/particle_smokegrenade" ), origin );
+
+ if ( pParticle == NULL )
+ return;
+
+ alpha = random->RandomInt( 32, 84 );
+ color = random->RandomInt( 64, 164 );
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
+
+ pParticle->m_vecVelocity.Random( -0.5f, 0.5f );
+ pParticle->m_vecVelocity += forward;
+ VectorNormalize( pParticle->m_vecVelocity );
+
+ pParticle->m_vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
+ pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
+
+ pParticle->m_uchColor[0] = color;
+ pParticle->m_uchColor[1] = color;
+ pParticle->m_uchColor[2] = color;
+ pParticle->m_uchStartAlpha = alpha;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = random->RandomInt( 4, 8 ) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+ }
+ */
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : scale -
+// attachmentIndex -
+// bOneFrame -
+//-----------------------------------------------------------------------------
+void FX_MuzzleEffectAttached(
+ float scale,
+ ClientEntityHandle_t hEntity,
+ int attachmentIndex,
+ unsigned char *pFlashColor,
+ bool bOneFrame )
+{
+ VPROF_BUDGET( "FX_MuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+
+ // If the material isn't available, let's not do anything.
+ if ( g_Mat_SMG_Muzzleflash[0] == NULL )
+ {
+ return;
+ }
+
+ CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex );
+ Assert( pSimple );
+ if ( pSimple == NULL )
+ return;
+
+ // Lock our bounding box
+ pSimple->GetBinding().SetBBox( -( Vector( 16, 16, 16 ) * scale ), ( Vector( 16, 16, 16 ) * scale ) );
+
+ SimpleParticle *pParticle;
+ Vector forward(1,0,0), offset;
+
+ float flScale = random->RandomFloat( scale-0.25f, scale+0.25f );
+
+ if ( flScale < 0.5f )
+ {
+ flScale = 0.5f;
+ }
+ else if ( flScale > 8.0f )
+ {
+ flScale = 8.0f;
+ }
+
+ //
+ // Flash
+ //
+
+ int i;
+ for ( i = 1; i < 9; i++ )
+ {
+ offset = (forward * (i*2.0f*scale));
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[random->RandomInt(0,3)], offset );
+
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = bOneFrame ? 0.0001f : 0.1f;
+
+ pParticle->m_vecVelocity.Init();
+
+ if ( !pFlashColor )
+ {
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+ }
+ else
+ {
+ pParticle->m_uchColor[0] = pFlashColor[0];
+ pParticle->m_uchColor[1] = pFlashColor[1];
+ pParticle->m_uchColor[2] = pFlashColor[2];
+ }
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 128;
+
+ pParticle->m_uchStartSize = (random->RandomFloat( 6.0f, 9.0f ) * (12-(i))/9) * flScale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = 0.0f;
+ }
+
+
+ if ( !ToolsEnabled() )
+ return;
+
+ if ( !clienttools->IsInRecordingMode() )
+ return;
+
+ C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity );
+ if ( pEnt )
+ {
+ pEnt->RecordToolMessage();
+ }
+
+ // NOTE: Particle system destruction message will be sent by the particle effect itself.
+ int nId = pSimple->AllocateToolParticleEffectId();
+
+ KeyValues *msg = new KeyValues( "OldParticleSystem_Create" );
+ msg->SetString( "name", "FX_MuzzleEffectAttached" );
+ msg->SetInt( "id", nId );
+ msg->SetFloat( "time", gpGlobals->curtime );
+
+ KeyValues *pEmitter = msg->FindKey( "DmeSpriteEmitter", true );
+ pEmitter->SetInt( "count", 9 );
+ pEmitter->SetFloat( "duration", 0 );
+ pEmitter->SetString( "material", "effects/muzzleflash2" ); // FIXME - create DmeMultiMaterialSpriteEmitter to support the 4 materials of muzzleflash
+ pEmitter->SetInt( "active", true );
+
+ KeyValues *pInitializers = pEmitter->FindKey( "initializers", true );
+
+ KeyValues *pPosition = pInitializers->FindKey( "DmeLinearAttachedPositionInitializer", true );
+ pPosition->SetPtr( "entindex", (void*)pEnt->entindex() );
+ pPosition->SetInt( "attachmentIndex", attachmentIndex );
+ pPosition->SetFloat( "linearOffsetX", 2.0f * scale );
+
+ // TODO - create a DmeConstantLifetimeInitializer
+ KeyValues *pLifetime = pInitializers->FindKey( "DmeRandomLifetimeInitializer", true );
+ pLifetime->SetFloat( "minLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
+ pLifetime->SetFloat( "maxLifetime", bOneFrame ? 1.0f / 24.0f : 0.1f );
+
+ KeyValues *pVelocity = pInitializers->FindKey( "DmeConstantVelocityInitializer", true );
+ pVelocity->SetFloat( "velocityX", 0.0f );
+ pVelocity->SetFloat( "velocityY", 0.0f );
+ pVelocity->SetFloat( "velocityZ", 0.0f );
+
+ KeyValues *pRoll = pInitializers->FindKey( "DmeRandomRollInitializer", true );
+ pRoll->SetFloat( "minRoll", 0.0f );
+ pRoll->SetFloat( "maxRoll", 360.0f );
+
+ // TODO - create a DmeConstantRollSpeedInitializer
+ KeyValues *pRollSpeed = pInitializers->FindKey( "DmeRandomRollSpeedInitializer", true );
+ pRollSpeed->SetFloat( "minRollSpeed", 0.0f );
+ pRollSpeed->SetFloat( "maxRollSpeed", 0.0f );
+
+ // TODO - create a DmeConstantColorInitializer
+ KeyValues *pColor = pInitializers->FindKey( "DmeRandomInterpolatedColorInitializer", true );
+ Color color( pFlashColor ? pFlashColor[ 0 ] : 255, pFlashColor ? pFlashColor[ 1 ] : 255, pFlashColor ? pFlashColor[ 2 ] : 255, 255 );
+ pColor->SetColor( "color1", color );
+ pColor->SetColor( "color2", color );
+
+ // TODO - create a DmeConstantAlphaInitializer
+ KeyValues *pAlpha = pInitializers->FindKey( "DmeRandomAlphaInitializer", true );
+ pAlpha->SetInt( "minStartAlpha", 255 );
+ pAlpha->SetInt( "maxStartAlpha", 255 );
+ pAlpha->SetInt( "minEndAlpha", 128 );
+ pAlpha->SetInt( "maxEndAlpha", 128 );
+
+ // size = rand(6..9) * indexed(12/9..4/9) * flScale = rand(6..9) * ( 4f + f * i )
+ KeyValues *pSize = pInitializers->FindKey( "DmeMuzzleFlashSizeInitializer", true );
+ float f = flScale / 9.0f;
+ pSize->SetFloat( "indexedBase", 4.0f * f );
+ pSize->SetFloat( "indexedDelta", f );
+ pSize->SetFloat( "minRandomFactor", 6.0f );
+ pSize->SetFloat( "maxRandomFactor", 9.0f );
+
+/*
+ KeyValues *pUpdaters = pEmitter->FindKey( "updaters", true );
+
+ pUpdaters->FindKey( "DmePositionVelocityUpdater", true );
+ pUpdaters->FindKey( "DmeRollUpdater", true );
+ pUpdaters->FindKey( "DmeAlphaLinearUpdater", true );
+ pUpdaters->FindKey( "DmeSizeUpdater", true );
+*/
+ ToolFramework_PostToolMessage( HTOOLHANDLE_INVALID, msg );
+ msg->deleteThis();
+}
+
+//-----------------------------------------------------------------------------
+// Old-style muzzle flashes
+//-----------------------------------------------------------------------------
+void MuzzleFlashCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+ if ( data.entindex() > 0 )
+ {
+ IClientRenderable *pRenderable = data.GetRenderable();
+ if ( !pRenderable )
+ return;
+
+ if ( data.m_nAttachmentIndex )
+ {
+ //FIXME: We also need to allocate these particles into an attachment space setup
+ pRenderable->GetAttachment( data.m_nAttachmentIndex, vecOrigin, vecAngles );
+ }
+ else
+ {
+ vecOrigin = pRenderable->GetRenderOrigin();
+ vecAngles = pRenderable->GetRenderAngles();
+ }
+ }
+
+ tempents->MuzzleFlash( vecOrigin, vecAngles, data.m_fFlags & (~MUZZLEFLASH_FIRSTPERSON), data.m_hEntity, (data.m_fFlags & MUZZLEFLASH_FIRSTPERSON) != 0 );
+}
+
+DECLARE_CLIENT_EFFECT( "MuzzleFlash", MuzzleFlashCallback );
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : &origin -
+// &velocity -
+// scale -
+// numParticles -
+// *pColor -
+// iAlpha -
+// *pMaterial -
+// flRoll -
+// flRollDelta -
+//-----------------------------------------------------------------------------
+CSmartPtr<CSimpleEmitter> FX_Smoke( const Vector &origin, const Vector &velocity, float scale, int numParticles, float flDietime, unsigned char *pColor, int iAlpha, const char *pMaterial, float flRoll, float flRollDelta )
+{
+ VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Smoke" );
+ pSimple->SetSortOrigin( origin );
+
+ SimpleParticle *pParticle;
+
+ // Smoke
+ for ( int i = 0; i < numParticles; i++ )
+ {
+ PMaterialHandle hMaterial = pSimple->GetPMaterial( pMaterial );
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), hMaterial, origin );
+ if ( pParticle == NULL )
+ return NULL;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = flDietime;
+ pParticle->m_vecVelocity = velocity;
+ for( int i = 0; i < 3; ++i )
+ {
+ pParticle->m_uchColor[i] = pColor[i];
+ }
+ pParticle->m_uchStartAlpha = iAlpha;
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = scale;
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
+ pParticle->m_flRoll = flRoll;
+ pParticle->m_flRollDelta = flRollDelta;
+ }
+
+ return pSimple;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Smoke puffs
+//-----------------------------------------------------------------------------
+void FX_Smoke( const Vector &origin, const QAngle &angles, float scale, int numParticles, unsigned char *pColor, int iAlpha )
+{
+ VPROF_BUDGET( "FX_Smoke", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ Vector vecVelocity;
+ Vector vecForward;
+
+ // Smoke
+ for ( int i = 0; i < numParticles; i++ )
+ {
+ // Velocity
+ AngleVectors( angles, &vecForward );
+ vecVelocity.Random( -0.5f, 0.5f );
+ vecVelocity += vecForward;
+ VectorNormalize( vecVelocity );
+ vecVelocity *= random->RandomFloat( 16.0f, 32.0f );
+ vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
+
+ // Color
+ unsigned char particlecolor[3];
+ if ( !pColor )
+ {
+ int color = random->RandomInt( 64, 164 );
+ particlecolor[0] = color;
+ particlecolor[1] = color;
+ particlecolor[2] = color;
+ }
+ else
+ {
+ particlecolor[0] = pColor[0];
+ particlecolor[1] = pColor[1];
+ particlecolor[2] = pColor[2];
+ }
+
+ // Alpha
+ int alpha = iAlpha;
+ if ( alpha == -1 )
+ {
+ alpha = random->RandomInt( 10, 25 );
+ }
+
+ // Scale
+ int iSize = random->RandomInt( 4, 8 ) * scale;
+
+ // Roll
+ float flRoll = random->RandomInt( 0, 360 );
+ float flRollDelta = random->RandomFloat( -4.0f, 4.0f );
+
+ //pParticle->m_uchEndSize = pParticle->m_uchStartSize*2;
+
+ FX_Smoke( origin, vecVelocity, iSize, 1, random->RandomFloat( 0.5f, 1.0f ), particlecolor, alpha, "particle/particle_smokegrenade", flRoll, flRollDelta );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Smoke Emitter
+// This is an emitter that keeps spitting out particles for its lifetime
+// It won't create particles if it's not in view, so it's best when short lived
+//-----------------------------------------------------------------------------
+class CSmokeEmitter : public CSimpleEmitter
+{
+ typedef CSimpleEmitter BaseClass;
+public:
+ CSmokeEmitter( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName ) : CSimpleEmitter( pDebugName )
+ {
+ m_hEntity = hEntity;
+ m_nAttachmentIndex = nAttachment;
+ m_flDeathTime = 0;
+ m_flLastParticleSpawnTime = 0;
+ }
+
+ // Create
+ static CSmokeEmitter *Create( ClientEntityHandle_t hEntity, int nAttachment, const char *pDebugName="smoke" )
+ {
+ return new CSmokeEmitter( hEntity, nAttachment, pDebugName );
+ }
+
+ void SetLifeTime( float flTime )
+ {
+ m_flDeathTime = gpGlobals->curtime + flTime;
+ }
+
+ void SetSpurtAngle( QAngle &vecAngles )
+ {
+ AngleVectors( vecAngles, &m_vecSpurtForward );
+ }
+
+ void SetSpurtColor( const Vector4D &pColor )
+ {
+ for ( int i = 0; i <= 3; i++ )
+ {
+ m_SpurtColor[i] = pColor[i];
+ }
+ }
+
+ void SetSpawnRate( float flRate )
+ {
+ m_flSpawnRate = flRate;
+ }
+
+ void CreateSpurtParticles( void )
+ {
+ SimpleParticle *pParticle;
+ // PMaterialHandle hMaterial = GetPMaterial( "particle/particle_smokegrenade" );
+
+ Vector vecOrigin = m_vSortOrigin;
+ IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle(m_hEntity);
+ if ( pRenderable && m_nAttachmentIndex )
+ {
+ QAngle tmp;
+ pRenderable->GetAttachment( m_nAttachmentIndex, vecOrigin, tmp );
+ SetSortOrigin( vecOrigin );
+ }
+
+ // Smoke
+ int numParticles = RandomInt( 1,2 );
+ for ( int i = 0; i < numParticles; i++ )
+ {
+ pParticle = (SimpleParticle *) AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], vecOrigin );
+ if ( pParticle == NULL )
+ break;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = RandomFloat( 0.5, 1.0 );
+
+ // Random velocity around the angles forward
+ Vector vecVelocity;
+ vecVelocity.Random( -0.1f, 0.1f );
+ vecVelocity += m_vecSpurtForward;
+ VectorNormalize( vecVelocity );
+ vecVelocity *= RandomFloat( 160.0f, 640.0f );
+ pParticle->m_vecVelocity = vecVelocity;
+
+ // Randomize the color a little
+ int color[3][2];
+ for( int i = 0; i < 3; ++i )
+ {
+ color[i][0] = MAX( 0, m_SpurtColor[i] - 64 );
+ color[i][1] = MIN( 255, m_SpurtColor[i] + 64 );
+ }
+ pParticle->m_uchColor[0] = random->RandomInt( color[0][0], color[0][1] );
+ pParticle->m_uchColor[1] = random->RandomInt( color[1][0], color[1][1] );
+ pParticle->m_uchColor[2] = random->RandomInt( color[2][0], color[2][1] );
+
+ pParticle->m_uchStartAlpha = m_SpurtColor[3];
+ pParticle->m_uchEndAlpha = 0;
+ pParticle->m_uchStartSize = RandomInt( 50, 60 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize*3;
+ pParticle->m_flRoll = RandomFloat( 0, 360 );
+ pParticle->m_flRollDelta = RandomFloat( -4.0f, 4.0f );
+ }
+
+ m_flLastParticleSpawnTime = gpGlobals->curtime + m_flSpawnRate;
+ }
+
+ virtual void SimulateParticles( CParticleSimulateIterator *pIterator )
+ {
+ Particle *pParticle = pIterator->GetFirst();
+ while ( pParticle )
+ {
+ // If our lifetime isn't up, create more particles
+ if ( m_flDeathTime > gpGlobals->curtime )
+ {
+ if ( m_flLastParticleSpawnTime <= gpGlobals->curtime )
+ {
+ CreateSpurtParticles();
+ }
+ }
+
+ pParticle = pIterator->GetNext();
+ }
+
+ BaseClass::SimulateParticles( pIterator );
+ }
+
+
+private:
+ float m_flDeathTime;
+ float m_flLastParticleSpawnTime;
+ float m_flSpawnRate;
+ Vector m_vecSpurtForward;
+ Vector4D m_SpurtColor;
+ ClientEntityHandle_t m_hEntity;
+ int m_nAttachmentIndex;
+
+ CSmokeEmitter( const CSmokeEmitter & ); // not defined, not accessible
+};
+
+//-----------------------------------------------------------------------------
+// Purpose: Small hose gas spurt
+//-----------------------------------------------------------------------------
+void FX_BuildSmoke( Vector &vecOrigin, QAngle &vecAngles, ClientEntityHandle_t hEntity, int nAttachment, float flLifeTime, const Vector4D &pColor )
+{
+ CSmartPtr<CSmokeEmitter> pSimple = CSmokeEmitter::Create( hEntity, nAttachment, "FX_Smoke" );
+ pSimple->SetSortOrigin( vecOrigin );
+ pSimple->SetLifeTime( flLifeTime );
+ pSimple->SetSpurtAngle( vecAngles );
+ pSimple->SetSpurtColor( pColor );
+ pSimple->SetSpawnRate( 0.03 );
+ pSimple->CreateSpurtParticles();
+}
+
+//-----------------------------------------------------------------------------
+// Purpose: Green hose gas spurt
+//-----------------------------------------------------------------------------
+void SmokeCallback( const CEffectData &data )
+{
+ Vector vecOrigin = data.m_vOrigin;
+ QAngle vecAngles = data.m_vAngles;
+
+ Vector4D color( 50,50,50,255 );
+ FX_BuildSmoke( vecOrigin, vecAngles, data.m_hEntity, data.m_nAttachmentIndex, 100.0, color );
+}
+
+DECLARE_CLIENT_EFFECT( "Smoke", SmokeCallback );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Shockwave for gunship bullet impacts!
+// Input : &pos -
+//
+// NOTES: -Don't draw this effect when the viewer is very far away.
+//-----------------------------------------------------------------------------
+void FX_GunshipImpact( const Vector &pos, const Vector &normal, float r, float g, float b )
+{
+ VPROF_BUDGET( "FX_GunshipImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ if ( CImpactOverlay *pOverlay = new CImpactOverlay )
+ {
+ pOverlay->m_flLifetime = 0;
+ VectorMA( pos, 1.0f, normal, pOverlay->m_vPos ); // Doesn't show up on terrain if you don't do this(sjb)
+ pOverlay->m_nSprites = 1;
+
+ pOverlay->m_vBaseColors[0].Init( r, g, b );
+
+ pOverlay->m_Sprites[0].m_flHorzSize = 0.01f;
+ pOverlay->m_Sprites[0].m_flVertSize = 0.01f;
+
+ pOverlay->Activate();
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : data -
+//-----------------------------------------------------------------------------
+void GunshipImpactCallback( const CEffectData & data )
+{
+ Vector vecPosition;
+
+ vecPosition = data.m_vOrigin;
+
+ FX_GunshipImpact( vecPosition, Vector( 0, 0, 1 ), 100, 0, 200 );
+}
+DECLARE_CLIENT_EFFECT( "GunshipImpact", GunshipImpactCallback );
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void CommandPointerCallback( const CEffectData & data )
+{
+ int size = COLOR_TABLE_SIZE( commandercolors );
+
+ for( int i = 0 ; i < size ; i++ )
+ {
+ if( commandercolors[ i ].index == data.m_nColor )
+ {
+ FX_GunshipImpact( data.m_vOrigin, Vector( 0, 0, 1 ), commandercolors[ i ].r, commandercolors[ i ].g, commandercolors[ i ].b );
+ return;
+ }
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "CommandPointer", CommandPointerCallback );
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+//-----------------------------------------------------------------------------
+void FX_GunshipMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
+{
+ VPROF_BUDGET( "FX_GunshipMuzzleEffect", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash" );
+ pSimple->SetSortOrigin( origin );
+
+ SimpleParticle *pParticle;
+ Vector forward, offset;
+
+ AngleVectors( angles, &forward );
+
+ //
+ // Flash
+ //
+ offset = origin;
+
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/gunshipmuzzle" ), offset );
+
+ if ( pParticle == NULL )
+ return;
+
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = 0.15f;
+
+ pParticle->m_vecVelocity.Init();
+
+ pParticle->m_uchStartSize = random->RandomFloat( 40.0, 50.0 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize;
+
+ pParticle->m_flRoll = random->RandomInt( 0, 360 );
+ pParticle->m_flRollDelta = 0.15f;
+
+ pParticle->m_uchColor[0] = 255;
+ pParticle->m_uchColor[1] = 255;
+ pParticle->m_uchColor[2] = 255;
+
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 255;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : start -
+// end -
+// velocity -
+// makeWhiz -
+//-----------------------------------------------------------------------------
+void FX_GunshipTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
+{
+ VPROF_BUDGET( "FX_GunshipTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ Vector vNear, dStart, dEnd, shotDir;
+ float totalDist;
+
+ //Get out shot direction and length
+ VectorSubtract( end, start, shotDir );
+ totalDist = VectorNormalize( shotDir );
+
+ //Don't make small tracers
+ if ( totalDist <= 256 )
+ return;
+
+ float length = random->RandomFloat( 128.0f, 256.0f );
+ float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
+
+ //Add it
+ FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 5.0f, life, "effects/gunshiptracer" );
+
+ if( makeWhiz )
+ {
+ FX_TracerSound( start, end, TRACER_TYPE_GUNSHIP );
+ }
+}
+
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+void FX_StriderMuzzleEffect( const Vector &origin, const QAngle &angles, float scale, ClientEntityHandle_t hEntity, unsigned char *pFlashColor )
+{
+ Vector vecDir;
+ AngleVectors( angles, &vecDir );
+
+ float life = 0.3f;
+ float speed = 100.0f;
+
+ for( int i = 0 ; i < 5 ; i++ )
+ {
+ FX_AddDiscreetLine( origin, vecDir, speed, 32, speed * life, 5.0f, life, "effects/bluespark" );
+ speed *= 1.5f;
+ }
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : start -
+// end -
+// velocity -
+// makeWhiz -
+//-----------------------------------------------------------------------------
+void FX_StriderTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
+{
+ VPROF_BUDGET( "FX_StriderTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ Vector vNear, dStart, dEnd, shotDir;
+ float totalDist;
+
+ //Get out shot direction and length
+ VectorSubtract( end, start, shotDir );
+ totalDist = VectorNormalize( shotDir );
+
+ //Don't make small tracers
+ if ( totalDist <= 256 )
+ return;
+
+ float length = random->RandomFloat( 64.0f, 128.0f );
+ float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
+
+ //Add it
+ FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, 2.5f, life, "effects/gunshiptracer" );
+
+ if( makeWhiz )
+ {
+ FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : start -
+// end -
+// velocity -
+// makeWhiz -
+//-----------------------------------------------------------------------------
+void FX_HunterTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
+{
+ VPROF_BUDGET( "FX_HunterTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ Vector vNear, dStart, dEnd, shotDir;
+ float totalDist;
+
+ // Get out shot direction and length
+ VectorSubtract( end, start, shotDir );
+ totalDist = VectorNormalize( shotDir );
+
+ // Make short tracers in close quarters
+ // float flMinLength = MIN( totalDist, 128.0f );
+ // float flMaxLength = MIN( totalDist, 128.0f );
+
+ float length = 128.0f;//random->RandomFloat( flMinLength, flMaxLength );
+ float life = ( totalDist + length ) / velocity; // NOTENOTE: We want the tail to finish its run as well
+
+ // Add it
+ FX_AddDiscreetLine( start, shotDir, velocity*0.5f, length, totalDist, 2.0f, life, "effects/huntertracer" );
+
+ if( makeWhiz )
+ {
+ FX_TracerSound( start, end, TRACER_TYPE_STRIDER );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : start -
+// end -
+// velocity -
+// makeWhiz -
+//-----------------------------------------------------------------------------
+void FX_GaussTracer( Vector& start, Vector& end, int velocity, bool makeWhiz )
+{
+ VPROF_BUDGET( "FX_GaussTracer", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
+ Vector vNear, dStart, dEnd, shotDir;
+ float totalDist;
+
+ //Get out shot direction and length
+ VectorSubtract( end, start, shotDir );
+ totalDist = VectorNormalize( shotDir );
+
+ //Don't make small tracers
+ if ( totalDist <= 256 )
+ return;
+
+ float length = random->RandomFloat( 250.0f, 500.0f );
+ float life = ( totalDist + length ) / velocity; //NOTENOTE: We want the tail to finish its run as well
+
+ //Add it
+ FX_AddDiscreetLine( start, shotDir, velocity, length, totalDist, random->RandomFloat( 5.0f, 8.0f ), life, "effects/spark" );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Create a tesla effect between two points
+//-----------------------------------------------------------------------------
+void FX_BuildTesla(
+ C_BaseEntity *pEntity,
+ const Vector &vecOrigin,
+ const Vector &vecEnd,
+ const char *pModelName,
+ float flBeamWidth,
+ const Vector &vColor,
+ int nFlags,
+ float flTimeVisible )
+{
+ BeamInfo_t beamInfo;
+ beamInfo.m_nType = TE_BEAMTESLA;
+ beamInfo.m_vecStart = vecOrigin;
+ beamInfo.m_vecEnd = vecEnd;
+ beamInfo.m_pszModelName = pModelName;
+ beamInfo.m_flHaloScale = 0.0;
+ beamInfo.m_flLife = flTimeVisible;
+ beamInfo.m_flWidth = flBeamWidth;
+ beamInfo.m_flEndWidth = 1;
+ beamInfo.m_flFadeLength = 0.3;
+ beamInfo.m_flAmplitude = 16;
+ beamInfo.m_flBrightness = 200.0;
+ beamInfo.m_flSpeed = 0.0;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 1.0;
+ beamInfo.m_flRed = vColor.x * 255.0;
+ beamInfo.m_flGreen = vColor.y * 255.0;
+ beamInfo.m_flBlue = vColor.z * 255.0;
+ beamInfo.m_nSegments = 20;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_nFlags = nFlags;
+
+ beams->CreateBeamPoints( beamInfo );
+}
+
+void FX_Tesla( const CTeslaInfo &teslaInfo )
+{
+ C_BaseEntity *pEntity = ClientEntityList().GetEnt( teslaInfo.m_nEntIndex );
+
+ // Send out beams around us
+ int iNumBeamsAround = (teslaInfo.m_nBeams * 2) / 3; // (2/3 of the beams are placed around in a circle)
+ int iNumRandomBeams = teslaInfo.m_nBeams - iNumBeamsAround;
+ int iTotalBeams = iNumBeamsAround + iNumRandomBeams;
+ float flYawOffset = RandomFloat(0,360);
+ for ( int i = 0; i < iTotalBeams; i++ )
+ {
+ // Make a couple of tries at it
+ int iTries = -1;
+ Vector vecForward;
+ trace_t tr;
+ do
+ {
+ iTries++;
+
+ // Some beams are deliberatly aimed around the point, the rest are random.
+ if ( i < iNumBeamsAround )
+ {
+ QAngle vecTemp = teslaInfo.m_vAngles;
+ vecTemp[YAW] += anglemod( flYawOffset + ((360 / iTotalBeams) * i) );
+ AngleVectors( vecTemp, &vecForward );
+
+ // Randomly angle it up or down
+ vecForward.z = RandomFloat( -1, 1 );
+ }
+ else
+ {
+ vecForward = RandomVector( -1, 1 );
+ }
+ VectorNormalize( vecForward );
+
+ UTIL_TraceLine( teslaInfo.m_vPos, teslaInfo.m_vPos + (vecForward * teslaInfo.m_flRadius), MASK_SHOT, pEntity, COLLISION_GROUP_NONE, &tr );
+ } while ( tr.fraction >= 1.0 && iTries < 3 );
+
+ Vector vecEnd = tr.endpos - (vecForward * 8);
+
+ // Only spark & glow if we hit something
+ if ( tr.fraction < 1.0 )
+ {
+ if ( !EffectOccluded( tr.endpos, 0 ) )
+ {
+ // Move it towards the camera
+ Vector vecFlash = tr.endpos;
+ Vector vecForward;
+ AngleVectors( MainViewAngles(), &vecForward );
+ vecFlash -= (vecForward * 8);
+
+ g_pEffects->EnergySplash( vecFlash, -vecForward, false );
+
+ // End glow
+ CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "dust" );
+ pSimple->SetSortOrigin( vecFlash );
+ SimpleParticle *pParticle;
+ pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( "effects/tesla_glow_noz" ), vecFlash );
+ if ( pParticle != NULL )
+ {
+ pParticle->m_flLifetime = 0.0f;
+ pParticle->m_flDieTime = RandomFloat( 0.5, 1 );
+ pParticle->m_vecVelocity = vec3_origin;
+ Vector color( 1,1,1 );
+ float colorRamp = RandomFloat( 0.75f, 1.25f );
+ pParticle->m_uchColor[0] = MIN( 1.0f, color[0] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[1] = MIN( 1.0f, color[1] * colorRamp ) * 255.0f;
+ pParticle->m_uchColor[2] = MIN( 1.0f, color[2] * colorRamp ) * 255.0f;
+ pParticle->m_uchStartSize = RandomFloat( 6,13 );
+ pParticle->m_uchEndSize = pParticle->m_uchStartSize - 2;
+ pParticle->m_uchStartAlpha = 255;
+ pParticle->m_uchEndAlpha = 10;
+ pParticle->m_flRoll = RandomFloat( 0,360 );
+ pParticle->m_flRollDelta = 0;
+ }
+ }
+ }
+
+ // Build the tesla
+ FX_BuildTesla( pEntity, teslaInfo.m_vPos, tr.endpos, teslaInfo.m_pszSpriteName, teslaInfo.m_flBeamWidth, teslaInfo.m_vColor, FBEAM_ONLYNOISEONCE, teslaInfo.m_flTimeVisible );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tesla effect
+//-----------------------------------------------------------------------------
+void BuildTeslaCallback( const CEffectData &data )
+{
+ if ( data.entindex() < 0 )
+ return;
+
+ CTeslaInfo teslaInfo;
+
+ teslaInfo.m_vPos = data.m_vOrigin;
+ teslaInfo.m_vAngles = data.m_vAngles;
+ teslaInfo.m_nEntIndex = data.entindex();
+ teslaInfo.m_flBeamWidth = 5;
+ teslaInfo.m_vColor.Init( 1, 1, 1 );
+ teslaInfo.m_flTimeVisible = 0.3;
+ teslaInfo.m_flRadius = 192;
+ teslaInfo.m_nBeams = 6;
+ teslaInfo.m_pszSpriteName = "sprites/physbeam.vmt";
+
+ FX_Tesla( teslaInfo );
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tesla hitbox
+//-----------------------------------------------------------------------------
+void FX_BuildTeslaHitbox(
+ C_BaseEntity *pEntity,
+ int nStartAttachment,
+ int nEndAttachment,
+ float flBeamWidth,
+ const Vector &vColor,
+ float flTimeVisible )
+{
+ // One along the body
+ BeamInfo_t beamInfo;
+ beamInfo.m_nType = TE_BEAMTESLA;
+ beamInfo.m_vecStart = vec3_origin;
+ beamInfo.m_vecEnd = vec3_origin;
+ beamInfo.m_pszModelName = "sprites/lgtning.vmt";
+ beamInfo.m_flHaloScale = 8.0f;
+ beamInfo.m_flLife = 0.01f;
+ beamInfo.m_flWidth = random->RandomFloat( 3.0f, 6.0f );
+ beamInfo.m_flEndWidth = 0.0f;
+ beamInfo.m_flFadeLength = 0.0f;
+ beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
+ beamInfo.m_flBrightness = 255.0f;
+ beamInfo.m_flSpeed = 32.0;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 30.0;
+ beamInfo.m_flRed = vColor.x * 255.0;
+ beamInfo.m_flGreen = vColor.y * 255.0;
+ beamInfo.m_flBlue = vColor.z * 255.0;
+ beamInfo.m_nSegments = 32;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
+
+ beamInfo.m_nFlags = (FBEAM_USE_HITBOXES);
+
+ beamInfo.m_pStartEnt = pEntity;
+ beamInfo.m_nStartAttachment = nStartAttachment;
+ beamInfo.m_pEndEnt = pEntity;
+ beamInfo.m_nEndAttachment = nEndAttachment;
+
+ beams->CreateBeamEntPoint( beamInfo );
+
+ // One out to the world
+ trace_t tr;
+ Vector randomDir;
+
+ randomDir = RandomVector( -1.0f, 1.0f );
+ VectorNormalize( randomDir );
+
+ UTIL_TraceLine( pEntity->WorldSpaceCenter(), pEntity->WorldSpaceCenter() + ( randomDir * 100 ), MASK_SOLID_BRUSHONLY, pEntity, COLLISION_GROUP_NONE, &tr );
+
+ if ( tr.fraction < 1.0f )
+ {
+ beamInfo.m_nType = TE_BEAMTESLA;
+ beamInfo.m_vecStart = vec3_origin;
+ beamInfo.m_vecEnd = tr.endpos;
+ beamInfo.m_pszModelName = "sprites/lgtning.vmt";
+ beamInfo.m_flHaloScale = 8.0f;
+ beamInfo.m_flLife = 0.05f;
+ beamInfo.m_flWidth = random->RandomFloat( 2.0f, 6.0f );
+ beamInfo.m_flEndWidth = 0.0f;
+ beamInfo.m_flFadeLength = 0.0f;
+ beamInfo.m_flAmplitude = random->RandomInt( 16, 32 );
+ beamInfo.m_flBrightness = 255.0f;
+ beamInfo.m_flSpeed = 32.0;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 30.0;
+ beamInfo.m_flRed = vColor.x * 255.0;
+ beamInfo.m_flGreen = vColor.y * 255.0;
+ beamInfo.m_flBlue = vColor.z * 255.0;
+ beamInfo.m_nSegments = 32;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_pStartEnt = beamInfo.m_pEndEnt = NULL;
+
+ beamInfo.m_pStartEnt = pEntity;
+ beamInfo.m_nStartAttachment = nStartAttachment;
+
+ beams->CreateBeamEntPoint( beamInfo );
+ }
+
+ // Create an elight to illuminate the target
+ if ( pEntity != NULL )
+ {
+ dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_TE_DYNAMIC + pEntity->entindex() );
+
+ // Randomly place it
+ el->origin = pEntity->WorldSpaceCenter() + RandomVector( -32, 32 );
+
+ el->color.r = 235;
+ el->color.g = 235;
+ el->color.b = 255;
+ el->color.exponent = 4;
+
+ el->radius = random->RandomInt( 32, 128 );
+ el->decay = el->radius / 0.1f;
+ el->die = gpGlobals->curtime + 0.1f;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tesla effect
+//-----------------------------------------------------------------------------
+void FX_BuildTeslaHitbox( const CEffectData &data )
+{
+ Vector vColor( 1, 1, 1 );
+
+ C_BaseEntity *pEntity = ClientEntityList().GetEnt( data.entindex() );
+ C_BaseAnimating *pAnimating = pEntity ? pEntity->GetBaseAnimating() : NULL;
+ if (!pAnimating)
+ return;
+
+ studiohdr_t *pStudioHdr = modelinfo->GetStudiomodel( pAnimating->GetModel() );
+ if (!pStudioHdr)
+ return;
+
+ mstudiohitboxset_t *set = pStudioHdr->pHitboxSet( pAnimating->GetHitboxSet() );
+ if ( !set )
+ return;
+
+ matrix3x4_t *hitboxbones[MAXSTUDIOBONES];
+ if ( !pAnimating->HitboxToWorldTransforms( hitboxbones ) )
+ return;
+
+ int nBeamCount = (int)(data.m_flMagnitude + 0.5f);
+ for ( int i = 0; i < nBeamCount; ++i )
+ {
+ int nStartHitBox = random->RandomInt( 1, set->numhitboxes );
+ int nEndHitBox = random->RandomInt( 1, set->numhitboxes );
+ FX_BuildTeslaHitbox( pEntity, nStartHitBox, nEndHitBox, data.m_flScale, vColor, random->RandomFloat( 0.05f, 0.2f ) );
+ }
+}
+
+DECLARE_CLIENT_EFFECT( "TeslaHitboxes", FX_BuildTeslaHitbox );
+
+
+//-----------------------------------------------------------------------------
+// Purpose: Tesla effect
+//-----------------------------------------------------------------------------
+void FX_BuildTeslaZap( const CEffectData &data )
+{
+ // Build the tesla, only works on entities
+ C_BaseEntity *pEntity = data.GetEntity();
+ if ( !pEntity )
+ return;
+
+ Vector vColor( 1, 1, 1 );
+
+ BeamInfo_t beamInfo;
+ beamInfo.m_nType = TE_BEAMTESLA;
+ beamInfo.m_pStartEnt = pEntity;
+ beamInfo.m_nStartAttachment = data.m_nAttachmentIndex;
+ beamInfo.m_pEndEnt = NULL;
+ beamInfo.m_vecEnd = data.m_vOrigin;
+ beamInfo.m_pszModelName = "sprites/physbeam.vmt";
+ beamInfo.m_flHaloScale = 0.0;
+ beamInfo.m_flLife = 0.3f;
+ beamInfo.m_flWidth = data.m_flScale;
+ beamInfo.m_flEndWidth = 1;
+ beamInfo.m_flFadeLength = 0.3;
+ beamInfo.m_flAmplitude = 16;
+ beamInfo.m_flBrightness = 200.0;
+ beamInfo.m_flSpeed = 0.0;
+ beamInfo.m_nStartFrame = 0.0;
+ beamInfo.m_flFrameRate = 1.0;
+ beamInfo.m_flRed = vColor.x * 255.0;
+ beamInfo.m_flGreen = vColor.y * 255.0;
+ beamInfo.m_flBlue = vColor.z * 255.0;
+ beamInfo.m_nSegments = 20;
+ beamInfo.m_bRenderable = true;
+ beamInfo.m_nFlags = 0;
+
+ beams->CreateBeamEntPoint( beamInfo );
+}
+
+DECLARE_CLIENT_EFFECT( "TeslaZap", FX_BuildTeslaZap );
+