|
|
//========= Copyright Valve Corporation, All rights reserved. ============//
//
// Purpose:
//
// $Workfile: $
// $NoKeywords: $
//=============================================================================//
#include "cbase.h"
#include "model_types.h"
#include "view_shared.h"
#include "iviewrender.h"
#include "tempentity.h"
#include "dlight.h"
#include "tempent.h"
#include "c_te_legacytempents.h"
#include "clientsideeffects.h"
#include "cl_animevent.h"
#include "iefx.h"
#include "engine/IEngineSound.h"
#include "env_wind_shared.h"
#include "clienteffectprecachesystem.h"
#include "fx_sparks.h"
#include "fx.h"
#include "movevars_shared.h"
#include "engine/ivmodelinfo.h"
#include "SoundEmitterSystem/isoundemittersystembase.h"
#include "view.h"
#include "tier0/vprof.h"
#include "particles_localspace.h"
#include "physpropclientside.h"
#include "tier0/icommandline.h"
#include "datacache/imdlcache.h"
#include "engine/ivdebugoverlay.h"
#include "effect_dispatch_data.h"
#include "c_te_effect_dispatch.h"
#include "c_props.h"
#include "c_basedoor.h"
// NOTE: Always include this last!
#include "tier0/memdbgon.h"
extern ConVar muzzleflash_light;
#define TENT_WIND_ACCEL 50
//Precache the effects
#ifndef TF_CLIENT_DLL
CLIENTEFFECT_REGISTER_BEGIN( PrecacheEffectMuzzleFlash )
CLIENTEFFECT_MATERIAL( "effects/muzzleflash1" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash2" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash3" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash4" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash1_noz" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash2_noz" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash3_noz" ) CLIENTEFFECT_MATERIAL( "effects/muzzleflash4_noz" ) #ifndef CSTRIKE_DLL
CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle1_noz" ) CLIENTEFFECT_MATERIAL( "effects/combinemuzzle2_noz" ) CLIENTEFFECT_MATERIAL( "effects/strider_muzzle" ) #endif
CLIENTEFFECT_REGISTER_END() #endif
//Whether or not to eject brass from weapons
ConVar cl_ejectbrass( "cl_ejectbrass", "1" );
ConVar func_break_max_pieces( "func_break_max_pieces", "15", FCVAR_ARCHIVE | FCVAR_REPLICATED );
ConVar cl_fasttempentcollision( "cl_fasttempentcollision", "5" );
#if !defined( HL1_CLIENT_DLL ) // HL1 implements a derivative of CTempEnts
// Temp entity interface
static CTempEnts g_TempEnts; // Expose to rest of the client .dll
ITempEnts *tempents = ( ITempEnts * )&g_TempEnts; #endif
C_LocalTempEntity::C_LocalTempEntity() { #ifdef _DEBUG
tentOffset.Init(); m_vecTempEntVelocity.Init(); m_vecTempEntAngVelocity.Init(); m_vecNormal.Init(); #endif
m_vecTempEntAcceleration.Init(); m_pfnDrawHelper = 0; m_pszImpactEffect = NULL; }
#if defined( CSTRIKE_DLL ) || defined (SDK_DLL )
#define TE_RIFLE_SHELL 1024
#define TE_PISTOL_SHELL 2048
#define TE_SHOTGUN_SHELL 4096
#endif
//-----------------------------------------------------------------------------
// Purpose: Prepare a temp entity for creation
// Input : time -
// *model -
//-----------------------------------------------------------------------------
void C_LocalTempEntity::Prepare( const model_t *pmodel, float time ) { Interp_SetupMappings( GetVarMapping() );
index = -1; Clear();
// Use these to set per-frame and termination conditions / actions
flags = FTENT_NONE; die = time + 0.75; SetModelPointer( pmodel ); SetRenderMode( kRenderNormal ); m_nRenderFX = kRenderFxNone; m_nBody = 0; m_nSkin = 0; fadeSpeed = 0.5; hitSound = 0; clientIndex = -1; bounceFactor = 1; m_nFlickerFrame = 0; m_bParticleCollision = false; }
//-----------------------------------------------------------------------------
// Sets the velocity
//-----------------------------------------------------------------------------
void C_LocalTempEntity::SetVelocity( const Vector &vecVelocity ) { m_vecTempEntVelocity = vecVelocity; }
//-----------------------------------------------------------------------------
// Sets the velocity
//-----------------------------------------------------------------------------
void C_LocalTempEntity::SetAcceleration( const Vector &vecVelocity ) { m_vecTempEntAcceleration = vecVelocity; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : int
//-----------------------------------------------------------------------------
int C_LocalTempEntity::DrawStudioModel( int modelFlags ) { VPROF_BUDGET( "C_LocalTempEntity::DrawStudioModel", VPROF_BUDGETGROUP_MODEL_RENDERING ); int drawn = 0;
if ( !GetModel() || modelinfo->GetModelType( GetModel() ) != mod_studio ) return drawn; // Make sure m_pstudiohdr is valid for drawing
MDLCACHE_CRITICAL_SECTION(); if ( !GetModelPtr() ) return drawn;
if ( m_pfnDrawHelper ) { drawn = ( *m_pfnDrawHelper )( this, modelFlags); } else { drawn = modelrender->DrawModel( modelFlags, this, MODEL_INSTANCE_INVALID, index, GetModel(), GetAbsOrigin(), GetAbsAngles(), m_nSkin, m_nBody, m_nHitboxSet ); } return drawn; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : flags -
//-----------------------------------------------------------------------------
int C_LocalTempEntity::DrawModel( int modelFlags ) { int drawn = 0;
if ( !GetModel() ) { return drawn; }
if ( GetRenderMode() == kRenderNone ) return drawn;
if ( this->flags & FTENT_BEOCCLUDED ) { // Check normal
Vector vecDelta = (GetAbsOrigin() - MainViewOrigin()); VectorNormalize( vecDelta ); float flDot = DotProduct( m_vecNormal, vecDelta ); if ( flDot > 0 ) { float flAlpha = RemapVal( MIN(flDot,0.3), 0, 0.3, 0, 1 ); flAlpha = MAX( 1.0, tempent_renderamt - (tempent_renderamt * flAlpha) ); SetRenderColorA( flAlpha ); } }
switch ( modelinfo->GetModelType( GetModel() ) ) { case mod_sprite: drawn = DrawSprite( this, GetModel(), GetAbsOrigin(), GetAbsAngles(), m_flFrame, // sprite frame to render
m_nBody > 0 ? cl_entitylist->GetBaseEntity( m_nBody ) : NULL, // attach to
m_nSkin, // attachment point
GetRenderMode(), // rendermode
m_nRenderFX, // renderfx
m_clrRender->a, // alpha
m_clrRender->r, m_clrRender->g, m_clrRender->b, m_flSpriteScale // sprite scale
); break; case mod_studio: drawn = DrawStudioModel( modelFlags ); break; default: break; }
return drawn; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : Returns true on success, false on failure.
//-----------------------------------------------------------------------------
bool C_LocalTempEntity::IsActive( void ) { bool active = true;
float life = die - gpGlobals->curtime; if ( life < 0 ) { if ( flags & FTENT_FADEOUT ) { int alpha; if (GetRenderMode() == kRenderNormal) { SetRenderMode( kRenderTransTexture ); } alpha = tempent_renderamt * ( 1 + life * fadeSpeed ); if ( alpha <= 0 ) { active = false; alpha = 0; }
SetRenderColorA( alpha ); } else { active = false; } }
// Never die tempents only die when their die is cleared
if ( flags & FTENT_NEVERDIE ) { active = (die != 0); }
return active; }
bool C_LocalTempEntity::Frame( float frametime, int framenumber ) { float fastFreq = gpGlobals->curtime * 5.5; float gravity = -frametime * GetCurrentGravity(); float gravitySlow = gravity * 0.5; float traceFraction = 1;
Assert( !GetMoveParent() );
m_vecPrevLocalOrigin = GetLocalOrigin();
m_vecTempEntVelocity = m_vecTempEntVelocity + ( m_vecTempEntAcceleration * frametime );
if ( flags & FTENT_PLYRATTACHMENT ) { if ( IClientEntity *pClient = cl_entitylist->GetClientEntity( clientIndex ) ) { SetLocalOrigin( pClient->GetAbsOrigin() + tentOffset ); } } else if ( flags & FTENT_SINEWAVE ) { x += m_vecTempEntVelocity[0] * frametime; y += m_vecTempEntVelocity[1] * frametime;
SetLocalOrigin( Vector( x + sin( m_vecTempEntVelocity[2] + gpGlobals->curtime /* * anim.prevframe */ ) * (10*m_flSpriteScale), y + sin( m_vecTempEntVelocity[2] + fastFreq + 0.7 ) * (8*m_flSpriteScale), GetLocalOriginDim( Z_INDEX ) + m_vecTempEntVelocity[2] * frametime ) ); } else if ( flags & FTENT_SPIRAL ) { float s, c; SinCos( m_vecTempEntVelocity[2] + fastFreq, &s, &c );
SetLocalOrigin( GetLocalOrigin() + Vector( m_vecTempEntVelocity[0] * frametime + 8 * sin( gpGlobals->curtime * 20 ), m_vecTempEntVelocity[1] * frametime + 4 * sin( gpGlobals->curtime * 30 ), m_vecTempEntVelocity[2] * frametime ) ); } else { SetLocalOrigin( GetLocalOrigin() + m_vecTempEntVelocity * frametime ); } if ( flags & FTENT_SPRANIMATE ) { m_flFrame += frametime * m_flFrameRate; if ( m_flFrame >= m_flFrameMax ) { m_flFrame = m_flFrame - (int)(m_flFrame);
if ( !(flags & FTENT_SPRANIMATELOOP) ) { // this animating sprite isn't set to loop, so destroy it.
die = 0.0f; return false; } } } else if ( flags & FTENT_SPRCYCLE ) { m_flFrame += frametime * 10; if ( m_flFrame >= m_flFrameMax ) { m_flFrame = m_flFrame - (int)(m_flFrame); } }
if ( flags & FTENT_SMOKEGROWANDFADE ) { m_flSpriteScale += frametime * 0.5f; //m_clrRender.a -= frametime * 1500;
}
if ( flags & FTENT_ROTATE ) { SetLocalAngles( GetLocalAngles() + m_vecTempEntAngVelocity * frametime ); } else if ( flags & FTENT_ALIGNTOMOTION ) { if ( m_vecTempEntVelocity.Length() > 0.0f ) { QAngle angles; VectorAngles( m_vecTempEntVelocity, angles ); SetAbsAngles( angles ); } }
if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEWORLD | FTENT_COLLIDEPROPS ) ) { Vector traceNormal; traceNormal.Init(); bool bShouldCollide = true;
trace_t trace;
if ( flags & (FTENT_COLLIDEALL | FTENT_COLLIDEPROPS) ) { Vector vPrevOrigin = m_vecPrevLocalOrigin;
if ( cl_fasttempentcollision.GetInt() > 0 && flags & FTENT_USEFASTCOLLISIONS ) { if ( m_iLastCollisionFrame + cl_fasttempentcollision.GetInt() > gpGlobals->framecount ) { bShouldCollide = false; } else { if ( m_vLastCollisionOrigin != vec3_origin ) { vPrevOrigin = m_vLastCollisionOrigin; }
m_iLastCollisionFrame = gpGlobals->framecount; bShouldCollide = true; } }
if ( bShouldCollide == true ) { // If the FTENT_COLLISIONGROUP flag is set, use the entity's collision group
int collisionGroup = COLLISION_GROUP_NONE; if ( flags & FTENT_COLLISIONGROUP ) { collisionGroup = GetCollisionGroup(); }
UTIL_TraceLine( vPrevOrigin, GetLocalOrigin(), MASK_SOLID, GetOwnerEntity(), collisionGroup, &trace );
if ( (flags & FTENT_COLLIDEPROPS) && trace.m_pEnt ) { bool bIsDynamicProp = ( NULL != dynamic_cast<CDynamicProp *>( trace.m_pEnt ) ); bool bIsDoor = ( NULL != dynamic_cast<CBaseDoor *>( trace.m_pEnt ) ); if ( !bIsDynamicProp && !bIsDoor && !trace.m_pEnt->IsWorld() ) // Die on props, doors, and the world.
return true; }
// Make sure it didn't bump into itself... (?!?)
if ( (trace.fraction != 1) && ( (trace.DidHitWorld()) || (trace.m_pEnt != ClientEntityList().GetEnt(clientIndex)) ) ) { traceFraction = trace.fraction; VectorCopy( trace.plane.normal, traceNormal ); }
m_vLastCollisionOrigin = trace.endpos; } } else if ( flags & FTENT_COLLIDEWORLD ) { CTraceFilterWorldOnly traceFilter; UTIL_TraceLine( m_vecPrevLocalOrigin, GetLocalOrigin(), MASK_SOLID, &traceFilter, &trace ); if ( trace.fraction != 1 ) { traceFraction = trace.fraction; VectorCopy( trace.plane.normal, traceNormal ); } } if ( traceFraction != 1 ) // Decent collision now, and damping works
{ float proj, damp; SetLocalOrigin( trace.endpos ); // Damp velocity
damp = bounceFactor; if ( flags & (FTENT_GRAVITY|FTENT_SLOWGRAVITY) ) { damp *= 0.5; if ( traceNormal[2] > 0.9 ) // Hit floor?
{ if ( m_vecTempEntVelocity[2] <= 0 && m_vecTempEntVelocity[2] >= gravity*3 ) { damp = 0; // Stop
flags &= ~(FTENT_ROTATE|FTENT_GRAVITY|FTENT_SLOWGRAVITY|FTENT_COLLIDEWORLD|FTENT_SMOKETRAIL); SetLocalAnglesDim( X_INDEX, 0 ); SetLocalAnglesDim( Z_INDEX, 0 ); } } }
if ( flags & (FTENT_CHANGERENDERONCOLLIDE) ) { m_RenderGroup = RENDER_GROUP_OTHER; flags &= ~FTENT_CHANGERENDERONCOLLIDE; }
if (hitSound) { tempents->PlaySound(this, damp); }
if ( m_pszImpactEffect ) { CEffectData data; //data.m_vOrigin = newOrigin;
data.m_vOrigin = trace.endpos; data.m_vStart = trace.startpos; data.m_nSurfaceProp = trace.surface.surfaceProps; data.m_nHitBox = trace.hitbox;
data.m_nDamageType = TEAM_UNASSIGNED;
IClientNetworkable *pClient = cl_entitylist->GetClientEntity( clientIndex );
if ( pClient ) { C_BasePlayer *pPlayer = dynamic_cast<C_BasePlayer*>(pClient); if( pPlayer ) { data.m_nDamageType = pPlayer->GetTeamNumber(); } }
if ( trace.m_pEnt ) { data.m_hEntity = ClientEntityList().EntIndexToHandle( trace.m_pEnt->entindex() ); } DispatchEffect( m_pszImpactEffect, data ); }
// Check for a collision and stop the particle system.
if ( flags & FTENT_CLIENTSIDEPARTICLES ) { // Stop the emission of particles on collision - removed from the ClientEntityList on removal from the tempent pool.
ParticleProp()->StopEmission(); m_bParticleCollision = true; }
if (flags & FTENT_COLLIDEKILL) { // die on impact
flags &= ~FTENT_FADEOUT; die = gpGlobals->curtime; } else if ( flags & FTENT_ATTACHTOTARGET) { // If we've hit the world, just stop moving
if ( trace.DidHitWorld() && !( trace.surface.flags & SURF_SKY ) ) { m_vecTempEntVelocity = vec3_origin; m_vecTempEntAcceleration = vec3_origin;
// Remove movement flags so we don't keep tracing
flags &= ~(FTENT_COLLIDEALL | FTENT_COLLIDEWORLD); } else { // Couldn't attach to this entity. Die.
flags &= ~FTENT_FADEOUT; die = gpGlobals->curtime; } } else { // Reflect velocity
if ( damp != 0 ) { proj = ((Vector)m_vecTempEntVelocity).Dot(traceNormal); VectorMA( m_vecTempEntVelocity, -proj*2, traceNormal, m_vecTempEntVelocity ); // Reflect rotation (fake)
SetLocalAnglesDim( Y_INDEX, -GetLocalAnglesDim( Y_INDEX ) ); } if ( damp != 1 ) { VectorScale( m_vecTempEntVelocity, damp, m_vecTempEntVelocity ); SetLocalAngles( GetLocalAngles() * 0.9 ); } } } }
if ( (flags & FTENT_FLICKER) && framenumber == m_nFlickerFrame ) { dlight_t *dl = effects->CL_AllocDlight (LIGHT_INDEX_TE_DYNAMIC); VectorCopy (GetLocalOrigin(), dl->origin); dl->radius = 60; dl->color.r = 255; dl->color.g = 120; dl->color.b = 0; dl->die = gpGlobals->curtime + 0.01; }
if ( flags & FTENT_SMOKETRAIL ) { Assert( !"FIXME: Rework smoketrail to be client side\n" ); }
// add gravity if we didn't collide in this frame
if ( traceFraction == 1 ) { if ( flags & FTENT_GRAVITY ) m_vecTempEntVelocity[2] += gravity; else if ( flags & FTENT_SLOWGRAVITY ) m_vecTempEntVelocity[2] += gravitySlow; }
if ( flags & FTENT_WINDBLOWN ) { Vector vecWind; GetWindspeedAtTime( gpGlobals->curtime, vecWind );
for ( int i = 0 ; i < 2 ; i++ ) { if ( m_vecTempEntVelocity[i] < vecWind[i] ) { m_vecTempEntVelocity[i] += ( frametime * TENT_WIND_ACCEL );
// clamp
if ( m_vecTempEntVelocity[i] > vecWind[i] ) m_vecTempEntVelocity[i] = vecWind[i]; } else if (m_vecTempEntVelocity[i] > vecWind[i] ) { m_vecTempEntVelocity[i] -= ( frametime * TENT_WIND_ACCEL );
// clamp.
if ( m_vecTempEntVelocity[i] < vecWind[i] ) m_vecTempEntVelocity[i] = vecWind[i]; } } }
return true; }
//-----------------------------------------------------------------------------
// Purpose: Attach a particle effect to a temp entity.
//-----------------------------------------------------------------------------
CNewParticleEffect* C_LocalTempEntity::AddParticleEffect( const char *pszParticleEffect ) { // Do we have a valid particle effect.
if ( !pszParticleEffect || ( pszParticleEffect[0] == '\0' ) ) return NULL;
// Check to see that we don't already have a particle effect.
if ( ( flags & FTENT_CLIENTSIDEPARTICLES ) != 0 ) return NULL;
// Add the entity to the ClientEntityList and create the particle system.
ClientEntityList().AddNonNetworkableEntity( this ); CNewParticleEffect* pEffect = ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW );
// Set the particle flag on the temp entity and save the name of the particle effect.
flags |= FTENT_CLIENTSIDEPARTICLES; SetParticleEffect( pszParticleEffect );
return pEffect; }
//-----------------------------------------------------------------------------
// Purpose: This helper keeps track of batches of "breakmodels" so that they can all share the lighting origin
// of the first of the group (because the server sends down 15 chunks at a time, and rebuilding 15 light cache
// entries for a map with a lot of worldlights is really slow).
//-----------------------------------------------------------------------------
class CBreakableHelper { public: void Insert( C_LocalTempEntity *entity, bool isSlave ); void Remove( C_LocalTempEntity *entity );
void Clear();
const Vector *GetLightingOrigin( C_LocalTempEntity *entity );
private:
// A context is the first master until the next one, which starts a new context
struct BreakableList_t { unsigned int context; C_LocalTempEntity *entity; };
CUtlLinkedList< BreakableList_t, unsigned short > m_Breakables; unsigned int m_nCurrentContext; };
//-----------------------------------------------------------------------------
// Purpose: Adds brekable to list, starts new context if needed
// Input : *entity -
// isSlave -
//-----------------------------------------------------------------------------
void CBreakableHelper::Insert( C_LocalTempEntity *entity, bool isSlave ) { // A master signifies the start of a new run of broken objects
if ( !isSlave ) { ++m_nCurrentContext; } BreakableList_t entry; entry.context = m_nCurrentContext; entry.entity = entity;
m_Breakables.AddToTail( entry ); }
//-----------------------------------------------------------------------------
// Purpose: Removes all instances of entity in the list
// Input : *entity -
//-----------------------------------------------------------------------------
void CBreakableHelper::Remove( C_LocalTempEntity *entity ) { for ( unsigned short i = m_Breakables.Head(); i != m_Breakables.InvalidIndex() ; ) { unsigned short n = m_Breakables.Next( i );
if ( m_Breakables[ i ].entity == entity ) { m_Breakables.Remove( i ); }
i = n; } }
//-----------------------------------------------------------------------------
// Purpose: For a given breakable, find the "first" or head object and use it's current
// origin as the lighting origin for the entire group of objects
// Input : *entity -
// Output : const Vector
//-----------------------------------------------------------------------------
const Vector *CBreakableHelper::GetLightingOrigin( C_LocalTempEntity *entity ) { unsigned int nCurContext = 0; C_LocalTempEntity *head = NULL; FOR_EACH_LL( m_Breakables, i ) { BreakableList_t& e = m_Breakables[ i ];
if ( e.context != nCurContext ) { nCurContext = e.context; head = e.entity; }
if ( e.entity == entity ) { Assert( head ); return head ? &head->GetAbsOrigin() : NULL; } } return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Wipe breakable helper list
// Input : -
//-----------------------------------------------------------------------------
void CBreakableHelper::Clear() { m_Breakables.RemoveAll(); m_nCurrentContext = 0; }
static CBreakableHelper g_BreakableHelper;
//-----------------------------------------------------------------------------
// Purpose: See if it's in the breakable helper list and, if so, remove
// Input : -
//-----------------------------------------------------------------------------
void C_LocalTempEntity::OnRemoveTempEntity() { g_BreakableHelper.Remove( this ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTempEnts::CTempEnts( void ) : m_TempEntsPool( ( MAX_TEMP_ENTITIES / 20 ), CUtlMemoryPool::GROW_SLOW ) { }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
CTempEnts::~CTempEnts( void ) { m_TempEntsPool.Clear(); m_TempEnts.RemoveAll(); }
//-----------------------------------------------------------------------------
// Purpose: Create a fizz effect
// Input : *pent -
// modelIndex -
// density -
//-----------------------------------------------------------------------------
void CTempEnts::FizzEffect( C_BaseEntity *pent, int modelIndex, int density, int current ) { C_LocalTempEntity *pTemp; const model_t *model; int i, width, depth, count, frameCount; float maxHeight, speed, xspeed, yspeed; Vector origin; Vector mins, maxs;
if ( !pent->GetModel() || !modelIndex ) return;
model = modelinfo->GetModel( modelIndex ); if ( !model ) return;
count = density + 1; density = count * 3 + 6;
modelinfo->GetModelBounds( pent->GetModel(), mins, maxs );
maxHeight = maxs[2] - mins[2]; width = maxs[0] - mins[0]; depth = maxs[1] - mins[1]; speed = current;
SinCos( pent->GetLocalAngles()[1]*M_PI/180, &yspeed, &xspeed ); xspeed *= speed; yspeed *= speed; frameCount = modelinfo->GetModelFrameCount( model );
for (i=0 ; i<count ; i++) { origin[0] = mins[0] + random->RandomInt(0,width-1); origin[1] = mins[1] + random->RandomInt(0,depth-1); origin[2] = mins[2]; pTemp = TempEntAlloc( origin, model ); if (!pTemp) return;
pTemp->flags |= FTENT_SINEWAVE;
pTemp->x = origin[0]; pTemp->y = origin[1];
float zspeed = random->RandomInt(80,140); pTemp->SetVelocity( Vector(xspeed, yspeed, zspeed) ); pTemp->die = gpGlobals->curtime + (maxHeight / zspeed) - 0.1; pTemp->m_flFrame = random->RandomInt(0,frameCount-1); // Set sprite scale
pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(2,5); pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->SetRenderColorA( 255 ); } }
//-----------------------------------------------------------------------------
// Purpose: Create bubbles
// Input : *mins -
// *maxs -
// height -
// modelIndex -
// count -
// speed -
//-----------------------------------------------------------------------------
void CTempEnts::Bubbles( const Vector &mins, const Vector &maxs, float height, int modelIndex, int count, float speed ) { C_LocalTempEntity *pTemp; const model_t *model; int i, frameCount; float sine, cosine; Vector origin;
if ( !modelIndex ) return;
model = modelinfo->GetModel( modelIndex ); if ( !model ) return;
frameCount = modelinfo->GetModelFrameCount( model );
for (i=0 ; i<count ; i++) { origin[0] = random->RandomInt( mins[0], maxs[0] ); origin[1] = random->RandomInt( mins[1], maxs[1] ); origin[2] = random->RandomInt( mins[2], maxs[2] ); pTemp = TempEntAlloc( origin, model ); if (!pTemp) return;
pTemp->flags |= FTENT_SINEWAVE;
pTemp->x = origin[0]; pTemp->y = origin[1]; SinCos( random->RandomInt( -3, 3 ), &sine, &cosine ); float zspeed = random->RandomInt(80,140); pTemp->SetVelocity( Vector(speed * cosine, speed * sine, zspeed) ); pTemp->die = gpGlobals->curtime + ((height - (origin[2] - mins[2])) / zspeed) - 0.1; pTemp->m_flFrame = random->RandomInt( 0, frameCount-1 ); // Set sprite scale
pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,16); pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->SetRenderColor( 255, 255, 255, 192 ); } }
//-----------------------------------------------------------------------------
// Purpose: Create bubble trail
// Input : *start -
// *end -
// height -
// modelIndex -
// count -
// speed -
//-----------------------------------------------------------------------------
void CTempEnts::BubbleTrail( const Vector &start, const Vector &end, float flWaterZ, int modelIndex, int count, float speed ) { C_LocalTempEntity *pTemp; const model_t *model; int i, frameCount; float dist, angle; Vector origin;
if ( !modelIndex ) return;
model = modelinfo->GetModel( modelIndex ); if ( !model ) return;
frameCount = modelinfo->GetModelFrameCount( model );
for (i=0 ; i<count ; i++) { dist = random->RandomFloat( 0, 1.0 ); VectorLerp( start, end, dist, origin ); pTemp = TempEntAlloc( origin, model ); if (!pTemp) return;
pTemp->flags |= FTENT_SINEWAVE;
pTemp->x = origin[0]; pTemp->y = origin[1]; angle = random->RandomInt( -3, 3 );
float zspeed = random->RandomInt(80,140); pTemp->SetVelocity( Vector(speed * cos(angle), speed * sin(angle), zspeed) ); pTemp->die = gpGlobals->curtime + ((flWaterZ - origin[2]) / zspeed) - 0.1; pTemp->m_flFrame = random->RandomInt(0,frameCount-1); // Set sprite scale
pTemp->m_flSpriteScale = 1.0 / random->RandomFloat(4,8); pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->SetRenderColor( 255, 255, 255, 192 ); } }
#define SHARD_VOLUME 12.0 // on shard ever n^3 units
//-----------------------------------------------------------------------------
// Purpose: Only used by BreakModel temp ents for now. Allows them to share a single
// lighting origin amongst a group of objects. If the master object goes away, the next object
// in the group becomes the new lighting origin, etc.
// Input : *entity -
// flags -
// Output : int
//-----------------------------------------------------------------------------
int BreakModelDrawHelper( C_LocalTempEntity *entity, int flags ) { ModelRenderInfo_t sInfo; sInfo.flags = flags; sInfo.pRenderable = entity; sInfo.instance = MODEL_INSTANCE_INVALID; sInfo.entity_index = entity->index; sInfo.pModel = entity->GetModel(); sInfo.origin = entity->GetRenderOrigin(); sInfo.angles = entity->GetRenderAngles(); sInfo.skin = entity->m_nSkin; sInfo.body = entity->m_nBody; sInfo.hitboxset = entity->m_nHitboxSet;
// This is the main change, look up a lighting origin from the helper singleton
const Vector *pLightingOrigin = g_BreakableHelper.GetLightingOrigin( entity ); if ( pLightingOrigin ) { sInfo.pLightingOrigin = pLightingOrigin; }
int drawn = modelrender->DrawModelEx( sInfo ); return drawn; }
//-----------------------------------------------------------------------------
// Purpose: Create model shattering shards
// Input : *pos -
// *size -
// *dir -
// random -
// life -
// count -
// modelIndex -
// flags -
//-----------------------------------------------------------------------------
void CTempEnts::BreakModel( const Vector &pos, const QAngle &angles, const Vector &size, const Vector &dir, float randRange, float life, int count, int modelIndex, char flags) { int i, frameCount; C_LocalTempEntity *pTemp; const model_t *pModel;
if (!modelIndex) return;
pModel = modelinfo->GetModel( modelIndex ); if ( !pModel ) return;
// See g_BreakableHelper above for notes...
bool isSlave = ( flags & BREAK_SLAVE ) ? true : false;
frameCount = modelinfo->GetModelFrameCount( pModel );
if (count == 0) { // assume surface (not volume)
count = (size[0] * size[1] + size[1] * size[2] + size[2] * size[0])/(3 * SHARD_VOLUME * SHARD_VOLUME); }
if ( count > func_break_max_pieces.GetInt() ) { count = func_break_max_pieces.GetInt(); }
matrix3x4_t transform; AngleMatrix( angles, pos, transform ); for ( i = 0; i < count; i++ ) { Vector vecLocalSpot, vecSpot;
// fill up the box with stuff
vecLocalSpot[0] = random->RandomFloat(-0.5,0.5) * size[0]; vecLocalSpot[1] = random->RandomFloat(-0.5,0.5) * size[1]; vecLocalSpot[2] = random->RandomFloat(-0.5,0.5) * size[2]; VectorTransform( vecLocalSpot, transform, vecSpot );
pTemp = TempEntAlloc(vecSpot, pModel); if (!pTemp) return;
// keep track of break_type, so we know how to play sound on collision
pTemp->hitSound = flags; if ( modelinfo->GetModelType( pModel ) == mod_sprite ) { pTemp->m_flFrame = random->RandomInt(0,frameCount-1); } else if ( modelinfo->GetModelType( pModel ) == mod_studio ) { pTemp->m_nBody = random->RandomInt(0,frameCount-1); }
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
if ( random->RandomInt(0,255) < 200 ) { pTemp->flags |= FTENT_ROTATE; pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-256,255); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-256,255); pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-256,255); }
if ( (random->RandomInt(0,255) < 100 ) && (flags & BREAK_SMOKE) ) { pTemp->flags |= FTENT_SMOKETRAIL; }
if ((flags & BREAK_GLASS) || (flags & BREAK_TRANS)) { pTemp->SetRenderMode( kRenderTransTexture ); pTemp->SetRenderColorA( 128 ); pTemp->tempent_renderamt = 128; pTemp->bounceFactor = 0.3f; } else { pTemp->SetRenderMode( kRenderNormal ); pTemp->tempent_renderamt = 255; // Set this for fadeout
}
pTemp->SetVelocity( Vector( dir[0] + random->RandomFloat(-randRange,randRange), dir[1] + random->RandomFloat(-randRange,randRange), dir[2] + random->RandomFloat( 0,randRange) ) );
pTemp->die = gpGlobals->curtime + life + random->RandomFloat(0,1); // Add an extra 0-1 secs of life
// We use a special rendering function because these objects will want to share their lighting
// origin with the first/master object. Prevents a huge spike in Light Cache building in maps
// with many worldlights.
pTemp->SetDrawHelper( BreakModelDrawHelper ); g_BreakableHelper.Insert( pTemp, isSlave ); } }
void CTempEnts::PhysicsProp( int modelindex, int skin, const Vector& pos, const QAngle &angles, const Vector& vel, int physFlags, int physEffects ) { C_PhysPropClientside *pEntity = C_PhysPropClientside::CreateNew(); if ( !pEntity ) return;
const model_t *model = modelinfo->GetModel( modelindex );
if ( !model ) { DevMsg("CTempEnts::PhysicsProp: model index %i not found\n", modelindex ); return; }
pEntity->SetModelName( modelinfo->GetModelName(model) ); pEntity->m_nSkin = skin; pEntity->SetAbsOrigin( pos ); pEntity->SetAbsAngles( angles ); pEntity->SetPhysicsMode( PHYSICS_MULTIPLAYER_CLIENTSIDE ); pEntity->SetEffects( physEffects );
if ( !pEntity->Initialize() ) { pEntity->Release(); return; }
IPhysicsObject *pPhysicsObject = pEntity->VPhysicsGetObject();
if( pPhysicsObject ) { pPhysicsObject->AddVelocity( &vel, NULL ); } else { // failed to create a physics object
pEntity->Release(); return; }
if ( physFlags & 1 ) { pEntity->SetHealth( 0 ); pEntity->Break(); } }
//-----------------------------------------------------------------------------
// Purpose: Create a clientside projectile
// Input : vecOrigin -
// vecVelocity -
// modelindex -
// lifetime -
// *pOwner -
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::ClientProjectile( const Vector& vecOrigin, const Vector& vecVelocity, const Vector& vecAcceleration, int modelIndex, int lifetime, CBaseEntity *pOwner, const char *pszImpactEffect, const char *pszParticleEffect ) { C_LocalTempEntity *pTemp; const model_t *model;
if ( !modelIndex ) return NULL;
model = modelinfo->GetModel( modelIndex ); if ( !model ) { Warning("ClientProjectile: No model %d!\n", modelIndex); return NULL; }
pTemp = TempEntAlloc( vecOrigin, model ); if (!pTemp) return NULL;
pTemp->SetVelocity( vecVelocity ); pTemp->SetAcceleration( vecAcceleration ); QAngle angles; VectorAngles( vecVelocity, angles ); pTemp->SetAbsAngles( angles ); pTemp->SetAbsOrigin( vecOrigin ); pTemp->die = gpGlobals->curtime + lifetime; pTemp->flags = FTENT_COLLIDEALL | FTENT_ATTACHTOTARGET | FTENT_ALIGNTOMOTION; pTemp->clientIndex = ( pOwner != NULL ) ? pOwner->entindex() : 0; pTemp->SetOwnerEntity( pOwner ); pTemp->SetImpactEffect( pszImpactEffect ); if ( pszParticleEffect ) { // Add the entity to the ClientEntityList and create the particle system.
ClientEntityList().AddNonNetworkableEntity( pTemp ); pTemp->ParticleProp()->Create( pszParticleEffect, PATTACH_ABSORIGIN_FOLLOW );
// Set the particle flag on the temp entity and save the name of the particle effect.
pTemp->flags |= FTENT_CLIENTSIDEPARTICLES; pTemp->SetParticleEffect( pszParticleEffect ); } return pTemp; }
//-----------------------------------------------------------------------------
// Purpose: Create sprite TE
// Input : *pos -
// *dir -
// scale -
// modelIndex -
// rendermode -
// renderfx -
// a -
// life -
// flags -
// Output : C_LocalTempEntity
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::TempSprite( const Vector &pos, const Vector &dir, float scale, int modelIndex, int rendermode, int renderfx, float a, float life, int flags, const Vector &normal ) { C_LocalTempEntity *pTemp; const model_t *model; int frameCount;
if ( !modelIndex ) return NULL;
model = modelinfo->GetModel( modelIndex ); if ( !model ) { Warning("No model %d!\n", modelIndex); return NULL; }
frameCount = modelinfo->GetModelFrameCount( model );
pTemp = TempEntAlloc( pos, model ); if (!pTemp) return NULL;
pTemp->m_flFrameMax = frameCount - 1; pTemp->m_flFrameRate = 10; pTemp->SetRenderMode( (RenderMode_t)rendermode ); pTemp->m_nRenderFX = renderfx; pTemp->m_flSpriteScale = scale; pTemp->tempent_renderamt = a * 255; pTemp->m_vecNormal = normal; pTemp->SetRenderColor( 255, 255, 255, a * 255 );
pTemp->flags |= flags;
pTemp->SetVelocity( dir ); pTemp->SetLocalOrigin( pos ); if ( life ) pTemp->die = gpGlobals->curtime + life; else pTemp->die = gpGlobals->curtime + (frameCount * 0.1) + 1;
pTemp->m_flFrame = 0; return pTemp; }
//-----------------------------------------------------------------------------
// Purpose: Spray sprite
// Input : *pos -
// *dir -
// modelIndex -
// count -
// speed -
// iRand -
//-----------------------------------------------------------------------------
void CTempEnts::Sprite_Spray( const Vector &pos, const Vector &dir, int modelIndex, int count, int speed, int iRand ) { C_LocalTempEntity *pTemp; const model_t *pModel; float noise; float znoise; int frameCount; int i;
noise = (float)iRand / 100;
// more vertical displacement
znoise = noise * 1.5; if ( znoise > 1 ) { znoise = 1; }
pModel = modelinfo->GetModel( modelIndex ); if ( !pModel ) { Warning("No model %d!\n", modelIndex); return; }
frameCount = modelinfo->GetModelFrameCount( pModel ) - 1;
for ( i = 0; i < count; i++ ) { pTemp = TempEntAlloc( pos, pModel ); if (!pTemp) return;
pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->SetRenderColor( 255, 255, 255, 255 ); pTemp->tempent_renderamt = 255; pTemp->m_nRenderFX = kRenderFxNoDissipation; //pTemp->scale = random->RandomFloat( 0.1, 0.25 );
pTemp->m_flSpriteScale = 0.5; pTemp->flags |= FTENT_FADEOUT | FTENT_SLOWGRAVITY; pTemp->fadeSpeed = 2.0;
// make the spittle fly the direction indicated, but mix in some noise.
Vector velocity; velocity.x = dir[ 0 ] + random->RandomFloat ( -noise, noise ); velocity.y = dir[ 1 ] + random->RandomFloat ( -noise, noise ); velocity.z = dir[ 2 ] + random->RandomFloat ( 0, znoise ); velocity *= random->RandomFloat( (speed * 0.8), (speed * 1.2) ); pTemp->SetVelocity( velocity );
pTemp->SetLocalOrigin( pos );
pTemp->die = gpGlobals->curtime + 0.35;
pTemp->m_flFrame = random->RandomInt( 0, frameCount ); } }
void CTempEnts::Sprite_Trail( const Vector &vecStart, const Vector &vecEnd, int modelIndex, int nCount, float flLife, float flSize, float flAmplitude, int nRenderamt, float flSpeed ) { C_LocalTempEntity *pTemp; const model_t *pModel; int flFrameCount;
pModel = modelinfo->GetModel( modelIndex ); if ( !pModel ) { Warning("No model %d!\n", modelIndex); return; }
flFrameCount = modelinfo->GetModelFrameCount( pModel );
Vector vecDelta; VectorSubtract( vecEnd, vecStart, vecDelta );
Vector vecDir; VectorCopy( vecDelta, vecDir ); VectorNormalize( vecDir );
flAmplitude /= 256.0;
for ( int i = 0 ; i < nCount; i++ ) { Vector vecPos;
// Be careful of divide by 0 when using 'count' here...
if ( i == 0 ) { VectorMA( vecStart, 0, vecDelta, vecPos ); } else { VectorMA( vecStart, i / (nCount - 1.0), vecDelta, vecPos ); }
pTemp = TempEntAlloc( vecPos, pModel ); if (!pTemp) return;
pTemp->flags |= FTENT_COLLIDEWORLD | FTENT_SPRCYCLE | FTENT_FADEOUT | FTENT_SLOWGRAVITY;
Vector vecVel = vecDir * flSpeed; vecVel.x += random->RandomInt( -127,128 ) * flAmplitude; vecVel.y += random->RandomInt( -127,128 ) * flAmplitude; vecVel.z += random->RandomInt( -127,128 ) * flAmplitude; pTemp->SetVelocity( vecVel ); pTemp->SetLocalOrigin( vecPos );
pTemp->m_flSpriteScale = flSize; pTemp->SetRenderMode( kRenderGlow ); pTemp->m_nRenderFX = kRenderFxNoDissipation; pTemp->tempent_renderamt = nRenderamt; pTemp->SetRenderColor( 255, 255, 255 );
pTemp->m_flFrame = random->RandomInt( 0, flFrameCount - 1 ); pTemp->m_flFrameMax = flFrameCount - 1; pTemp->die = gpGlobals->curtime + flLife + random->RandomFloat( 0, 4 ); } }
//-----------------------------------------------------------------------------
// Purpose: Attaches entity to player
// Input : client -
// modelIndex -
// zoffset -
// life -
//-----------------------------------------------------------------------------
void CTempEnts::AttachTentToPlayer( int client, int modelIndex, float zoffset, float life ) { C_LocalTempEntity *pTemp; const model_t *pModel; Vector position; int frameCount;
if ( client <= 0 || client > gpGlobals->maxClients ) { Warning("Bad client in AttachTentToPlayer()!\n"); return; }
IClientEntity *clientClass = cl_entitylist->GetClientEntity( client ); if ( !clientClass ) { Warning("Couldn't get IClientEntity for %i\n", client ); return; }
pModel = modelinfo->GetModel( modelIndex ); if ( !pModel ) { Warning("No model %d!\n", modelIndex); return; }
VectorCopy( clientClass->GetAbsOrigin(), position ); position[ 2 ] += zoffset;
pTemp = TempEntAllocHigh( position, pModel ); if (!pTemp) { Warning("No temp ent.\n"); return; }
pTemp->SetRenderMode( kRenderNormal ); pTemp->SetRenderColorA( 255 ); pTemp->tempent_renderamt = 255; pTemp->m_nRenderFX = kRenderFxNoDissipation; pTemp->clientIndex = client; pTemp->tentOffset[ 0 ] = 0; pTemp->tentOffset[ 1 ] = 0; pTemp->tentOffset[ 2 ] = zoffset; pTemp->die = gpGlobals->curtime + life; pTemp->flags |= FTENT_PLYRATTACHMENT | FTENT_PERSIST;
// is the model a sprite?
if ( modelinfo->GetModelType( pTemp->GetModel() ) == mod_sprite ) { frameCount = modelinfo->GetModelFrameCount( pModel ); pTemp->m_flFrameMax = frameCount - 1; pTemp->flags |= FTENT_SPRANIMATE | FTENT_SPRANIMATELOOP; pTemp->m_flFrameRate = 10; } else { // no animation support for attached clientside studio models.
pTemp->m_flFrameMax = 0; }
pTemp->m_flFrame = 0; }
//-----------------------------------------------------------------------------
// Purpose: Detach entity from player
//-----------------------------------------------------------------------------
void CTempEnts::KillAttachedTents( int client ) { if ( client <= 0 || client > gpGlobals->maxClients ) { Warning("Bad client in KillAttachedTents()!\n"); return; }
FOR_EACH_LL( m_TempEnts, i ) { C_LocalTempEntity *pTemp = m_TempEnts[ i ];
if ( pTemp->flags & FTENT_PLYRATTACHMENT ) { // this TENT is player attached.
// if it is attached to this client, set it to die instantly.
if ( pTemp->clientIndex == client ) { pTemp->die = gpGlobals->curtime;// good enough, it will die on next tent update.
} } } }
//-----------------------------------------------------------------------------
// Purpose: Create ricochet sprite
// Input : *pos -
// *pmodel -
// duration -
// scale -
//-----------------------------------------------------------------------------
void CTempEnts::RicochetSprite( const Vector &pos, model_t *pmodel, float duration, float scale ) { C_LocalTempEntity *pTemp;
pTemp = TempEntAlloc( pos, pmodel ); if (!pTemp) return;
pTemp->SetRenderMode( kRenderGlow ); pTemp->m_nRenderFX = kRenderFxNoDissipation; pTemp->SetRenderColorA( 200 ); pTemp->tempent_renderamt = 200; pTemp->m_flSpriteScale = scale; pTemp->flags = FTENT_FADEOUT;
pTemp->SetVelocity( vec3_origin );
pTemp->SetLocalOrigin( pos ); pTemp->fadeSpeed = 8; pTemp->die = gpGlobals->curtime;
pTemp->m_flFrame = 0; pTemp->SetLocalAnglesDim( Z_INDEX, 45 * random->RandomInt( 0, 7 ) ); }
//-----------------------------------------------------------------------------
// Purpose: Create blood sprite
// Input : *org -
// colorindex -
// modelIndex -
// modelIndex2 -
// size -
//-----------------------------------------------------------------------------
void CTempEnts::BloodSprite( const Vector &org, int r, int g, int b, int a, int modelIndex, int modelIndex2, float size ) { const model_t *model;
//Validate the model first
if ( modelIndex && (model = modelinfo->GetModel( modelIndex ) ) != NULL ) { C_LocalTempEntity *pTemp; int frameCount = modelinfo->GetModelFrameCount( model ); color32 impactcolor = { (byte)r, (byte)g, (byte)b, (byte)a };
//Large, single blood sprite is a high-priority tent
if ( ( pTemp = TempEntAllocHigh( org, model ) ) != NULL ) { pTemp->SetRenderMode( kRenderTransTexture ); pTemp->m_nRenderFX = kRenderFxClampMinScale; pTemp->m_flSpriteScale = random->RandomFloat( size / 25, size / 35); pTemp->flags = FTENT_SPRANIMATE; pTemp->m_clrRender = impactcolor; pTemp->tempent_renderamt= pTemp->m_clrRender->a;
pTemp->SetVelocity( vec3_origin );
pTemp->m_flFrameRate = frameCount * 4; // Finish in 0.250 seconds
pTemp->die = gpGlobals->curtime + (frameCount / pTemp->m_flFrameRate); // Play the whole thing Once
pTemp->m_flFrame = 0; pTemp->m_flFrameMax = frameCount - 1; pTemp->bounceFactor = 0; pTemp->SetLocalAnglesDim( Z_INDEX, random->RandomInt( 0, 360 ) ); } } }
//-----------------------------------------------------------------------------
// Purpose: Create default sprite TE
// Input : *pos -
// spriteIndex -
// framerate -
// Output : C_LocalTempEntity
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::DefaultSprite( const Vector &pos, int spriteIndex, float framerate ) { C_LocalTempEntity *pTemp; int frameCount; const model_t *pSprite;
// don't spawn while paused
if ( gpGlobals->frametime == 0.0 ) return NULL;
pSprite = modelinfo->GetModel( spriteIndex ); if ( !spriteIndex || !pSprite || modelinfo->GetModelType( pSprite ) != mod_sprite ) { DevWarning( 1,"No Sprite %d!\n", spriteIndex); return NULL; }
frameCount = modelinfo->GetModelFrameCount( pSprite );
pTemp = TempEntAlloc( pos, pSprite ); if (!pTemp) return NULL;
pTemp->m_flFrameMax = frameCount - 1; pTemp->m_flSpriteScale = 1.0; pTemp->flags |= FTENT_SPRANIMATE; if ( framerate == 0 ) framerate = 10;
pTemp->m_flFrameRate = framerate; pTemp->die = gpGlobals->curtime + (float)frameCount / framerate; pTemp->m_flFrame = 0; pTemp->SetLocalOrigin( pos );
return pTemp; }
//-----------------------------------------------------------------------------
// Purpose: Create sprite smoke
// Input : *pTemp -
// scale -
//-----------------------------------------------------------------------------
void CTempEnts::Sprite_Smoke( C_LocalTempEntity *pTemp, float scale ) { if ( !pTemp ) return;
pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->m_nRenderFX = kRenderFxNone; pTemp->SetVelocity( Vector( 0, 0, 30 ) ); int iColor = random->RandomInt(20,35); pTemp->SetRenderColor( iColor, iColor, iColor, 255 ); pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 20 ); pTemp->m_flSpriteScale = scale; pTemp->flags = FTENT_WINDBLOWN;
}
//-----------------------------------------------------------------------------
// Purpose:
// Input : pos1 -
// angles -
// type -
//-----------------------------------------------------------------------------
void CTempEnts::EjectBrass( const Vector &pos1, const QAngle &angles, const QAngle &gunAngles, int type ) { if ( cl_ejectbrass.GetBool() == false ) return;
const model_t *pModel = m_pShells[type]; if ( pModel == NULL ) return;
C_LocalTempEntity *pTemp = TempEntAlloc( pos1, pModel );
if ( pTemp == NULL ) return;
//Keep track of shell type
if ( type == 2 ) { pTemp->hitSound = BOUNCE_SHOTSHELL; } else { pTemp->hitSound = BOUNCE_SHELL; }
pTemp->m_nBody = 0;
pTemp->flags |= ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY | FTENT_ROTATE );
pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-1024,1024); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-1024,1024); pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-1024,1024);
//Face forward
pTemp->SetAbsAngles( gunAngles );
pTemp->SetRenderMode( kRenderNormal ); pTemp->tempent_renderamt = 255; // Set this for fadeout
Vector dir;
AngleVectors( angles, &dir );
dir *= random->RandomFloat( 150.0f, 200.0f );
pTemp->SetVelocity( Vector(dir[0] + random->RandomFloat(-64,64), dir[1] + random->RandomFloat(-64,64), dir[2] + random->RandomFloat( 0,64) ) );
pTemp->die = gpGlobals->curtime + 1.0f + random->RandomFloat( 0.0f, 1.0f ); // Add an extra 0-1 secs of life
}
//-----------------------------------------------------------------------------
// Purpose: Create some simple physically simulated models
//-----------------------------------------------------------------------------
C_LocalTempEntity * CTempEnts::SpawnTempModel( const model_t *pModel, const Vector &vecOrigin, const QAngle &vecAngles, const Vector &vecVelocity, float flLifeTime, int iFlags ) { Assert( pModel );
// Alloc a new tempent
C_LocalTempEntity *pTemp = TempEntAlloc( vecOrigin, pModel ); if ( !pTemp ) return NULL;
pTemp->SetAbsAngles( vecAngles ); pTemp->m_nBody = 0; pTemp->flags |= iFlags; pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-255,255); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-255,255); pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat(-255,255); pTemp->SetRenderMode( kRenderNormal ); pTemp->tempent_renderamt = 255; pTemp->SetVelocity( vecVelocity ); pTemp->die = gpGlobals->curtime + flLifeTime;
return pTemp; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : type -
// entityIndex -
// attachmentIndex -
// firstPerson -
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash( int type, ClientEntityHandle_t hEntity, int attachmentIndex, bool firstPerson ) { switch( type ) { case MUZZLEFLASH_COMBINE: if ( firstPerson ) { MuzzleFlash_Combine_Player( hEntity, attachmentIndex ); } else { MuzzleFlash_Combine_NPC( hEntity, attachmentIndex ); } break;
case MUZZLEFLASH_SMG1: if ( firstPerson ) { MuzzleFlash_SMG1_Player( hEntity, attachmentIndex ); } else { MuzzleFlash_SMG1_NPC( hEntity, attachmentIndex ); } break;
case MUZZLEFLASH_PISTOL: if ( firstPerson ) { MuzzleFlash_Pistol_Player( hEntity, attachmentIndex ); } else { MuzzleFlash_Pistol_NPC( hEntity, attachmentIndex ); } break; case MUZZLEFLASH_SHOTGUN: if ( firstPerson ) { MuzzleFlash_Shotgun_Player( hEntity, attachmentIndex ); } else { MuzzleFlash_Shotgun_NPC( hEntity, attachmentIndex ); } break; case MUZZLEFLASH_357: if ( firstPerson ) { MuzzleFlash_357_Player( hEntity, attachmentIndex ); } break; case MUZZLEFLASH_RPG: if ( firstPerson ) { // MuzzleFlash_RPG_Player( hEntity, attachmentIndex );
} else { MuzzleFlash_RPG_NPC( hEntity, attachmentIndex ); } break; break; default: { //NOTENOTE: This means you specified an invalid muzzleflash type, check your spelling?
Assert( 0 ); } break; } }
//-----------------------------------------------------------------------------
// Purpose: Play muzzle flash
// Input : *pos1 -
// type -
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash( const Vector& pos1, const QAngle& angles, int type, ClientEntityHandle_t hEntity, bool firstPerson ) { #ifdef CSTRIKE_DLL
return;
#else
//NOTENOTE: This function is becoming obsolete as the muzzles are moved over to being local to attachments
switch ( type ) { //
// Shotgun
//
case MUZZLEFLASH_SHOTGUN: if ( firstPerson ) { MuzzleFlash_Shotgun_Player( hEntity, 1 ); } else { MuzzleFlash_Shotgun_NPC( hEntity, 1 ); } break;
// UNDONE: These need their own effects/sprites. For now use the pistol
// SMG1
case MUZZLEFLASH_SMG1: if ( firstPerson ) { MuzzleFlash_SMG1_Player( hEntity, 1 ); } else { MuzzleFlash_SMG1_NPC( hEntity, 1 ); } break;
// SMG2
case MUZZLEFLASH_SMG2: case MUZZLEFLASH_PISTOL: if ( firstPerson ) { MuzzleFlash_Pistol_Player( hEntity, 1 ); } else { MuzzleFlash_Pistol_NPC( hEntity, 1 ); } break;
case MUZZLEFLASH_COMBINE: if ( firstPerson ) { //FIXME: These should go away
MuzzleFlash_Combine_Player( hEntity, 1 ); } else { //FIXME: These should go away
MuzzleFlash_Combine_NPC( hEntity, 1 ); } break; default: // There's no supported muzzle flash for the type specified!
Assert(0); break; }
#endif
}
//-----------------------------------------------------------------------------
// Purpose: Create explosion sprite
// Input : *pTemp -
// scale -
// flags -
//-----------------------------------------------------------------------------
void CTempEnts::Sprite_Explode( C_LocalTempEntity *pTemp, float scale, int flags ) { if ( !pTemp ) return;
if ( flags & TE_EXPLFLAG_NOADDITIVE ) { // solid sprite
pTemp->SetRenderMode( kRenderNormal ); pTemp->SetRenderColorA( 255 ); } else if( flags & TE_EXPLFLAG_DRAWALPHA ) { // alpha sprite
pTemp->SetRenderMode( kRenderTransAlpha ); pTemp->SetRenderColorA( 180 ); } else { // additive sprite
pTemp->SetRenderMode( kRenderTransAdd ); pTemp->SetRenderColorA( 180 ); }
if ( flags & TE_EXPLFLAG_ROTATE ) { pTemp->SetLocalAnglesDim( Z_INDEX, random->RandomInt( 0, 360 ) ); }
pTemp->m_nRenderFX = kRenderFxNone; pTemp->SetVelocity( Vector( 0, 0, 8 ) ); pTemp->SetRenderColor( 255, 255, 255 ); pTemp->SetLocalOriginDim( Z_INDEX, pTemp->GetLocalOriginDim( Z_INDEX ) + 10 ); pTemp->m_flSpriteScale = scale; }
enum { SHELL_NONE = 0, SHELL_SMALL, SHELL_BIG, SHELL_SHOTGUN, };
//-----------------------------------------------------------------------------
// Purpose: Clear existing temp entities
//-----------------------------------------------------------------------------
void CTempEnts::Clear( void ) { FOR_EACH_LL( m_TempEnts, i ) { C_LocalTempEntity *p = m_TempEnts[ i ];
m_TempEntsPool.Free( p ); }
m_TempEnts.RemoveAll(); g_BreakableHelper.Clear(); }
C_LocalTempEntity *CTempEnts::FindTempEntByID( int nID, int nSubID ) { // HACK HACK: We're using skin and hitsounds as a hacky way to store an ID and sub-ID for later identification
FOR_EACH_LL( m_TempEnts, i ) { C_LocalTempEntity *p = m_TempEnts[ i ]; if ( p && p->m_nSkin == nID && p->hitSound == nSubID ) { return p; } }
return NULL; }
//-----------------------------------------------------------------------------
// Purpose: Allocate temp entity ( normal/low priority )
// Input : *org -
// *model -
// Output : C_LocalTempEntity
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::TempEntAlloc( const Vector& org, const model_t *model ) { C_LocalTempEntity *pTemp;
if ( !model ) { DevWarning( 1, "Can't create temporary entity with NULL model!\n" ); return NULL; }
pTemp = TempEntAlloc();
if ( !pTemp ) { DevWarning( 1, "Overflow %d temporary ents!\n", MAX_TEMP_ENTITIES ); return NULL; }
m_TempEnts.AddToTail( pTemp );
pTemp->Prepare( model, gpGlobals->curtime );
pTemp->priority = TENTPRIORITY_LOW; pTemp->SetAbsOrigin( org );
pTemp->m_RenderGroup = RENDER_GROUP_OTHER; pTemp->AddToLeafSystem( pTemp->m_RenderGroup );
if ( CommandLine()->CheckParm( "-tools" ) != NULL ) { #ifdef _DEBUG
static bool first = true; if ( first ) { Msg( "Currently not recording tempents, since recording them as entites causes them to be deleted as entities, even though they were allocated through the tempent pool. (crash)\n" ); first = false; } #endif
// ClientEntityList().AddNonNetworkableEntity( pTemp );
}
return pTemp; }
//-----------------------------------------------------------------------------
// Purpose:
// Output : C_LocalTempEntity
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::TempEntAlloc() { if ( m_TempEnts.Count() >= MAX_TEMP_ENTITIES ) return NULL;
C_LocalTempEntity *pTemp = m_TempEntsPool.AllocZero(); return pTemp; }
void CTempEnts::TempEntFree( int index ) { C_LocalTempEntity *pTemp = m_TempEnts[ index ]; if ( pTemp ) { // Remove from the active list.
m_TempEnts.Remove( index );
// Cleanup its data.
pTemp->RemoveFromLeafSystem();
// Remove the tempent from the ClientEntityList before removing it from the pool.
if ( ( pTemp->flags & FTENT_CLIENTSIDEPARTICLES ) ) { // Stop the particle emission if this hasn't happened already - collision or system timing out on its own.
if ( !pTemp->m_bParticleCollision ) { pTemp->ParticleProp()->StopEmission(); } ClientEntityList().RemoveEntity( pTemp->GetRefEHandle() ); }
pTemp->OnRemoveTempEntity(); m_TempEntsPool.Free( pTemp ); } }
// Free the first low priority tempent it finds.
bool CTempEnts::FreeLowPriorityTempEnt() { int next = 0; for( int i = m_TempEnts.Head(); i != m_TempEnts.InvalidIndex(); i = next ) { next = m_TempEnts.Next( i );
C_LocalTempEntity *pActive = m_TempEnts[ i ];
if ( pActive->priority == TENTPRIORITY_LOW ) { TempEntFree( i ); return true; } }
return false; }
//-----------------------------------------------------------------------------
// Purpose: Allocate a temp entity, if there are no slots, kick out a low priority
// one if possible
// Input : *org -
// *model -
// Output : C_LocalTempEntity
//-----------------------------------------------------------------------------
C_LocalTempEntity *CTempEnts::TempEntAllocHigh( const Vector& org, const model_t *model ) { C_LocalTempEntity *pTemp;
if ( !model ) { DevWarning( 1, "temporary ent model invalid\n" ); return NULL; }
pTemp = TempEntAlloc(); if ( !pTemp ) { // no temporary ents free, so find the first active low-priority temp ent
// and overwrite it.
FreeLowPriorityTempEnt();
pTemp = TempEntAlloc(); }
if ( !pTemp ) { // didn't find anything? The tent list is either full of high-priority tents
// or all tents in the list are still due to live for > 10 seconds.
DevWarning( 1,"Couldn't alloc a high priority TENT (max %i)!\n", MAX_TEMP_ENTITIES ); return NULL; }
m_TempEnts.AddToTail( pTemp );
pTemp->Prepare( model, gpGlobals->curtime );
pTemp->priority = TENTPRIORITY_HIGH; pTemp->SetLocalOrigin( org );
pTemp->m_RenderGroup = RENDER_GROUP_OTHER; pTemp->AddToLeafSystem( pTemp->m_RenderGroup );
if ( CommandLine()->CheckParm( "-tools" ) != NULL ) { ClientEntityList().AddNonNetworkableEntity( pTemp ); }
return pTemp; }
//-----------------------------------------------------------------------------
// Purpose: Play sound when temp ent collides with something
// Input : *pTemp -
// damp -
//-----------------------------------------------------------------------------
void CTempEnts::PlaySound ( C_LocalTempEntity *pTemp, float damp ) { const char *soundname = NULL; float fvol; bool isshellcasing = false; int zvel;
switch ( pTemp->hitSound ) { default: return; // null sound
case BOUNCE_GLASS: { soundname = "Bounce.Glass"; } break;
case BOUNCE_METAL: { soundname = "Bounce.Metal"; } break;
case BOUNCE_FLESH: { soundname = "Bounce.Flesh"; } break;
case BOUNCE_WOOD: { soundname = "Bounce.Wood"; } break;
case BOUNCE_SHRAP: { soundname = "Bounce.Shrapnel"; } break;
case BOUNCE_SHOTSHELL: { soundname = "Bounce.ShotgunShell"; isshellcasing = true; // shell casings have different playback parameters
} break;
case BOUNCE_SHELL: { soundname = "Bounce.Shell"; isshellcasing = true; // shell casings have different playback parameters
} break;
case BOUNCE_CONCRETE: { soundname = "Bounce.Concrete"; } break;
#ifdef CSTRIKE_DLL
case TE_PISTOL_SHELL: { soundname = "Bounce.PistolShell"; } break;
case TE_RIFLE_SHELL: { soundname = "Bounce.RifleShell"; } break;
case TE_SHOTGUN_SHELL: { soundname = "Bounce.ShotgunShell"; } break; #endif
}
zvel = abs( pTemp->GetVelocity()[2] ); // only play one out of every n
if ( isshellcasing ) { // play first bounce, then 1 out of 3
if ( zvel < 200 && random->RandomInt(0,3) ) return; } else { if ( random->RandomInt(0,5) ) return; }
CSoundParameters params; if ( !C_BaseEntity::GetParametersForSound( soundname, params, NULL ) ) return;
fvol = params.volume;
if ( damp > 0.0 ) { int pitch; if ( isshellcasing ) { fvol *= MIN (1.0, ((float)zvel) / 350.0); } else { fvol *= MIN (1.0, ((float)zvel) / 450.0); } if ( !random->RandomInt(0,3) && !isshellcasing ) { pitch = random->RandomInt( params.pitchlow, params.pitchhigh ); } else { pitch = params.pitch; }
CLocalPlayerFilter filter;
EmitSound_t ep; ep.m_nChannel = params.channel; ep.m_pSoundName = params.soundname; ep.m_flVolume = fvol; ep.m_SoundLevel = params.soundlevel; ep.m_nPitch = pitch; ep.m_pOrigin = &pTemp->GetAbsOrigin();
C_BaseEntity::EmitSound( filter, SOUND_FROM_WORLD, ep ); } } //-----------------------------------------------------------------------------
// Purpose: Add temp entity to visible entities list of it's in PVS
// Input : *pEntity -
// Output : int
//-----------------------------------------------------------------------------
int CTempEnts::AddVisibleTempEntity( C_LocalTempEntity *pEntity ) { int i; Vector mins, maxs; Vector model_mins, model_maxs;
if ( !pEntity->GetModel() ) return 0;
modelinfo->GetModelBounds( pEntity->GetModel(), model_mins, model_maxs );
for (i=0 ; i<3 ; i++) { mins[i] = pEntity->GetAbsOrigin()[i] + model_mins[i]; maxs[i] = pEntity->GetAbsOrigin()[i] + model_maxs[i]; }
// FIXME: Vis isn't setup by the time we get here, so this call fails if
// you try to add a tempent before the first frame is drawn, and it's
// one frame behind the rest of the time. Fix this.
// does the box intersect a visible leaf?
//if ( engine->IsBoxInViewCluster( mins, maxs ) )
{ // Temporary entities have no corresponding element in cl_entitylist
pEntity->index = -1; // Add to list
if( pEntity->m_RenderGroup == RENDER_GROUP_OTHER ) { pEntity->AddToLeafSystem(); } else { pEntity->AddToLeafSystem( pEntity->m_RenderGroup ); }
return 1; } return 0; }
//-----------------------------------------------------------------------------
// Purpose: Runs Temp Ent simulation routines
//-----------------------------------------------------------------------------
void CTempEnts::Update(void) { VPROF_("CTempEnts::Update", 1, VPROF_BUDGETGROUP_CLIENT_SIM, false, BUDGETFLAG_CLIENT); static int gTempEntFrame = 0; float frametime;
// Don't simulate while loading
if ( ( m_TempEnts.Count() == 0 ) || !engine->IsInGame() ) { return; }
// !!!BUGBUG -- This needs to be time based
gTempEntFrame = (gTempEntFrame+1) & 31;
frametime = gpGlobals->frametime;
// in order to have tents collide with players, we have to run the player prediction code so
// that the client has the player list. We run this code once when we detect any COLLIDEALL
// tent, then set this BOOL to true so the code doesn't get run again if there's more than
// one COLLIDEALL ent for this update. (often are).
// !!! Don't simulate while paused.... This is sort of a hack, revisit.
if ( frametime == 0 ) { FOR_EACH_LL( m_TempEnts, i ) { C_LocalTempEntity *current = m_TempEnts[ i ];
AddVisibleTempEntity( current ); } } else { int next = 0; for( int i = m_TempEnts.Head(); i != m_TempEnts.InvalidIndex(); i = next ) { next = m_TempEnts.Next( i );
C_LocalTempEntity *current = m_TempEnts[ i ];
// Kill it
if ( !current->IsActive() || !current->Frame( frametime, gTempEntFrame ) ) { TempEntFree( i ); } else { // Cull to PVS (not frustum cull, just PVS)
if ( !AddVisibleTempEntity( current ) ) { if ( !( current->flags & FTENT_PERSIST ) ) { // If we can't draw it this frame, just dump it.
current->die = gpGlobals->curtime; // Don't fade out, just die
current->flags &= ~FTENT_FADEOUT;
TempEntFree( i ); } } } } } }
// Recache tempents which might have been flushed
void CTempEnts::LevelInit() { #ifndef TF_CLIENT_DLL
m_pSpriteMuzzleFlash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1.vmt" ); m_pSpriteMuzzleFlash[1] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" ); m_pSpriteMuzzleFlash[2] = (model_t *)engine->LoadModel( "sprites/muzzleflash4.vmt" );
m_pSpriteAR2Flash[0] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle1b.vmt" ); m_pSpriteAR2Flash[1] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle2b.vmt" ); m_pSpriteAR2Flash[2] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle3b.vmt" ); m_pSpriteAR2Flash[3] = (model_t *)engine->LoadModel( "sprites/ar2_muzzle4b.vmt" );
m_pSpriteCombineFlash[0] = (model_t *)engine->LoadModel( "effects/combinemuzzle1.vmt" ); m_pSpriteCombineFlash[1] = (model_t *)engine->LoadModel( "effects/combinemuzzle2.vmt" );
m_pShells[0] = (model_t *) engine->LoadModel( "models/weapons/shell.mdl" ); m_pShells[1] = (model_t *) engine->LoadModel( "models/weapons/rifleshell.mdl" ); m_pShells[2] = (model_t *) engine->LoadModel( "models/weapons/shotgun_shell.mdl" ); #endif
#if defined( HL1_CLIENT_DLL )
m_pHL1Shell = (model_t *)engine->LoadModel( "models/shell.mdl" ); m_pHL1ShotgunShell = (model_t *)engine->LoadModel( "models/shotgunshell.mdl" ); #endif
#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL )
m_pCS_9MMShell = (model_t *)engine->LoadModel( "models/Shells/shell_9mm.mdl" ); m_pCS_57Shell = (model_t *)engine->LoadModel( "models/Shells/shell_57.mdl" ); m_pCS_12GaugeShell = (model_t *)engine->LoadModel( "models/Shells/shell_12gauge.mdl" ); m_pCS_556Shell = (model_t *)engine->LoadModel( "models/Shells/shell_556.mdl" ); m_pCS_762NATOShell = (model_t *)engine->LoadModel( "models/Shells/shell_762nato.mdl" ); m_pCS_338MAGShell = (model_t *)engine->LoadModel( "models/Shells/shell_338mag.mdl" ); #endif
}
//-----------------------------------------------------------------------------
// Purpose: Initialize TE system
//-----------------------------------------------------------------------------
void CTempEnts::Init (void) { m_pSpriteMuzzleFlash[0] = NULL; m_pSpriteMuzzleFlash[1] = NULL; m_pSpriteMuzzleFlash[2] = NULL;
m_pSpriteAR2Flash[0] = NULL; m_pSpriteAR2Flash[1] = NULL; m_pSpriteAR2Flash[2] = NULL; m_pSpriteAR2Flash[3] = NULL;
m_pSpriteCombineFlash[0] = NULL; m_pSpriteCombineFlash[1] = NULL;
m_pShells[0] = NULL; m_pShells[1] = NULL; m_pShells[2] = NULL;
#if defined( HL1_CLIENT_DLL )
m_pHL1Shell = NULL; m_pHL1ShotgunShell = NULL; #endif
#if defined( CSTRIKE_DLL ) || defined ( SDK_DLL )
m_pCS_9MMShell = NULL; m_pCS_57Shell = NULL; m_pCS_12GaugeShell = NULL; m_pCS_556Shell = NULL; m_pCS_762NATOShell = NULL; m_pCS_338MAGShell = NULL; #endif
// Clear out lists to start
Clear(); }
void CTempEnts::LevelShutdown() { // Free all active tempents.
Clear(); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTempEnts::Shutdown() { LevelShutdown(); }
//-----------------------------------------------------------------------------
// Purpose: Cache off all material references
// Input : *pEmitter - Emitter used for material lookup
//-----------------------------------------------------------------------------
inline void CTempEnts::CacheMuzzleFlashes( void ) { int i; for ( i = 0; i < 4; i++ ) { if ( m_Material_MuzzleFlash_Player[i] == NULL ) { m_Material_MuzzleFlash_Player[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/muzzleflash%d_noz", i+1 ) ); } }
for ( i = 0; i < 4; i++ ) { if ( m_Material_MuzzleFlash_NPC[i] == NULL ) { m_Material_MuzzleFlash_NPC[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/muzzleflash%d", i+1 ) ); } }
for ( i = 0; i < 2; i++ ) { if ( m_Material_Combine_MuzzleFlash_Player[i] == NULL ) { m_Material_Combine_MuzzleFlash_Player[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/combinemuzzle%d_noz", i+1 ) ); } }
for ( i = 0; i < 2; i++ ) { if ( m_Material_Combine_MuzzleFlash_NPC[i] == NULL ) { m_Material_Combine_MuzzleFlash_NPC[i] = ParticleMgr()->GetPMaterial( VarArgs( "effects/combinemuzzle%d", i+1 ) ); } } }
//-----------------------------------------------------------------------------
// Purpose:
// Input : entityIndex -
// attachmentIndex -
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash_Combine_Player( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_Combine_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash", hEntity, attachmentIndex, FLE_VIEWMODEL );
CacheMuzzleFlashes();
SimpleParticle *pParticle; Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
float flScale = random->RandomFloat( 2.0f, 2.25f );
pSimple->SetDrawBeforeViewModel( true );
// Flash
for ( int i = 1; i < 6; i++ ) { offset = (forward * (i*8.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Combine_MuzzleFlash_Player[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.025f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 255;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (12-(i))/12) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; }
// Tack on the smoke
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_Combine_MuzzleFlash_Player[random->RandomInt(0,1)], vec3_origin ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.025f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); pParticle->m_uchEndAlpha = 32;
pParticle->m_uchStartSize = random->RandomFloat( 10.0f, 16.0f ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; }
//-----------------------------------------------------------------------------
// Purpose:
// Input : &origin -
// &angles -
// entityIndex -
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash_Combine_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_Combine_NPC", VPROF_BUDGETGROUP_PARTICLE_RENDERING );
// If the material isn't available, let's not do anything.
if ( g_Mat_Combine_Muzzleflash[0] == NULL ) { return; }
CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Combine_NPC", hEntity, attachmentIndex );
SimpleParticle *pParticle; Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
float flScale = random->RandomFloat( 1.0f, 1.5f );
float burstSpeed = random->RandomFloat( 50.0f, 150.0f );
#define FRONT_LENGTH 6
// Front flash
for ( int i = 1; i < FRONT_LENGTH; i++ ) { offset = (forward * (i*2.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.1f;
pParticle->m_vecVelocity = forward * burstSpeed;
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255.0f; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (FRONT_LENGTH*1.25f-(i))/(FRONT_LENGTH)) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } Vector right(0,1,0), up(0,0,1); Vector dir = right - up;
#define SIDE_LENGTH 6
burstSpeed = random->RandomFloat( 50.0f, 150.0f );
// Diagonal flash
for ( int i = 1; i < SIDE_LENGTH; i++ ) { offset = (dir * (i*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.2f;
pParticle->m_vecVelocity = dir * burstSpeed * 0.25f;
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; }
dir = right + up; burstSpeed = random->RandomFloat( 50.0f, 150.0f );
// Diagonal flash
for ( int i = 1; i < SIDE_LENGTH; i++ ) { offset = (-dir * (i*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.2f;
pParticle->m_vecVelocity = dir * -burstSpeed * 0.25f;
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; }
dir = up; burstSpeed = random->RandomFloat( 50.0f, 150.0f );
// Top flash
for ( int i = 1; i < SIDE_LENGTH; i++ ) { offset = (dir * (i*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[random->RandomInt(0,1)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.2f;
pParticle->m_vecVelocity = dir * burstSpeed * 0.25f;
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = ( (random->RandomFloat( 2.0f, 4.0f ) * (SIDE_LENGTH-(i))/(SIDE_LENGTH*0.5f)) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; }
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_Combine_Muzzleflash[2], vec3_origin ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.3f, 0.4f );
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 255;
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = flScale * random->RandomFloat( 12.0f, 16.0f ); pParticle->m_uchEndSize = 0.0f; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f;
matrix3x4_t matAttachment; Vector origin; // Grab the origin out of the transform for the attachment
if ( FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) { origin.x = matAttachment[0][3]; origin.y = matAttachment[1][3]; origin.z = matAttachment[2][3]; } else { //NOTENOTE: If you're here, you've specified an entity or an attachment that is invalid
Assert(0); return; }
if ( muzzleflash_light.GetBool() ) { C_BaseEntity *pEnt = ClientEntityList().GetBaseEntityFromHandle( hEntity ); if ( pEnt ) { dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + pEnt->entindex() );
el->origin = origin;
el->color.r = 64; el->color.g = 128; el->color.b = 255; el->color.exponent = 5;
el->radius = random->RandomInt( 32, 128 ); el->decay = el->radius / 0.05f; el->die = gpGlobals->curtime + 0.05f; } } }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_AR2_NPC( const Vector &origin, const QAngle &angles, ClientEntityHandle_t hEntity ) { //Draw the cloud of fire
FX_MuzzleEffect( origin, angles, 1.0f, hEntity ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash_SMG1_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { //Draw the cloud of fire
FX_MuzzleEffectAttached( 1.0f, hEntity, attachmentIndex, NULL, true ); }
//-----------------------------------------------------------------------------
// Purpose:
//-----------------------------------------------------------------------------
void CTempEnts::MuzzleFlash_SMG1_Player( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_SMG1_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_SMG1_Player", hEntity, attachmentIndex, FLE_VIEWMODEL );
CacheMuzzleFlashes();
SimpleParticle *pParticle; Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space
float flScale = random->RandomFloat( 1.25f, 1.5f );
pSimple->SetDrawBeforeViewModel( true );
// Flash
for ( int i = 1; i < 6; i++ ) { offset = (forward * (i*8.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.025f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 255;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_Shotgun_Player( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_Shotgun_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_Shotgun_Player" );
pSimple->SetDrawBeforeViewModel( true );
CacheMuzzleFlashes();
Vector origin; QAngle angles;
// Get our attachment's transformation matrix
FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
Vector forward; AngleVectors( angles, &forward, NULL, NULL );
SimpleParticle *pParticle; Vector offset;
float flScale = random->RandomFloat( 1.25f, 1.5f );
// Flash
for ( int i = 1; i < 6; i++ ) { offset = origin + (forward * (i*8.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.0001f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 255;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_Shotgun_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { //Draw the cloud of fire
FX_MuzzleEffectAttached( 0.75f, hEntity, attachmentIndex );
// If the material isn't available, let's not do anything else.
if ( g_Mat_SMG_Muzzleflash[0] == NULL ) { return; }
QAngle angles;
Vector forward;
// Setup the origin.
Vector origin; IClientRenderable *pRenderable = ClientEntityList().GetClientRenderableFromHandle( hEntity ); if ( !pRenderable ) return;
pRenderable->GetAttachment( attachmentIndex, origin, angles ); AngleVectors( angles, &forward );
//Embers less often
if ( random->RandomInt( 0, 2 ) == 0 ) { //Embers
CSmartPtr<CEmberEffect> pEmbers = CEmberEffect::Create( "muzzle_embers" ); pEmbers->SetSortOrigin( origin );
SimpleParticle *pParticle;
int numEmbers = random->RandomInt( 0, 4 );
for ( int i = 0; i < numEmbers; i++ ) { pParticle = (SimpleParticle *) pEmbers->AddParticle( sizeof( SimpleParticle ), g_Mat_SMG_Muzzleflash[0], origin ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.2f, 0.4f );
pParticle->m_vecVelocity.Random( -0.05f, 0.05f ); pParticle->m_vecVelocity += forward; VectorNormalize( pParticle->m_vecVelocity );
pParticle->m_vecVelocity *= random->RandomFloat( 64.0f, 256.0f );
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 128; pParticle->m_uchColor[2] = 64;
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = 1; pParticle->m_uchEndSize = 0;
pParticle->m_flRoll = 0; pParticle->m_flRollDelta = 0; } }
//
// Trails
//
CSmartPtr<CTrailParticles> pTrails = CTrailParticles::Create( "MuzzleFlash_Shotgun_NPC" ); pTrails->SetSortOrigin( origin );
TrailParticle *pTrailParticle;
pTrails->SetFlag( bitsPARTICLE_TRAIL_FADE ); pTrails->m_ParticleCollision.SetGravity( 0.0f );
int numEmbers = random->RandomInt( 4, 8 );
for ( int i = 0; i < numEmbers; i++ ) { pTrailParticle = (TrailParticle *) pTrails->AddParticle( sizeof( TrailParticle ), g_Mat_SMG_Muzzleflash[0], origin ); if ( pTrailParticle == NULL ) return;
pTrailParticle->m_flLifetime = 0.0f; pTrailParticle->m_flDieTime = random->RandomFloat( 0.1f, 0.2f );
float spread = 0.05f;
pTrailParticle->m_vecVelocity.Random( -spread, spread ); pTrailParticle->m_vecVelocity += forward; VectorNormalize( pTrailParticle->m_vecVelocity ); VectorNormalize( forward );
float dot = forward.Dot( pTrailParticle->m_vecVelocity );
dot = (1.0f-fabs(dot)) / spread; pTrailParticle->m_vecVelocity *= (random->RandomFloat( 256.0f, 1024.0f ) * (1.0f-dot));
Color32Init( pTrailParticle->m_color, 255, 242, 191, 255 );
pTrailParticle->m_flLength = 0.05f; pTrailParticle->m_flWidth = random->RandomFloat( 0.25f, 0.5f ); } }
//==================================================
// Purpose:
//==================================================
void CTempEnts::MuzzleFlash_357_Player( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_357_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_357_Player" );
pSimple->SetDrawBeforeViewModel( true );
CacheMuzzleFlashes();
Vector origin; QAngle angles;
// Get our attachment's transformation matrix
FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
Vector forward; AngleVectors( angles, &forward, NULL, NULL );
SimpleParticle *pParticle; Vector offset;
// Smoke
offset = origin + forward * 8.0f;
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.5f, 1.0f );
pParticle->m_vecVelocity.Init(); pParticle->m_vecVelocity = forward * random->RandomFloat( 8.0f, 64.0f ); pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
int color = random->RandomInt( 200, 255 ); pParticle->m_uchColor[0] = color; pParticle->m_uchColor[1] = color; pParticle->m_uchColor[2] = color;
pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = random->RandomInt( 2, 4 ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 8.0f; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = random->RandomFloat( -0.5f, 0.5f );
float flScale = random->RandomFloat( 1.25f, 1.5f );
// Flash
for ( int i = 1; i < 6; i++ ) { offset = origin + (forward * (i*8.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.01f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 255;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_Pistol_Player( ClientEntityHandle_t hEntity, int attachmentIndex ) { VPROF_BUDGET( "MuzzleFlash_Pistol_Player", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); CSmartPtr<CSimpleEmitter> pSimple = CSimpleEmitter::Create( "MuzzleFlash_Pistol_Player" ); pSimple->SetDrawBeforeViewModel( true );
CacheMuzzleFlashes();
Vector origin; QAngle angles;
// Get our attachment's transformation matrix
FX_GetAttachmentTransform( hEntity, attachmentIndex, &origin, &angles );
pSimple->GetBinding().SetBBox( origin - Vector( 4, 4, 4 ), origin + Vector( 4, 4, 4 ) );
Vector forward; AngleVectors( angles, &forward, NULL, NULL );
SimpleParticle *pParticle; Vector offset;
// Smoke
offset = origin + forward * 8.0f;
if ( random->RandomInt( 0, 3 ) != 0 ) { pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), g_Mat_DustPuff[0], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = random->RandomFloat( 0.25f, 0.5f );
pParticle->m_vecVelocity.Init(); pParticle->m_vecVelocity = forward * random->RandomFloat( 48.0f, 64.0f ); pParticle->m_vecVelocity[2] += random->RandomFloat( 4.0f, 16.0f );
int color = random->RandomInt( 200, 255 ); pParticle->m_uchColor[0] = color; pParticle->m_uchColor[1] = color; pParticle->m_uchColor[2] = color;
pParticle->m_uchStartAlpha = random->RandomInt( 64, 128 ); pParticle->m_uchEndAlpha = 0;
pParticle->m_uchStartSize = random->RandomInt( 2, 4 ); pParticle->m_uchEndSize = pParticle->m_uchStartSize * 4.0f; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = random->RandomFloat( -0.1f, 0.1f ); }
float flScale = random->RandomFloat( 1.0f, 1.25f );
// Flash
for ( int i = 1; i < 6; i++ ) { offset = origin + (forward * (i*4.0f*flScale));
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), m_Material_MuzzleFlash_Player[random->RandomInt(0,3)], offset ); if ( pParticle == NULL ) return;
pParticle->m_flLifetime = 0.0f; pParticle->m_flDieTime = 0.01f;
pParticle->m_vecVelocity.Init();
pParticle->m_uchColor[0] = 255; pParticle->m_uchColor[1] = 255; pParticle->m_uchColor[2] = 200+random->RandomInt(0,55);
pParticle->m_uchStartAlpha = 255; pParticle->m_uchEndAlpha = 255;
pParticle->m_uchStartSize = ( (random->RandomFloat( 6.0f, 8.0f ) * (8-(i))/6) * flScale ); pParticle->m_uchEndSize = pParticle->m_uchStartSize; pParticle->m_flRoll = random->RandomInt( 0, 360 ); pParticle->m_flRollDelta = 0.0f; } }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_Pistol_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { FX_MuzzleEffectAttached( 0.5f, hEntity, attachmentIndex, NULL, true ); }
//==================================================
// Purpose:
// Input:
//==================================================
void CTempEnts::MuzzleFlash_RPG_NPC( ClientEntityHandle_t hEntity, int attachmentIndex ) { //Draw the cloud of fire
FX_MuzzleEffectAttached( 1.5f, hEntity, attachmentIndex );
}
void CTempEnts::RocketFlare( const Vector& pos ) { C_LocalTempEntity *pTemp; const model_t *model; int nframeCount;
model = (model_t *)engine->LoadModel( "sprites/animglow01.vmt" ); if ( !model ) { return; }
nframeCount = modelinfo->GetModelFrameCount( model );
pTemp = TempEntAlloc( pos, model ); if ( !pTemp ) return;
pTemp->m_flFrameMax = nframeCount - 1; pTemp->SetRenderMode( kRenderGlow ); pTemp->m_nRenderFX = kRenderFxNoDissipation; pTemp->tempent_renderamt = 255; pTemp->m_flFrameRate = 1.0; pTemp->m_flFrame = random->RandomInt( 0, nframeCount - 1); pTemp->m_flSpriteScale = 1.0; pTemp->SetAbsOrigin( pos ); pTemp->die = gpGlobals->curtime + 0.01; }
void CTempEnts::HL1EjectBrass( const Vector &vecPosition, const QAngle &angAngles, const Vector &vecVelocity, int nType ) { const model_t *pModel = NULL;
#if defined( HL1_CLIENT_DLL )
switch ( nType ) { case 0: default: pModel = m_pHL1Shell; break; case 1: pModel = m_pHL1ShotgunShell; break; } #endif
if ( pModel == NULL ) return;
C_LocalTempEntity *pTemp = TempEntAlloc( vecPosition, pModel );
if ( pTemp == NULL ) return;
switch ( nType ) { case 0: default: pTemp->hitSound = BOUNCE_SHELL; break; case 1: pTemp->hitSound = BOUNCE_SHOTSHELL; break; }
pTemp->m_nBody = 0; pTemp->flags |= ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY | FTENT_ROTATE );
pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat( -512,511 ); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat( -256,255 ); pTemp->m_vecTempEntAngVelocity[2] = random->RandomFloat( -256,255 );
//Face forward
pTemp->SetAbsAngles( angAngles );
pTemp->SetRenderMode( kRenderNormal ); pTemp->tempent_renderamt = 255; // Set this for fadeout
pTemp->SetVelocity( vecVelocity );
pTemp->die = gpGlobals->curtime + 2.5; }
#define SHELLTYPE_PISTOL 0
#define SHELLTYPE_RIFLE 1
#define SHELLTYPE_SHOTGUN 2
void CTempEnts::CSEjectBrass( const Vector &vecPosition, const QAngle &angVelocity, int nVelocity, int shellType, CBasePlayer *pShooter ) { const model_t *pModel = NULL; int hitsound = TE_BOUNCE_SHELL;
#if defined ( CSTRIKE_DLL ) || defined ( SDK_DLL )
switch( shellType ) { default: case CS_SHELL_9MM: hitsound = TE_PISTOL_SHELL; pModel = m_pCS_9MMShell; break; case CS_SHELL_57: hitsound = TE_PISTOL_SHELL; pModel = m_pCS_57Shell; break; case CS_SHELL_12GAUGE: hitsound = TE_SHOTGUN_SHELL; pModel = m_pCS_12GaugeShell; break; case CS_SHELL_556: hitsound = TE_RIFLE_SHELL; pModel = m_pCS_556Shell; break; case CS_SHELL_762NATO: hitsound = TE_RIFLE_SHELL; pModel = m_pCS_762NATOShell; break; case CS_SHELL_338MAG: hitsound = TE_RIFLE_SHELL; pModel = m_pCS_338MAGShell; break; } #endif
if ( pModel == NULL ) return;
Vector forward, right, up; Vector velocity; Vector origin; QAngle angle; // Add some randomness to the velocity
AngleVectors( angVelocity, &forward, &right, &up ); velocity = forward * nVelocity * random->RandomFloat( 1.2, 2.8 ) + up * random->RandomFloat( -10, 10 ) + right * random->RandomFloat( -20, 20 );
if( pShooter ) velocity += pShooter->GetAbsVelocity();
C_LocalTempEntity *pTemp = TempEntAlloc( vecPosition, pModel ); if ( !pTemp ) return;
if( pShooter ) pTemp->SetAbsAngles( pShooter->EyeAngles() ); else pTemp->SetAbsAngles( vec3_angle );
pTemp->SetVelocity( velocity );
pTemp->hitSound = hitsound;
pTemp->SetGravity( 0.4 );
pTemp->m_nBody = 0; pTemp->flags = FTENT_FADEOUT | FTENT_GRAVITY | FTENT_COLLIDEALL | FTENT_HITSOUND | FTENT_ROTATE | FTENT_CHANGERENDERONCOLLIDE;
pTemp->m_vecTempEntAngVelocity[0] = random->RandomFloat(-256,256); pTemp->m_vecTempEntAngVelocity[1] = random->RandomFloat(-256,256); pTemp->m_vecTempEntAngVelocity[2] = 0; pTemp->SetRenderMode( kRenderNormal ); pTemp->tempent_renderamt = 255; pTemp->die = gpGlobals->curtime + 10;
bool bViewModelBrass = false;
if ( pShooter && pShooter->GetObserverMode() == OBS_MODE_IN_EYE ) { // we are spectating the shooter in first person view
pShooter = ToBasePlayer( pShooter->GetObserverTarget() ); bViewModelBrass = true; }
if ( pShooter ) { pTemp->clientIndex = pShooter->entindex(); bViewModelBrass |= pShooter->IsLocalPlayer(); } else { pTemp->clientIndex = 0; }
if ( bViewModelBrass ) { // for viewmodel brass put it in the viewmodel renderer group
pTemp->m_RenderGroup = RENDER_GROUP_VIEW_MODEL_OPAQUE; }
}
|