diff options
Diffstat (limited to 'mp/src/game/client/c_te_legacytempents.cpp')
| -rw-r--r-- | mp/src/game/client/c_te_legacytempents.cpp | 3439 |
1 files changed, 3439 insertions, 0 deletions
diff --git a/mp/src/game/client/c_te_legacytempents.cpp b/mp/src/game/client/c_te_legacytempents.cpp new file mode 100644 index 00000000..e15f009c --- /dev/null +++ b/mp/src/game/client/c_te_legacytempents.cpp @@ -0,0 +1,3439 @@ +//========= 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 flags )
+{
+ 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, flags );
+ }
+ else
+ {
+ drawn = modelrender->DrawModel(
+ flags,
+ this,
+ MODEL_INSTANCE_INVALID,
+ index,
+ GetModel(),
+ GetAbsOrigin(),
+ GetAbsAngles(),
+ m_nSkin,
+ m_nBody,
+ m_nHitboxSet );
+ }
+ return drawn;
+}
+
+//-----------------------------------------------------------------------------
+// Purpose:
+// Input : flags -
+//-----------------------------------------------------------------------------
+int C_LocalTempEntity::DrawModel( int flags )
+{
+ 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( flags );
+ 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 flags, int effects )
+{
+ 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( effects );
+
+ 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 ( flags & 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 = { r, g, b, 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;
+ int i;
+
+ // 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 ( 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;
+ }
+
+
+}
+
|