Counter Strike : Global Offensive Source Code
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1191 lines
38 KiB

//========= Copyright © 1996-2005, Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
//=============================================================================//
#include "cbase.h"
#include "fx.h"
#include "fx_sparks.h"
#include "precache_register.h"
#include "particle_simple3d.h"
#include "decals.h"
#include "engine/IEngineSound.h"
#include "c_te_particlesystem.h"
#include "engine/ivmodelinfo.h"
#include "particles_ez.h"
#include "c_impact_effects.h"
#include "engine/IStaticPropMgr.h"
#include "tier0/vprof.h"
#include "c_te_effect_dispatch.h"
// memdbgon must be the last include file in a .cpp file!!!
#include "tier0/memdbgon.h"
//Precahce the effects
PRECACHE_REGISTER_BEGIN( GLOBAL, PrecacheEffectImpacts )
PRECACHE( MATERIAL, "effects/fleck_cement1" )
PRECACHE( MATERIAL, "effects/fleck_cement2" )
PRECACHE( MATERIAL, "effects/fleck_antlion1" )
PRECACHE( MATERIAL, "effects/fleck_antlion2" )
PRECACHE( MATERIAL, "effects/fleck_wood1" )
PRECACHE( MATERIAL, "effects/fleck_wood2" )
PRECACHE( MATERIAL, "effects/blood" )
PRECACHE( MATERIAL, "effects/blood2" )
PRECACHE( MATERIAL, "sprites/bloodspray" )
PRECACHE( MATERIAL, "particle/particle_noisesphere" )
PRECACHE_REGISTER_END()
// Cached handles to commonly used materials
PMaterialHandle g_Mat_Fleck_Wood[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Cement[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Antlion[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Glass[2] = { NULL, NULL };
PMaterialHandle g_Mat_Fleck_Tile[2] = { NULL, NULL };
PMaterialHandle g_Mat_DustPuff[2] = { NULL, NULL };
PMaterialHandle g_Mat_BloodPuff[2] = { NULL, NULL };
PMaterialHandle g_Mat_SMG_Muzzleflash[4] = { NULL, NULL, NULL, NULL };
PMaterialHandle g_Mat_Combine_Muzzleflash[3] = { NULL, NULL, NULL };
static ConVar fx_drawimpactdebris( "fx_drawimpactdebris", "1", FCVAR_DEVELOPMENTONLY, "Draw impact debris effects." );
static ConVar fx_drawimpactdust( "fx_drawimpactdust", "1", FCVAR_DEVELOPMENTONLY, "Draw impact dust effects." );
PRECACHE_REGISTER_BEGIN( GLOBAL, FX_CacheMaterialHandles )
#ifndef DOTA_DLL
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_wood1", g_Mat_Fleck_Wood[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_wood2", g_Mat_Fleck_Wood[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_cement1", g_Mat_Fleck_Cement[0])
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_cement2", g_Mat_Fleck_Cement[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_antlion1", g_Mat_Fleck_Antlion[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_antlion2", g_Mat_Fleck_Antlion[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_glass1", g_Mat_Fleck_Glass[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_glass2", g_Mat_Fleck_Glass[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_tile1", g_Mat_Fleck_Tile[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/fleck_tile2", g_Mat_Fleck_Tile[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "particle/particle_smokegrenade", g_Mat_DustPuff[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "particle/particle_noisesphere", g_Mat_DustPuff[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/blood", g_Mat_BloodPuff[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/blood2", g_Mat_BloodPuff[1] )
#ifndef TF_CLIENT_DLL
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash1", g_Mat_SMG_Muzzleflash[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash2", g_Mat_SMG_Muzzleflash[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash3", g_Mat_SMG_Muzzleflash[2] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/muzzleflash4", g_Mat_SMG_Muzzleflash[3] )
#if !defined( CSTRIKE_DLL )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/combinemuzzle1", g_Mat_Combine_Muzzleflash[0] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/combinemuzzle2", g_Mat_Combine_Muzzleflash[1] )
PRECACHE_INDEX( PARTICLE_MATERIAL, "effects/strider_muzzle", g_Mat_Combine_Muzzleflash[2] )
#endif
#endif
#endif
PRECACHE_REGISTER_END()
extern PMaterialHandle g_Material_Spark;
//-----------------------------------------------------------------------------
// Purpose: Returns the color given trace information
// Input : *trace - trace to get results for
// *color - return color, gamma corrected (0.0f to 1.0f)
//-----------------------------------------------------------------------------
void GetColorForSurface( trace_t *trace, Vector *color )
{
Vector baseColor, diffuseColor;
Vector end = trace->startpos + ( ( Vector )trace->endpos - ( Vector )trace->startpos ) * 1.1f;
if ( trace->DidHitWorld() )
{
if ( trace->hitbox == 0 )
{
// If we hit the world, then ask the world for the fleck color
engine->TraceLineMaterialAndLighting( trace->startpos, end, diffuseColor, baseColor );
}
else
{
// In this case we hit a static prop.
staticpropmgr->GetStaticPropMaterialColorAndLighting( trace, trace->hitbox - 1, diffuseColor, baseColor );
}
}
else
{
// In this case, we hit an entity. Find out the model associated with it
C_BaseEntity *pEnt = trace->m_pEnt;
if ( !pEnt )
{
Msg("Couldn't find surface in GetColorForSurface()\n");
color->x = 255;
color->y = 255;
color->z = 255;
return;
}
ICollideable *pCollide = pEnt->GetCollideable();
int modelIndex = pCollide->GetCollisionModelIndex();
model_t* pModel = const_cast<model_t*>(modelinfo->GetModel( modelIndex ));
// Ask the model info about what we need to know
modelinfo->GetModelMaterialColorAndLighting( pModel, pCollide->GetCollisionOrigin(),
pCollide->GetCollisionAngles(), trace, diffuseColor, baseColor );
}
//Get final light value
color->x = pow( diffuseColor[0], 1.0f/2.2f ) * baseColor[0];
color->y = pow( diffuseColor[1], 1.0f/2.2f ) * baseColor[1];
color->z = pow( diffuseColor[2], 1.0f/2.2f ) * baseColor[2];
}
//-----------------------------------------------------------------------------
// This does the actual debris flecks
//-----------------------------------------------------------------------------
#define FLECK_MIN_SPEED 64.0f
#define FLECK_MAX_SPEED 128.0f
#define FLECK_GRAVITY 800.0f
#define FLECK_DAMPEN 0.3f
#define FLECK_ANGULAR_SPRAY 0.6f
//
// PC ONLY!
//
static void CreateFleckParticles( const Vector& origin, const Vector &color, trace_t *trace, char materialType, int iScale )
{
Vector spawnOffset = trace->endpos + ( trace->plane.normal * 1.0f );
CSmartPtr<CFleckParticles> fleckEmitter = CFleckParticles::Create( "FX_DebrisFlecks", spawnOffset, Vector(5,5,5) );
if ( !fleckEmitter )
return;
// Handle increased scale
float flMaxSpeed = FLECK_MAX_SPEED * iScale;
float flAngularSpray = MAX( 0.2, FLECK_ANGULAR_SPRAY - ( (float)iScale * 0.2f) ); // More power makes the spray more controlled
// Setup our collision information
fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &trace->plane.normal, flAngularSpray, FLECK_MIN_SPEED, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );
PMaterialHandle *hMaterial;
switch ( materialType )
{
case CHAR_TEX_WOOD:
hMaterial = g_Mat_Fleck_Wood;
break;
case CHAR_TEX_CONCRETE:
case CHAR_TEX_TILE:
default:
hMaterial = g_Mat_Fleck_Cement;
break;
}
Vector dir, end;
float colorRamp;
int numFlecks = random->RandomInt( 4, 16 ) * iScale;
FleckParticle *pFleckParticle;
//Dump out flecks
int i;
for ( i = 0; i < numFlecks; i++ )
{
pFleckParticle = (FleckParticle *) fleckEmitter->AddParticle( sizeof(FleckParticle), hMaterial[random->RandomInt(0,1)], spawnOffset );
if ( pFleckParticle == NULL )
break;
pFleckParticle->m_flLifetime = 0.0f;
pFleckParticle->m_flDieTime = 3.0f;
dir[0] = trace->plane.normal[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[1] = trace->plane.normal[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[2] = trace->plane.normal[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
pFleckParticle->m_uchSize = random->RandomInt( 1, 2 );
pFleckParticle->m_vecVelocity = dir * ( random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed) * ( 3 - pFleckParticle->m_uchSize ) );
pFleckParticle->m_flRoll = random->RandomFloat( 0, 360 );
pFleckParticle->m_flRollDelta = random->RandomFloat( 0, 360 );
colorRamp = random->RandomFloat( 0.75f, 1.25f );
pFleckParticle->m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
pFleckParticle->m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
pFleckParticle->m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
}
}
//-----------------------------------------------------------------------------
// Purpose: Debris flecks caused by impacts
// Input : origin - start
// *trace - trace information
// *materialName - material hit
// materialType - type of material hit
//-----------------------------------------------------------------------------
void FX_DebrisFlecks( const Vector& origin, trace_t *tr, char materialType, int iScale, bool bNoFlecks )
{
VPROF_BUDGET( "FX_DebrisFlecks", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
if ( !fx_drawimpactdebris.GetBool() )
return;
Vector color;
GetColorForSurface( tr, &color );
if ( !bNoFlecks )
{
CreateFleckParticles( origin, color, tr, materialType, iScale );
}
//
// Dust trail
//
Vector offset = tr->endpos + ( tr->plane.normal * 2.0f );
SimpleParticle newParticle;
int i;
for ( i = 0; i < 2; i++ )
{
newParticle.m_Pos = offset;
newParticle.m_flLifetime = 0.0f;
newParticle.m_flDieTime = 1.0f;
Vector dir;
dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
newParticle.m_uchStartSize = random->RandomInt( 2, 4 ) * iScale;
newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8 * iScale;
newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f )*(i+1);
newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 32.0f )*(i+1);
newParticle.m_uchStartAlpha = random->RandomInt( 100, 200 );
newParticle.m_uchEndAlpha = 0;
newParticle.m_flRoll = random->RandomFloat( 0, 360 );
newParticle.m_flRollDelta = random->RandomFloat( -1, 1 );
float colorRamp = random->RandomFloat( 0.5f, 1.25f );
newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
}
for ( i = 0; i < 4; i++ )
{
newParticle.m_Pos = offset;
newParticle.m_flLifetime = 0.0f;
newParticle.m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
Vector dir;
dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
newParticle.m_uchStartSize = random->RandomInt( 1, 4 );
newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4;
newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 32.0f );
newParticle.m_vecVelocity[2] -= random->RandomFloat( 8.0f, 64.0f );
newParticle.m_uchStartAlpha = 255;
newParticle.m_uchEndAlpha = 0;
newParticle.m_flRoll = random->RandomFloat( 0, 360 );
newParticle.m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
float colorRamp = random->RandomFloat( 0.5f, 1.25f );
newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
}
//
// Bullet hole capper
//
newParticle.m_Pos = offset;
newParticle.m_flLifetime = 0.0f;
newParticle.m_flDieTime = random->RandomFloat( 1.0f, 1.5f );
Vector dir;
dir[0] = tr->plane.normal[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = tr->plane.normal[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = tr->plane.normal[2] + random->RandomFloat( -0.8f, 0.8f );
newParticle.m_uchStartSize = random->RandomInt( 4, 8 );
newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f;
newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 24.0f );
newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );
newParticle.m_uchStartAlpha = random->RandomInt( 100, 200 );
newParticle.m_uchEndAlpha = 0;
newParticle.m_flRoll = random->RandomFloat( 0, 360 );
newParticle.m_flRollDelta = random->RandomFloat( -2, 2 );
float colorRamp = random->RandomFloat( 0.5f, 1.25f );
newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
}
#define GLASS_SHARD_MIN_LIFE 2.5f
#define GLASS_SHARD_MAX_LIFE 5.0f
#define GLASS_SHARD_NOISE 0.8
#define GLASS_SHARD_GRAVITY 800
#define GLASS_SHARD_DAMPING 0.3
#define GLASS_SHARD_MIN_SPEED 1
#define GLASS_SHARD_MAX_SPEED 300
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void GlassImpactCallback( const CEffectData &data )
{
VPROF_BUDGET( "GlassImpactCallback", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
Vector pos = data.m_vOrigin;
Vector normal = data.m_vNormal;
CSmartPtr<CSimple3DEmitter> pGlassEmitter = CSimple3DEmitter::Create( "FX_GlassImpact" );
pGlassEmitter->SetSortOrigin( pos );
Vector vecColor;
engine->ComputeLighting( pos, NULL, true, vecColor );
// HACK: Blend a little toward white to match the materials...
VectorLerp( vecColor, Vector( 1, 1, 1 ), 0.3, vecColor );
float flShardSize = random->RandomFloat( 2.0f, 6.0f );
unsigned char color[3] = { 200, 200, 210 };
// ---------------------
// Create glass shards
// ----------------------
int numShards = random->RandomInt( 2, 4 );
for ( int i = 0; i < numShards; i++ )
{
Particle3D *pParticle;
pParticle = (Particle3D *) pGlassEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Glass[random->RandomInt(0,1)], pos );
if ( pParticle )
{
pParticle->m_flLifeRemaining = random->RandomFloat(GLASS_SHARD_MIN_LIFE,GLASS_SHARD_MAX_LIFE);
pParticle->m_vecVelocity[0] = ( normal[0] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
pParticle->m_vecVelocity[1] = ( normal[1] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
pParticle->m_vecVelocity[2] = ( normal[2] + random->RandomFloat( -0.8f, 0.8f ) ) * random->RandomFloat( GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED );
pParticle->m_uchSize = flShardSize + random->RandomFloat(-0.5*flShardSize,0.5*flShardSize);
pParticle->m_vAngles = RandomAngle( 0, 360 );
pParticle->m_flAngSpeed = random->RandomFloat(-800,800);
pParticle->m_uchFrontColor[0] = (byte)(color[0] * vecColor.x);
pParticle->m_uchFrontColor[1] = (byte)(color[1] * vecColor.y);
pParticle->m_uchFrontColor[2] = (byte)(color[2] * vecColor.z);
pParticle->m_uchBackColor[0] = (byte)(color[0] * vecColor.x);
pParticle->m_uchBackColor[1] = (byte)(color[1] * vecColor.y);
pParticle->m_uchBackColor[2] = (byte)(color[2] * vecColor.z);
}
}
pGlassEmitter->m_ParticleCollision.Setup( pos, &normal, GLASS_SHARD_NOISE, GLASS_SHARD_MIN_SPEED, GLASS_SHARD_MAX_SPEED, GLASS_SHARD_GRAVITY, GLASS_SHARD_DAMPING );
color[0] = 64;
color[1] = 64;
color[2] = 92;
// ---------------------------
// Dust
// ---------------------------
Vector dir;
Vector offset = pos + ( normal * 2.0f );
float colorRamp;
SimpleParticle newParticle;
for ( int i = 0; i < 4; i++ )
{
newParticle.m_Pos = offset;
newParticle.m_flLifetime= 0.0f;
newParticle.m_flDieTime = random->RandomFloat( 0.1f, 0.25f );
dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
newParticle.m_uchStartSize = random->RandomInt( 1, 4 );
newParticle.m_uchEndSize = newParticle.m_uchStartSize * 8;
newParticle.m_vecVelocity = dir * random->RandomFloat( 8.0f, 16.0f )*(i+1);
newParticle.m_vecVelocity[2] -= random->RandomFloat( 16.0f, 32.0f )*(i+1);
newParticle.m_uchStartAlpha = random->RandomInt( 128, 255 );
newParticle.m_uchEndAlpha = 0;
newParticle.m_flRoll = random->RandomFloat( 0, 360 );
newParticle.m_flRollDelta = random->RandomFloat( -1, 1 );
colorRamp = random->RandomFloat( 0.5f, 1.25f );
newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
AddSimpleParticle( &newParticle, g_Mat_BloodPuff[0] );
}
//
// Bullet hole capper
//
newParticle.m_Pos = offset;
newParticle.m_flLifetime = 0.0f;
newParticle.m_flDieTime = random->RandomFloat( 1.0f, 1.5f );
dir[0] = normal[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = normal[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = normal[2] + random->RandomFloat( -0.8f, 0.8f );
newParticle.m_uchStartSize = random->RandomInt( 4, 8 );
newParticle.m_uchEndSize = newParticle.m_uchStartSize * 4.0f;
newParticle.m_vecVelocity = dir * random->RandomFloat( 2.0f, 8.0f );
newParticle.m_vecVelocity[2] = random->RandomFloat( -2.0f, 2.0f );
newParticle.m_uchStartAlpha = random->RandomInt( 32, 64 );
newParticle.m_uchEndAlpha = 0;
newParticle.m_flRoll = random->RandomFloat( 0, 360 );
newParticle.m_flRollDelta = random->RandomFloat( -2, 2 );
colorRamp = random->RandomFloat( 0.5f, 1.25f );
newParticle.m_uchColor[0] = MIN( 1.0f, color[0]*colorRamp )*255.0f;
newParticle.m_uchColor[1] = MIN( 1.0f, color[1]*colorRamp )*255.0f;
newParticle.m_uchColor[2] = MIN( 1.0f, color[2]*colorRamp )*255.0f;
AddSimpleParticle( &newParticle, g_Mat_DustPuff[0] );
}
DECLARE_CLIENT_EFFECT( GlassImpact, GlassImpactCallback )
//-----------------------------------------------------------------------------
// Purpose:
// Input : &pos -
// *tr -
//-----------------------------------------------------------------------------
void FX_AntlionImpact( const Vector &pos, trace_t *trace )
{
#if defined( _GAMECONSOLE )
return;
#endif // _GAMECONSOLE
VPROF_BUDGET( "FX_AntlionImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
CSmartPtr<CSimple3DEmitter> fleckEmitter = CSimple3DEmitter::Create( "FX_DebrisFlecks" );
if ( fleckEmitter == NULL )
return;
Vector shotDir = ( trace->startpos - trace->endpos );
VectorNormalize( shotDir );
Vector spawnOffset = trace->endpos + ( shotDir * 2.0f );
Vector vWorldMins, vWorldMaxs;
if ( trace->m_pEnt )
{
float scale = trace->m_pEnt->CollisionProp()->BoundingRadius();
vWorldMins[0] = spawnOffset[0] - scale;
vWorldMins[1] = spawnOffset[1] - scale;
vWorldMins[2] = spawnOffset[2] - scale;
vWorldMaxs[0] = spawnOffset[0] + scale;
vWorldMaxs[1] = spawnOffset[1] + scale;
vWorldMaxs[2] = spawnOffset[2] + scale;
}
else
{
return;
}
fleckEmitter->SetSortOrigin( spawnOffset );
fleckEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
// Handle increased scale
float flMaxSpeed = 256.0f;
float flAngularSpray = 1.0f;
// Setup our collision information
fleckEmitter->m_ParticleCollision.Setup( spawnOffset, &shotDir, flAngularSpray, 8.0f, flMaxSpeed, FLECK_GRAVITY, FLECK_DAMPEN );
Vector dir, end;
Vector color = Vector( 1, 0.9, 0.75 );
float colorRamp;
int numFlecks = random->RandomInt( 8, 16 );
Particle3D *pFleckParticle;
// Dump out flecks
int i;
for ( i = 0; i < numFlecks; i++ )
{
pFleckParticle = (Particle3D *) fleckEmitter->AddParticle( sizeof(Particle3D), g_Mat_Fleck_Antlion[random->RandomInt(0,1)], spawnOffset );
if ( pFleckParticle == NULL )
break;
pFleckParticle->m_flLifeRemaining = 3.0f;
dir[0] = shotDir[0] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[1] = shotDir[1] + random->RandomFloat( -flAngularSpray, flAngularSpray );
dir[2] = shotDir[2] + random->RandomFloat( -flAngularSpray, flAngularSpray );
pFleckParticle->m_uchSize = random->RandomInt( 1, 6 );
pFleckParticle->m_vecVelocity = dir * random->RandomFloat( FLECK_MIN_SPEED, flMaxSpeed);
pFleckParticle->m_vAngles.Random( 0, 360 );
pFleckParticle->m_flAngSpeed = random->RandomFloat(-800,800);
pFleckParticle->m_uchFrontColor[0] = 255;
pFleckParticle->m_uchFrontColor[1] = 255;
pFleckParticle->m_uchFrontColor[2] = 255;
pFleckParticle->m_uchBackColor[0] = 128;
pFleckParticle->m_uchBackColor[1] = 128;
pFleckParticle->m_uchBackColor[2] = 128;
}
//
// Dust trail
//
SimpleParticle *pParticle;
CSmartPtr<CSimpleEmitter> dustEmitter = CSimpleEmitter::Create( "FX_DebrisFlecks" );
if ( !dustEmitter )
return;
Vector offset = trace->endpos + ( shotDir * 4.0f );
dustEmitter->SetSortOrigin( offset );
dustEmitter->GetBinding().SetBBox( spawnOffset-Vector(32,32,32), spawnOffset+Vector(32,32,32), true );
for ( i = 0; i < 4; i++ )
{
pParticle = (SimpleParticle *) dustEmitter->AddParticle( sizeof(SimpleParticle), g_Mat_DustPuff[0], offset );
if ( pParticle == NULL )
break;
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = 1.0f;
dir[0] = shotDir[0] + random->RandomFloat( -0.8f, 0.8f );
dir[1] = shotDir[1] + random->RandomFloat( -0.8f, 0.8f );
dir[2] = shotDir[2] + random->RandomFloat( -0.8f, 0.8f );
pParticle->m_uchStartSize = random->RandomInt( 8, 16 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4.0f;
pParticle->m_vecVelocity = dir * random->RandomFloat( 4.0f, 64.0f );
pParticle->m_uchStartAlpha = random->RandomInt( 32, 64);
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomFloat( 0, 2.0f*M_PI );
pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
colorRamp = random->RandomFloat( 0.5f, 1.0f );
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;
}
CLocalPlayerFilter filter;
C_BaseEntity::EmitSound( filter, 0, "FX_AntlionImpact.ShellImpact", &trace->endpos );
}
//-----------------------------------------------------------------------------
// Purpose: Spurt out bug blood
// Input : &pos -
// &dir -
//-----------------------------------------------------------------------------
#define NUM_BUG_BLOOD 32
#define NUM_BUG_BLOOD2 16
#define NUM_BUG_SPLATS 16
void FX_BugBlood( Vector &pos, Vector &dir, Vector &vWorldMins, Vector &vWorldMaxs )
{
VPROF_BUDGET( "FX_BugBlood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_BugBlood" );
if ( !pSimple )
return;
pSimple->SetSortOrigin( pos );
pSimple->GetBinding().SetBBox( vWorldMins, vWorldMaxs, true );
pSimple->GetBinding().SetBBox( pos-Vector(32,32,32), pos+Vector(32,32,32), true );
Vector vDir;
vDir[0] = dir[0] + random->RandomFloat( -2.0f, 2.0f );
vDir[1] = dir[1] + random->RandomFloat( -2.0f, 2.0f );
vDir[2] = dir[2] + random->RandomFloat( -2.0f, 2.0f );
VectorNormalize( vDir );
int i;
for ( i = 0; i < NUM_BUG_BLOOD; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
if ( sParticle == NULL )
return;
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.25f;
float speed = random->RandomFloat( 32.0f, 150.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] -= 32.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
for ( i = 0; i < NUM_BUG_BLOOD2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = random->RandomFloat( 8.0f, 255.0f );
sParticle->m_vecVelocity = vDir * -speed;
sParticle->m_vecVelocity[2] -= 16.0f;
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = random->RandomInt( 16, 32 );
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 3 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*random->RandomInt( 1, 4 );
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
Vector offset;
for ( i = 0; i < NUM_BUG_SPLATS; i++ )
{
offset.Random( -2, 2 );
offset += pos;
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], offset );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = 75.0f * ((i/(float)NUM_BUG_SPLATS)+1);
sParticle->m_vecVelocity.Random( -16.0f, 16.0f );
sParticle->m_vecVelocity += vDir * -speed;
sParticle->m_vecVelocity[2] -= ( 64.0f * ((i/(float)NUM_BUG_SPLATS)+1) );
sParticle->m_uchColor[0] = 255;
sParticle->m_uchColor[1] = 200;
sParticle->m_uchColor[2] = 32;
sParticle->m_uchStartAlpha = 255;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = random->RandomInt( 1, 2 );
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Blood puff
//-----------------------------------------------------------------------------
void FX_Blood( Vector &pos, Vector &dir, float r, float g, float b, float a )
{
VPROF_BUDGET( "FX_Blood", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
// Cloud
CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "FX_Blood" );
if ( !pSimple )
return;
pSimple->SetSortOrigin( pos );
Vector vDir;
vDir[0] = dir[0] + random->RandomFloat( -1.0f, 1.0f );
vDir[1] = dir[1] + random->RandomFloat( -1.0f, 1.0f );
vDir[2] = dir[2] + random->RandomFloat( -1.0f, 1.0f );
VectorNormalize( vDir );
int i;
for ( i = 0; i < 2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
float speed = random->RandomFloat( 2.0f, 8.0f );
sParticle->m_vecVelocity = vDir * (speed*i);
sParticle->m_vecVelocity[2] += random->RandomFloat( -32.0f, -16.0f );
sParticle->m_uchColor[0] = r;
sParticle->m_uchColor[1] = g;
sParticle->m_uchColor[2] = b;
sParticle->m_uchStartAlpha = a;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 2;
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
for ( i = 0; i < 2; i++ )
{
SimpleParticle *sParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[1], pos );
if ( sParticle == NULL )
{
return;
}
sParticle->m_flLifetime = 0.0f;
sParticle->m_flDieTime = 0.5f;
float speed = random->RandomFloat( 4.0f, 16.0f );
sParticle->m_vecVelocity = vDir * (speed*i);
sParticle->m_uchColor[0] = r;
sParticle->m_uchColor[1] = g;
sParticle->m_uchColor[2] = b;
sParticle->m_uchStartAlpha = 128;
sParticle->m_uchEndAlpha = 0;
sParticle->m_uchStartSize = 2;
sParticle->m_uchEndSize = sParticle->m_uchStartSize*4;
sParticle->m_flRoll = random->RandomInt( 0, 360 );
sParticle->m_flRollDelta = random->RandomFloat( -4.0f, 4.0f );
}
}
//-----------------------------------------------------------------------------
// Purpose: Dust impact
// Input : &origin - position
// &tr - trace information
//-----------------------------------------------------------------------------
void FX_DustImpact( const Vector &origin, trace_t *tr, int iScale )
{
if ( !fx_drawimpactdust.GetBool() )
return;
FX_DustImpact( origin, tr, (float)iScale );
}
void FX_DustImpact( const Vector &origin, trace_t *tr, float flScale )
{
//
// PC version
//
VPROF_BUDGET( "FX_DustImpact", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
Vector offset;
float spread = 0.2f;
CSmartPtr<CDustParticle> pSimple = CDustParticle::Create( "dust" );
pSimple->SetSortOrigin( origin );
SimpleParticle *pParticle;
Vector color;
float colorRamp;
GetColorForSurface( tr, &color );
int i;
for ( i = 0; i < 4; i++ )
{
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
if ( pParticle != NULL )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
pParticle->m_vecVelocity.Random( -spread, spread );
pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
VectorNormalize( pParticle->m_vecVelocity );
float fForce = random->RandomFloat( 250, 500 ) * i;
// scaled
pParticle->m_vecVelocity *= fForce * flScale;
colorRamp = random->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;
// scaled
pParticle->m_uchStartSize = ( unsigned char )( flScale * random->RandomInt( 3, 4 ) * (i+1) );
// scaled
pParticle->m_uchEndSize = ( unsigned char )( flScale * pParticle->m_uchStartSize * 4 );
pParticle->m_uchStartAlpha = random->RandomInt( 32, 255 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -8.0f, 8.0f );
}
}
//Dust specs
for ( i = 0; i < 4; i++ )
{
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_BloodPuff[0], origin );
if ( pParticle != NULL )
{
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.75f );
pParticle->m_vecVelocity.Random( -spread, spread );
pParticle->m_vecVelocity += ( tr->plane.normal * random->RandomFloat( 1.0f, 6.0f ) );
VectorNormalize( pParticle->m_vecVelocity );
float fForce = random->RandomFloat( 250, 500 ) * i;
pParticle->m_vecVelocity *= fForce;
colorRamp = random->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 = random->RandomInt( 2, 4 ) * (i+1);
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 2;
pParticle->m_uchStartAlpha = 255;
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -2.0f, 2.0f );
}
}
//Impact hit
for ( i = 0; i < 4; i++ )
{
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], origin );
if ( pParticle != NULL )
{
offset = origin;
offset[0] += random->RandomFloat( -8.0f, 8.0f );
offset[1] += random->RandomFloat( -8.0f, 8.0f );
pParticle->m_flLifetime = 0.0f;
pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
spread = 1.0f;
pParticle->m_vecVelocity.Random( -spread, spread );
pParticle->m_vecVelocity += tr->plane.normal;
VectorNormalize( pParticle->m_vecVelocity );
float fForce = random->RandomFloat( 0, 50 );
pParticle->m_vecVelocity *= fForce;
colorRamp = random->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 = random->RandomInt( 1, 4 );
pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4;
pParticle->m_uchStartAlpha = random->RandomInt( 32, 64 );
pParticle->m_uchEndAlpha = 0;
pParticle->m_flRoll = random->RandomInt( 0, 360 );
pParticle->m_flRollDelta = random->RandomFloat( -16.0f, 16.0f );
}
}
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : &pos -
// &dir -
// type -
//-----------------------------------------------------------------------------
void FX_GaussExplosion( const Vector &pos, const Vector &dir, int type )
{
Vector vDir;
vDir[0] = dir[0] + random->RandomFloat( -1.0f, 1.0f );
vDir[1] = dir[1] + random->RandomFloat( -1.0f, 1.0f );
vDir[2] = dir[2] + random->RandomFloat( -1.0f, 1.0f );
VectorNormalize( vDir );
int i;
#if defined(_GAMECONSOLE)
//
// XBox version
//
CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_GaussExplosion" );
if ( pSparkEmitter == NULL )
{
Assert(0);
return;
}
if ( g_Material_Spark == NULL )
{
g_Material_Spark = pSparkEmitter->GetPMaterial( "effects/spark" );
}
pSparkEmitter->SetSortOrigin( pos );
pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN );
pSparkEmitter->GetBinding().SetBBox( pos - Vector( 32, 32, 32 ), pos + Vector( 32, 32, 32 ) );
int numSparks = random->RandomInt( 8, 16 );
TrailParticle *pParticle;
// Dump out sparks
for ( i = 0; i < numSparks; i++ )
{
pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), g_Material_Spark, pos );
if ( pParticle == NULL )
return;
pParticle->m_flLifetime = 0.0f;
vDir.Random( -0.6f, 0.6f );
vDir += dir;
VectorNormalize( vDir );
pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f );
pParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
pParticle->m_vecVelocity = vDir * random->RandomFloat( 128, 512 );
Color32Init( pParticle->m_color, 255, 255, 255, 255 );
}
// End cap
SimpleParticle particle;
particle.m_Pos = pos;
particle.m_flLifetime = 0.0f;
particle.m_flDieTime = 0.1f;
particle.m_vecVelocity.Init();
particle.m_flRoll = random->RandomInt( 0, 360 );
particle.m_flRollDelta = 0.0f;
particle.m_uchColor[0] = 255;
particle.m_uchColor[1] = 255;
particle.m_uchColor[2] = 255;
particle.m_uchStartAlpha = 255;
particle.m_uchEndAlpha = 255;
particle.m_uchStartSize = random->RandomInt( 24, 32 );
particle.m_uchEndSize = 0;
AddSimpleParticle( &particle, ParticleMgr()->GetPMaterial( "effects/yellowflare" ) );
#else
//
// PC version
//
CSmartPtr<CTrailParticles> pSparkEmitter = CTrailParticles::Create( "FX_ElectricSpark" );
if ( !pSparkEmitter )
{
Assert(0);
return;
}
PMaterialHandle hMaterial = pSparkEmitter->GetPMaterial( "effects/spark" );
pSparkEmitter->SetSortOrigin( pos );
pSparkEmitter->m_ParticleCollision.SetGravity( 800.0f );
pSparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN|bitsPARTICLE_TRAIL_COLLIDE );
//Setup our collision information
pSparkEmitter->m_ParticleCollision.Setup( pos, &vDir, 0.8f, 128, 512, 800, 0.3f );
int numSparks = random->RandomInt( 16, 32 );
TrailParticle *pParticle;
// Dump out sparks
for ( i = 0; i < numSparks; i++ )
{
pParticle = (TrailParticle *) pSparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, pos );
if ( pParticle == NULL )
return;
pParticle->m_flLifetime = 0.0f;
vDir.Random( -0.6f, 0.6f );
vDir += dir;
VectorNormalize( vDir );
pParticle->m_flWidth = random->RandomFloat( 1.0f, 4.0f );
pParticle->m_flLength = random->RandomFloat( 0.01f, 0.1f );
pParticle->m_flDieTime = random->RandomFloat( 0.25f, 1.0f );
pParticle->m_vecVelocity = vDir * random->RandomFloat( 128, 512 );
Color32Init( pParticle->m_color, 255, 255, 255, 255 );
}
FX_ElectricSpark( pos, 1, 1, &vDir );
#endif
}
class C_TEGaussExplosion : public C_TEParticleSystem
{
public:
DECLARE_CLASS( C_TEGaussExplosion, C_TEParticleSystem );
DECLARE_CLIENTCLASS();
C_TEGaussExplosion();
virtual ~C_TEGaussExplosion();
public:
virtual void PostDataUpdate( DataUpdateType_t updateType );
virtual bool ShouldDraw() { return true; }
public:
int m_nType;
Vector m_vecDirection;
};
IMPLEMENT_CLIENTCLASS_EVENT_DT( C_TEGaussExplosion, DT_TEGaussExplosion, CTEGaussExplosion )
RecvPropInt(RECVINFO(m_nType)),
RecvPropVector(RECVINFO(m_vecDirection)),
END_RECV_TABLE()
//==================================================
// C_TEGaussExplosion
//==================================================
C_TEGaussExplosion::C_TEGaussExplosion()
{
}
C_TEGaussExplosion::~C_TEGaussExplosion()
{
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : bNewEntity - whether or not to start a new entity
//-----------------------------------------------------------------------------
void C_TEGaussExplosion::PostDataUpdate( DataUpdateType_t updateType )
{
FX_GaussExplosion( m_vecOrigin, m_vecDirection, m_nType );
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : filter -
// delay -
// &pos -
// &dir -
// type -
//-----------------------------------------------------------------------------
void TE_GaussExplosion( IRecipientFilter& filter, float delay, const Vector &pos, const Vector &dir, int type )
{
FX_GaussExplosion( pos, dir, type );
}