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.cpp | 2656 ++++++++++++++++++++++----------------------- 1 file changed, 1328 insertions(+), 1328 deletions(-) (limited to 'mp/src/game/client/fx.cpp') 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 ); + -- cgit v1.2.3