You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1048 lines
31 KiB
1048 lines
31 KiB
//========= Copyright Valve Corporation, All rights reserved. ============// |
|
// |
|
// Purpose: |
|
// |
|
// $NoKeywords: $ |
|
//=============================================================================// |
|
#include "cbase.h" |
|
#include "c_ai_basenpc.h" |
|
#include "c_te_particlesystem.h" |
|
#include "fx.h" |
|
#include "fx_sparks.h" |
|
#include "c_tracer.h" |
|
#include "clientsideeffects.h" |
|
#include "iefx.h" |
|
#include "dlight.h" |
|
#include "bone_setup.h" |
|
#include "c_rope.h" |
|
#include "fx_line.h" |
|
#include "c_sprite.h" |
|
#include "view.h" |
|
#include "view_scene.h" |
|
#include "materialsystem/imaterialvar.h" |
|
#include "simple_keys.h" |
|
#include "fx_envelope.h" |
|
#include "iclientvehicle.h" |
|
#include "engine/ivdebugoverlay.h" |
|
#include "particles_localspace.h" |
|
#include "dlight.h" |
|
#include "iefx.h" |
|
#include "c_te_effect_dispatch.h" |
|
#include "tier0/vprof.h" |
|
#include "clienteffectprecachesystem.h" |
|
#include <bitbuf.h> |
|
#include "fx_water.h" |
|
|
|
// memdbgon must be the last include file in a .cpp file!!! |
|
#include "tier0/memdbgon.h" |
|
|
|
#define STRIDER_MSG_BIG_SHOT 1 |
|
#define STRIDER_MSG_STREAKS 2 |
|
#define STRIDER_MSG_DEAD 3 |
|
|
|
#define STOMP_IK_SLOT 11 |
|
const int NUM_STRIDER_IK_TARGETS = 6; |
|
|
|
const float STRIDERFX_BIG_SHOT_TIME = 1.25f; |
|
const float STRIDERFX_END_ALL_TIME = 4.0f; |
|
|
|
class C_StriderFX : public C_EnvelopeFX |
|
{ |
|
public: |
|
typedef C_EnvelopeFX BaseClass; |
|
|
|
C_StriderFX(); |
|
~C_StriderFX() |
|
{ |
|
EffectShutdown(); |
|
} |
|
|
|
|
|
void Update( C_BaseEntity *pOwner, const Vector &targetPos ); |
|
|
|
// Returns the bounds relative to the origin (render bounds) |
|
virtual void GetRenderBounds( Vector& mins, Vector& maxs ) |
|
{ |
|
ClearBounds( mins, maxs ); |
|
AddPointToBounds( m_worldPosition, mins, maxs ); |
|
AddPointToBounds( m_targetPosition, mins, maxs ); |
|
mins -= GetRenderOrigin(); |
|
maxs -= GetRenderOrigin(); |
|
} |
|
|
|
virtual void EffectInit( int entityIndex, int attachment ) |
|
{ |
|
m_limitHitTime = 0; |
|
BaseClass::EffectInit( entityIndex, attachment ); |
|
} |
|
virtual void EffectShutdown( void ) |
|
{ |
|
m_limitHitTime = 0; |
|
BaseClass::EffectShutdown(); |
|
} |
|
|
|
virtual int DrawModel( int flags ); |
|
virtual void LimitTime( float tmax ) |
|
{ |
|
float dt = tmax - m_t; |
|
if ( dt < 0 ) |
|
{ |
|
dt = 0; |
|
} |
|
m_limitHitTime = gpGlobals->curtime + dt; |
|
BaseClass::LimitTime( tmax ); |
|
} |
|
|
|
C_BaseEntity *m_pOwner; |
|
Vector m_targetPosition; |
|
Vector m_beamEndPosition; |
|
pixelvis_handle_t m_queryHandleGun; |
|
pixelvis_handle_t m_queryHandleBeamEnd; |
|
float m_limitHitTime; |
|
}; |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
//----------------------------------------------------------------------------- |
|
class C_Strider : public C_AI_BaseNPC |
|
{ |
|
DECLARE_CLASS( C_Strider, C_AI_BaseNPC ); |
|
public: |
|
DECLARE_CLIENTCLASS(); |
|
DECLARE_INTERPOLATION(); |
|
|
|
|
|
C_Strider(); |
|
virtual ~C_Strider(); |
|
|
|
// model specific |
|
virtual void ReceiveMessage( int classID, bf_read &msg ); |
|
virtual void CalculateIKLocks( float currentTime ) |
|
{ |
|
// NOTE: All strider IK is solved on the server, enable this to do it client-side |
|
//BaseClass::CalculateIKLocks( currentTime ); |
|
if ( m_pIk && m_pIk->m_target.Count() ) |
|
{ |
|
Assert(m_pIk->m_target.Count() > STOMP_IK_SLOT); |
|
// HACKHACK: Hardcoded 11??? Not a cleaner way to do this |
|
CIKTarget &target = m_pIk->m_target[STOMP_IK_SLOT]; |
|
target.SetPos( m_vecHitPos ); |
|
// target.latched.pos = m_vecHitPos; |
|
|
|
for ( int i = 0; i < NUM_STRIDER_IK_TARGETS; i++ ) |
|
{ |
|
CIKTarget &target = m_pIk->m_target[i]; |
|
target.SetPos( m_vecIKTarget[i] ); |
|
#if 0 |
|
debugoverlay->AddBoxOverlay( m_vecIKTarget[i], Vector( -2, -2, -2 ), Vector( 2, 2, 2), QAngle( 0, 0, 0 ), (int)255*m_pIk->m_target[i].est.latched, 0, 0, 0, 0 ); |
|
#endif |
|
} |
|
} |
|
} |
|
|
|
virtual void OnDataChanged( DataUpdateType_t updateType ); |
|
virtual void GetRenderBounds( Vector& theMins, Vector& theMaxs ); |
|
virtual void ClientThink(); |
|
|
|
private: |
|
C_Strider( const C_Strider & ); |
|
C_StriderFX m_cannonFX; |
|
Vector m_vecHitPos; |
|
Vector m_vecIKTarget[NUM_STRIDER_IK_TARGETS]; |
|
CInterpolatedVar< Vector > m_iv_vecHitPos; |
|
CInterpolatedVarArray< Vector, NUM_STRIDER_IK_TARGETS > m_iv_vecIKTarget; |
|
Vector m_vecRenderMins; |
|
Vector m_vecRenderMaxs; |
|
|
|
float m_flNextRopeCutTime; |
|
}; |
|
|
|
IMPLEMENT_CLIENTCLASS_DT(C_Strider, DT_NPC_Strider, CNPC_Strider) |
|
RecvPropVector(RECVINFO(m_vecHitPos)), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[0])), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[1])), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[2])), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[3])), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[4])), |
|
RecvPropVector(RECVINFO(m_vecIKTarget[5])), |
|
END_RECV_TABLE() |
|
|
|
C_StriderFX::C_StriderFX() |
|
{ |
|
m_pOwner = NULL; |
|
m_active = false; |
|
} |
|
|
|
void C_StriderFX::Update( C_BaseEntity *pOwner, const Vector &targetPos ) |
|
{ |
|
BaseClass::Update(); |
|
|
|
m_pOwner = pOwner; |
|
|
|
if ( m_active ) |
|
{ |
|
m_targetPosition = targetPos; |
|
} |
|
} |
|
|
|
// --on gun |
|
// warpy sprite bit |
|
// darkening sprite |
|
// glowy blue flare sprite |
|
// bubble warpy sprite |
|
// after glow sprite |
|
|
|
// --on line of sight |
|
// narrow beam |
|
// wide beam |
|
|
|
// --on impact point |
|
// sparkly white bits |
|
// sparkly white streaks |
|
// pale blue particle steam |
|
|
|
enum |
|
{ |
|
STRIDERFX_WARP_SCALE = 0, |
|
STRIDERFX_DARKNESS, |
|
STRIDERFX_FLARE_COLOR, |
|
STRIDERFX_FLARE_SIZE, |
|
STRIDERFX_BUBBLE_SIZE, |
|
STRIDERFX_BUBBLE_REFRACT, |
|
|
|
STRIDERFX_NARROW_BEAM_COLOR, |
|
STRIDERFX_NARROW_BEAM_SIZE, |
|
|
|
STRIDERFX_WIDE_BEAM_COLOR, |
|
STRIDERFX_WIDE_BEAM_SIZE, |
|
|
|
STRIDERFX_AFTERGLOW_COLOR, |
|
|
|
STRIDERFX_WIDE_BEAM_LENGTH, |
|
|
|
STRIDERFX_SPARK_COUNT, |
|
STRIDERFX_STREAK_COUNT, |
|
STRIDERFX_STEAM_COUNT, |
|
|
|
|
|
// must be last |
|
STRIDERFX_PARAMETERS, |
|
}; |
|
|
|
class CStriderFXEnvelope |
|
{ |
|
public: |
|
CStriderFXEnvelope(); |
|
|
|
void AddKey( int parameterIndex, const CSimpleKeyInterp &key ) |
|
{ |
|
Assert( parameterIndex >= 0 && parameterIndex < STRIDERFX_PARAMETERS ); |
|
|
|
if ( parameterIndex >= 0 && parameterIndex < STRIDERFX_PARAMETERS ) |
|
{ |
|
m_parameters[parameterIndex].Insert( key ); |
|
} |
|
|
|
} |
|
|
|
CSimpleKeyList m_parameters[STRIDERFX_PARAMETERS]; |
|
}; |
|
|
|
// NOTE: Beam widths are half-widths or radii, so this is a beam that represents a cylinder with 2" radius |
|
const float NARROW_BEAM_WIDTH = 2; |
|
const float WIDE_BEAM_WIDTH = 16; |
|
const float FLARE_SIZE = 128; |
|
const float DARK_SIZE = 64; |
|
const float AFTERGLOW_SIZE = 64; |
|
|
|
const float WARP_SIZE = 512; |
|
const float WARP_REFRACT = 0.075f; |
|
const float WARP_BUBBLE_SIZE = 256; |
|
const float WARP_BUBBLE_REFRACT = 1.0f; |
|
|
|
CStriderFXEnvelope::CStriderFXEnvelope() |
|
{ |
|
AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1 ) ); |
|
AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_WARP_SCALE, CSimpleKeyInterp( 1.3, KEY_LINEAR, 0 ) ); |
|
|
|
AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) ); |
|
AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 1.0, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 1.25, KEY_SPLINE, 0 ) ); |
|
AddKey( STRIDERFX_DARKNESS, CSimpleKeyInterp( 2.0, KEY_SPLINE, 0 ) ); |
|
|
|
AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1 ) ); |
|
AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 1.5, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_FLARE_COLOR, CSimpleKeyInterp( 2.0, KEY_SPLINE, 0 ) ); |
|
|
|
AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 1.0, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_FLARE_SIZE, CSimpleKeyInterp( 2.0, KEY_LINEAR, 1 ) ); |
|
|
|
AddKey( STRIDERFX_BUBBLE_SIZE, CSimpleKeyInterp( 1.3, KEY_LINEAR, 0.5 ) ); |
|
AddKey( STRIDERFX_BUBBLE_SIZE, CSimpleKeyInterp( 2.0, KEY_DECELERATE, 2 ) ); |
|
|
|
AddKey( STRIDERFX_BUBBLE_REFRACT, CSimpleKeyInterp( 1.3, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_BUBBLE_REFRACT, CSimpleKeyInterp( 2.0, KEY_LINEAR, 0 ) ); |
|
|
|
AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 1.25, KEY_ACCELERATE, 1.0 ) ); |
|
AddKey( STRIDERFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 1.5, KEY_SPLINE, 0 ) ); |
|
|
|
AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.5, KEY_ACCELERATE, 1 ) ); |
|
AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 1.5, KEY_DECELERATE, 2 ) ); |
|
|
|
AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.25, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.5, KEY_SPLINE, 1 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 1.75, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_COLOR, CSimpleKeyInterp( 2.1, KEY_SPLINE, 0 ) ); |
|
|
|
AddKey( STRIDERFX_WIDE_BEAM_SIZE, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_SIZE, CSimpleKeyInterp( 2.1, KEY_LINEAR, 1 ) ); |
|
|
|
AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 1.0, KEY_LINEAR, 0 ) ); |
|
AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 1.25, KEY_SPLINE, 1 ) ); |
|
AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); |
|
AddKey( STRIDERFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.5, KEY_ACCELERATE, 0 ) ); |
|
|
|
AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 1.25, KEY_LINEAR, 1.0 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 1.5, KEY_ACCELERATE, 0.0 ) ); |
|
AddKey( STRIDERFX_WIDE_BEAM_LENGTH, CSimpleKeyInterp( 2.1, KEY_LINEAR, 0 ) ); |
|
|
|
//AddKey( STRIDERFX_SPARK_COUNT, |
|
//AddKey( STRIDERFX_STREAK_COUNT, |
|
//AddKey( STRIDERFX_STEAM_COUNT, |
|
} |
|
|
|
CStriderFXEnvelope g_StriderCannonEnvelope; |
|
|
|
void ScaleColor( color32 &out, const color32 &in, float scale ) |
|
{ |
|
out.r = (byte)(int)((float)in.r * scale); |
|
out.g = (byte)(int)((float)in.g * scale); |
|
out.b = (byte)(int)((float)in.b * scale); |
|
out.a = (byte)(int)((float)in.a * scale); |
|
} |
|
|
|
void DrawSpriteTangentSpace( const Vector &vecOrigin, float flWidth, float flHeight, color32 color ) |
|
{ |
|
unsigned char pColor[4] = { color.r, color.g, color.b, color.a }; |
|
|
|
// Generate half-widths |
|
flWidth *= 0.5f; |
|
flHeight *= 0.5f; |
|
|
|
// Compute direction vectors for the sprite |
|
Vector fwd, right( 1, 0, 0 ), up( 0, 1, 0 ); |
|
VectorSubtract( CurrentViewOrigin(), vecOrigin, fwd ); |
|
float flDist = VectorNormalize( fwd ); |
|
if (flDist >= 1e-3) |
|
{ |
|
CrossProduct( CurrentViewUp(), fwd, right ); |
|
flDist = VectorNormalize( right ); |
|
if (flDist >= 1e-3) |
|
{ |
|
CrossProduct( fwd, right, up ); |
|
} |
|
else |
|
{ |
|
// In this case, fwd == g_vecVUp, it's right above or |
|
// below us in screen space |
|
CrossProduct( fwd, CurrentViewRight(), up ); |
|
VectorNormalize( up ); |
|
CrossProduct( up, fwd, right ); |
|
} |
|
} |
|
|
|
Vector left = -right; |
|
Vector down = -up; |
|
Vector back = -fwd; |
|
|
|
CMeshBuilder meshBuilder; |
|
Vector point; |
|
CMatRenderContextPtr pRenderContext( materials ); |
|
IMesh* pMesh = pRenderContext->GetDynamicMesh( ); |
|
|
|
meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); |
|
|
|
meshBuilder.Color4ubv (pColor); |
|
meshBuilder.TexCoord2f (0, 0, 1); |
|
VectorMA (vecOrigin, -flHeight, up, point); |
|
VectorMA (point, -flWidth, right, point); |
|
meshBuilder.TangentS3fv( left.Base() ); |
|
meshBuilder.TangentT3fv( down.Base() ); |
|
meshBuilder.Normal3fv( back.Base() ); |
|
meshBuilder.Position3fv (point.Base()); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Color4ubv (pColor); |
|
meshBuilder.TexCoord2f (0, 0, 0); |
|
VectorMA (vecOrigin, flHeight, up, point); |
|
VectorMA (point, -flWidth, right, point); |
|
meshBuilder.TangentS3fv( left.Base() ); |
|
meshBuilder.TangentT3fv( down.Base() ); |
|
meshBuilder.Normal3fv( back.Base() ); |
|
meshBuilder.Position3fv (point.Base()); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Color4ubv (pColor); |
|
meshBuilder.TexCoord2f (0, 1, 0); |
|
VectorMA (vecOrigin, flHeight, up, point); |
|
VectorMA (point, flWidth, right, point); |
|
meshBuilder.TangentS3fv( left.Base() ); |
|
meshBuilder.TangentT3fv( down.Base() ); |
|
meshBuilder.Normal3fv( back.Base() ); |
|
meshBuilder.Position3fv (point.Base()); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.Color4ubv (pColor); |
|
meshBuilder.TexCoord2f (0, 1, 1); |
|
VectorMA (vecOrigin, -flHeight, up, point); |
|
VectorMA (point, flWidth, right, point); |
|
meshBuilder.TangentS3fv( left.Base() ); |
|
meshBuilder.TangentT3fv( down.Base() ); |
|
meshBuilder.Normal3fv( back.Base() ); |
|
meshBuilder.Position3fv (point.Base()); |
|
meshBuilder.AdvanceVertex(); |
|
|
|
meshBuilder.End(); |
|
pMesh->Draw(); |
|
} |
|
|
|
|
|
void Strider_DrawSprite( const Vector &vecOrigin, float size, const color32 &color ) |
|
{ |
|
DrawSpriteTangentSpace( vecOrigin, size, size, color ); |
|
} |
|
|
|
|
|
void Strider_DrawLine( const Vector &start, const Vector &end, float width, IMaterial *pMaterial, const color32 &color ) |
|
{ |
|
FX_DrawLineFade( start, end, width, pMaterial, color, 8.0f ); |
|
} |
|
|
|
int C_StriderFX::DrawModel( int ) |
|
{ |
|
static color32 white = {255,255,255,255}; |
|
Vector params[STRIDERFX_PARAMETERS]; |
|
bool hasParam[STRIDERFX_PARAMETERS]; |
|
|
|
if ( !m_active ) |
|
return 1; |
|
|
|
C_BaseEntity *ent = cl_entitylist->GetEnt( m_entityIndex ); |
|
if ( ent ) |
|
{ |
|
QAngle angles; |
|
ent->GetAttachment( m_attachment, m_worldPosition, angles ); |
|
} |
|
|
|
// This forces time to drive from the main clock instead of being integrated per-draw below |
|
// that way the effect moves on even when culled for visibility |
|
if ( m_limitHitTime > 0 && m_tMax > 0 ) |
|
{ |
|
float dt = m_limitHitTime - gpGlobals->curtime; |
|
if ( dt < 0 ) |
|
{ |
|
dt = 0; |
|
} |
|
// if the clock needs to move, update it. |
|
if ( m_tMax - dt > m_t ) |
|
{ |
|
m_t = m_tMax - dt; |
|
m_beamEndPosition = m_worldPosition; |
|
} |
|
} |
|
else |
|
{ |
|
// don't have enough info to derive the time, integrate current frame time |
|
m_t += gpGlobals->frametime; |
|
if ( m_tMax > 0 ) |
|
{ |
|
m_t = clamp( m_t, 0, m_tMax ); |
|
m_beamEndPosition = m_worldPosition; |
|
} |
|
} |
|
float t = m_t; |
|
|
|
bool hasAny = false; |
|
memset( hasParam, 0, sizeof(hasParam) ); |
|
for ( int i = 0; i < STRIDERFX_PARAMETERS; i++ ) |
|
{ |
|
hasParam[i] = g_StriderCannonEnvelope.m_parameters[i].Interp( params[i], t ); |
|
hasAny = hasAny || hasParam[i]; |
|
} |
|
|
|
pixelvis_queryparams_t gunParams; |
|
gunParams.Init(m_worldPosition, 4.0f); |
|
float gunFractionVisible = PixelVisibility_FractionVisible( gunParams, &m_queryHandleGun ); |
|
bool gunVisible = gunFractionVisible > 0.0f ? true : false; |
|
|
|
// draw the narrow beam |
|
if ( hasParam[STRIDERFX_NARROW_BEAM_COLOR] && hasParam[STRIDERFX_NARROW_BEAM_SIZE] ) |
|
{ |
|
IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float width = NARROW_BEAM_WIDTH * params[STRIDERFX_NARROW_BEAM_SIZE].x; |
|
color32 color; |
|
float bright = params[STRIDERFX_NARROW_BEAM_COLOR].x; |
|
ScaleColor( color, white, bright ); |
|
|
|
Strider_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); |
|
} |
|
|
|
// draw the wide beam |
|
if ( hasParam[STRIDERFX_WIDE_BEAM_COLOR] && hasParam[STRIDERFX_WIDE_BEAM_SIZE] ) |
|
{ |
|
IMaterial *pMat = materials->FindMaterial( "effects/blueblacklargebeam", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float width = WIDE_BEAM_WIDTH * params[STRIDERFX_WIDE_BEAM_SIZE].x; |
|
color32 color; |
|
float bright = params[STRIDERFX_WIDE_BEAM_COLOR].x; |
|
ScaleColor( color, white, bright ); |
|
Vector wideBeamEnd = m_beamEndPosition; |
|
if ( hasParam[STRIDERFX_WIDE_BEAM_LENGTH] ) |
|
{ |
|
float amt = params[STRIDERFX_WIDE_BEAM_LENGTH].x; |
|
wideBeamEnd = m_beamEndPosition * amt + m_targetPosition * (1-amt); |
|
} |
|
|
|
Strider_DrawLine( wideBeamEnd, m_targetPosition, width, pMat, color ); |
|
} |
|
|
|
// after glow sprite |
|
bool updated = false; |
|
CMatRenderContextPtr pRenderContext( materials ); |
|
// warpy sprite bit |
|
if ( hasParam[STRIDERFX_WARP_SCALE] && !hasParam[STRIDERFX_BUBBLE_SIZE] && gunVisible ) |
|
{ |
|
if ( !updated ) |
|
{ |
|
updated = true; |
|
pRenderContext->Flush(); |
|
UpdateRefractTexture(); |
|
} |
|
|
|
IMaterial *pMat = materials->FindMaterial( "effects/strider_pinch_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float size = WARP_SIZE; |
|
float refract = params[STRIDERFX_WARP_SCALE].x * WARP_REFRACT * gunFractionVisible; |
|
|
|
pRenderContext->Bind( pMat, (IClientRenderable*)this ); |
|
IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); |
|
pVar->SetFloatValue( refract ); |
|
Strider_DrawSprite( m_worldPosition, size, white ); |
|
} |
|
// darkening sprite |
|
// glowy blue flare sprite |
|
if ( hasParam[STRIDERFX_FLARE_COLOR] && hasParam[STRIDERFX_FLARE_SIZE] && hasParam[STRIDERFX_DARKNESS] && gunVisible ) |
|
{ |
|
IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float size = FLARE_SIZE * params[STRIDERFX_FLARE_SIZE].x; |
|
color32 color; |
|
float bright = params[STRIDERFX_FLARE_COLOR].x * gunFractionVisible; |
|
ScaleColor( color, white, bright ); |
|
color.a = (int)(255 * params[STRIDERFX_DARKNESS].x); |
|
pRenderContext->Bind( pMat, (IClientRenderable*)this ); |
|
Strider_DrawSprite( m_worldPosition, size, color ); |
|
} |
|
// bubble warpy sprite |
|
if ( hasParam[STRIDERFX_BUBBLE_SIZE] ) |
|
{ |
|
Vector wideBeamEnd = m_beamEndPosition; |
|
if ( hasParam[STRIDERFX_WIDE_BEAM_LENGTH] ) |
|
{ |
|
float amt = params[STRIDERFX_WIDE_BEAM_LENGTH].x; |
|
wideBeamEnd = m_beamEndPosition * amt + m_targetPosition * (1-amt); |
|
} |
|
pixelvis_queryparams_t endParams; |
|
endParams.Init(wideBeamEnd, 4.0f, 0.001f); |
|
float endFractionVisible = PixelVisibility_FractionVisible( endParams, &m_queryHandleBeamEnd ); |
|
bool endVisible = endFractionVisible > 0.0f ? true : false; |
|
|
|
if ( endVisible ) |
|
{ |
|
if ( !updated ) |
|
{ |
|
updated = true; |
|
pRenderContext->Flush(); |
|
UpdateRefractTexture(); |
|
} |
|
IMaterial *pMat = materials->FindMaterial( "effects/strider_bulge_dudv", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float refract = endFractionVisible * WARP_BUBBLE_REFRACT * params[STRIDERFX_BUBBLE_REFRACT].x; |
|
float size = WARP_BUBBLE_SIZE * params[STRIDERFX_BUBBLE_SIZE].x; |
|
IMaterialVar *pVar = pMat->FindVar( "$refractamount", NULL ); |
|
pVar->SetFloatValue( refract ); |
|
|
|
pRenderContext->Bind( pMat, (IClientRenderable*)this ); |
|
Strider_DrawSprite( wideBeamEnd, size, white ); |
|
} |
|
} |
|
else |
|
{ |
|
// call this to have the check ready on the first frame |
|
pixelvis_queryparams_t endParams; |
|
endParams.Init(m_beamEndPosition, 4.0f, 0.001f); |
|
PixelVisibility_FractionVisible( endParams, &m_queryHandleBeamEnd ); |
|
} |
|
if ( hasParam[STRIDERFX_AFTERGLOW_COLOR] && gunVisible ) |
|
{ |
|
IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); |
|
float size = AFTERGLOW_SIZE;// * params[STRIDERFX_FLARE_SIZE].x; |
|
color32 color; |
|
float bright = params[STRIDERFX_AFTERGLOW_COLOR].x * gunFractionVisible; |
|
ScaleColor( color, white, bright ); |
|
|
|
pRenderContext->Bind( pMat, (IClientRenderable*)this ); |
|
Strider_DrawSprite( m_worldPosition, size, color ); |
|
|
|
dlight_t *dl = effects->CL_AllocDlight( m_entityIndex ); |
|
dl->origin = m_worldPosition; |
|
dl->color.r = 40; |
|
dl->color.g = 60; |
|
dl->color.b = 255; |
|
dl->color.exponent = 5; |
|
dl->radius = bright * 128; |
|
dl->die = gpGlobals->curtime + 0.001; |
|
} |
|
|
|
if ( m_t >= STRIDERFX_END_ALL_TIME && !hasAny ) |
|
{ |
|
EffectShutdown(); |
|
} |
|
return 1; |
|
} |
|
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Strider class implementation |
|
//----------------------------------------------------------------------------- |
|
C_Strider::C_Strider() : |
|
m_iv_vecHitPos("C_Strider::m_iv_vecHitPos"), |
|
m_iv_vecIKTarget("C_Strider::m_iv_vecIKTarget") |
|
{ |
|
AddVar( &m_vecHitPos, &m_iv_vecHitPos, LATCH_ANIMATION_VAR ); |
|
|
|
memset(m_vecIKTarget, 0, sizeof(m_vecIKTarget)); |
|
AddVar( &m_vecIKTarget, &m_iv_vecIKTarget, LATCH_ANIMATION_VAR ); |
|
|
|
m_flNextRopeCutTime = 0; |
|
} |
|
|
|
C_Strider::~C_Strider() |
|
{ |
|
} |
|
|
|
void C_Strider::ReceiveMessage( int classID, bf_read &msg ) |
|
{ |
|
if ( classID != GetClientClass()->m_ClassID ) |
|
{ |
|
// message is for subclass |
|
BaseClass::ReceiveMessage( classID, msg ); |
|
return; |
|
} |
|
|
|
int messageType = msg.ReadByte(); |
|
switch( messageType ) |
|
{ |
|
case STRIDER_MSG_STREAKS: |
|
{ |
|
Vector pos; |
|
msg.ReadBitVec3Coord( pos ); |
|
m_cannonFX.SetRenderOrigin( pos ); |
|
m_cannonFX.EffectInit( entindex(), LookupAttachment( "BigGun" ) ); |
|
m_cannonFX.LimitTime( STRIDERFX_BIG_SHOT_TIME ); |
|
} |
|
break; |
|
|
|
case STRIDER_MSG_BIG_SHOT: |
|
{ |
|
Vector tmp; |
|
msg.ReadBitVec3Coord( tmp ); |
|
m_cannonFX.SetTime( STRIDERFX_BIG_SHOT_TIME ); |
|
m_cannonFX.LimitTime( STRIDERFX_END_ALL_TIME ); |
|
} |
|
break; |
|
|
|
case STRIDER_MSG_DEAD: |
|
{ |
|
m_cannonFX.EffectShutdown(); |
|
} |
|
break; |
|
} |
|
} |
|
|
|
|
|
void C_Strider::OnDataChanged( DataUpdateType_t updateType ) |
|
{ |
|
if ( updateType == DATA_UPDATE_CREATED ) |
|
{ |
|
// We need to have our render bounds defined or shadow creation won't work correctly |
|
ClientThink(); |
|
ClientThinkList()->SetNextClientThink( GetClientHandle(), CLIENT_THINK_ALWAYS ); |
|
} |
|
|
|
BaseClass::OnDataChanged( updateType ); |
|
|
|
m_cannonFX.Update( this, m_vecHitPos ); |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Recompute my rendering box |
|
//----------------------------------------------------------------------------- |
|
void C_Strider::ClientThink() |
|
{ |
|
// The reason why this is here, as opposed to in SetObjectCollisionBox, |
|
// is because of IK. The code below recomputes bones so as to get at the hitboxes, |
|
// which causes IK to trigger, which causes raycasts against the other entities to occur, |
|
// which is illegal to do while in the Relink phase. |
|
|
|
ComputeEntitySpaceHitboxSurroundingBox( &m_vecRenderMins, &m_vecRenderMaxs ); |
|
// UNDONE: Disabled this until we can get closer to a final map and tune |
|
#if 0 |
|
// Cut ropes. |
|
if ( gpGlobals->curtime >= m_flNextRopeCutTime ) |
|
{ |
|
// Blow the bbox out a little. |
|
Vector vExtendedMins = vecMins - Vector( 50, 50, 50 ); |
|
Vector vExtendedMaxs = vecMaxs + Vector( 50, 50, 50 ); |
|
|
|
C_RopeKeyframe *ropes[512]; |
|
int nRopes = C_RopeKeyframe::GetRopesIntersectingAABB( ropes, ARRAYSIZE( ropes ), GetAbsOrigin() + vExtendedMins, GetAbsOrigin() + vExtendedMaxs ); |
|
for ( int i=0; i < nRopes; i++ ) |
|
{ |
|
C_RopeKeyframe *pRope = ropes[i]; |
|
|
|
if ( pRope->GetEndEntity() ) |
|
{ |
|
Vector vPos; |
|
if ( pRope->GetEndPointPos( 1, vPos ) ) |
|
{ |
|
// Detach the endpoint. |
|
pRope->SetEndEntity( NULL ); |
|
|
|
// Make some spark effect here.. |
|
g_pEffects->Sparks( vPos ); |
|
} |
|
} |
|
} |
|
|
|
m_flNextRopeCutTime = gpGlobals->curtime + 0.5; |
|
} |
|
#endif |
|
|
|
// True argument because the origin may have stayed the same, but the size is expected to always change |
|
g_pClientShadowMgr->AddToDirtyShadowList( this, true ); |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: Recompute my rendering box |
|
//----------------------------------------------------------------------------- |
|
void C_Strider::GetRenderBounds( Vector& theMins, Vector& theMaxs ) |
|
{ |
|
theMins = m_vecRenderMins; |
|
theMaxs = m_vecRenderMaxs; |
|
} |
|
|
|
|
|
//----------------------------------------------------------------------------- |
|
// Strider muzzle flashes |
|
//----------------------------------------------------------------------------- |
|
void MuzzleFlash_Strider( ClientEntityHandle_t hEntity, int attachmentIndex ) |
|
{ |
|
VPROF_BUDGET( "MuzzleFlash_Strider", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); |
|
|
|
// If the client hasn't seen this entity yet, bail. |
|
matrix3x4_t matAttachment; |
|
if ( !FX_GetAttachmentTransform( hEntity, attachmentIndex, matAttachment ) ) |
|
return; |
|
|
|
CSmartPtr<CLocalSpaceEmitter> pSimple = CLocalSpaceEmitter::Create( "MuzzleFlash_Strider", hEntity, attachmentIndex ); |
|
|
|
SimpleParticle *pParticle; |
|
Vector forward(1,0,0), offset; //NOTENOTE: All coords are in local space |
|
|
|
float flScale = random->RandomFloat( 3.0f, 4.0f ); |
|
|
|
float burstSpeed = random->RandomFloat( 400.0f, 600.0f ); |
|
|
|
#define FRONT_LENGTH 12 |
|
|
|
// Front flash |
|
for ( int i = 1; i < FRONT_LENGTH; i++ ) |
|
{ |
|
offset = (forward * (i*2.0f*flScale)); |
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), 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-(i))/(FRONT_LENGTH*0.75f)) * 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 8 |
|
|
|
burstSpeed = random->RandomFloat( 400.0f, 600.0f ); |
|
|
|
// Diagonal flash |
|
for ( int i = 1; i < SIDE_LENGTH; i++ ) |
|
{ |
|
offset = (dir * (i*flScale)); |
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), 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( 400.0f, 600.0f ); |
|
|
|
// Diagonal flash |
|
for ( int i = 1; i < SIDE_LENGTH; i++ ) |
|
{ |
|
offset = (-dir * (i*flScale)); |
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), 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( 400.0f, 600.0f ); |
|
|
|
// Top flash |
|
for ( int i = 1; i < SIDE_LENGTH; i++ ) |
|
{ |
|
offset = (dir * (i*flScale)); |
|
|
|
pParticle = (SimpleParticle *) pSimple->AddParticle( sizeof( SimpleParticle ), pSimple->GetPMaterial( VarArgs( "effects/combinemuzzle%d", random->RandomInt(1,2) ) ), 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 ), pSimple->GetPMaterial( "effects/strider_muzzle" ), 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; |
|
|
|
Vector origin; |
|
MatrixGetColumn( matAttachment, 3, &origin ); |
|
|
|
int entityIndex = ClientEntityList().HandleToEntIndex( hEntity ); |
|
if ( entityIndex >= 0 ) |
|
{ |
|
dlight_t *el = effects->CL_AllocElight( LIGHT_INDEX_MUZZLEFLASH + entityIndex ); |
|
|
|
el->origin = origin; |
|
|
|
el->color.r = 64; |
|
el->color.g = 128; |
|
el->color.b = 255; |
|
el->color.exponent = 5; |
|
|
|
el->radius = random->RandomInt( 100, 150 ); |
|
el->decay = el->radius / 0.05f; |
|
el->die = gpGlobals->curtime + 0.1f; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &data - |
|
//----------------------------------------------------------------------------- |
|
void StriderMuzzleFlashCallback( const CEffectData &data ) |
|
{ |
|
MuzzleFlash_Strider( data.m_hEntity, data.m_nAttachmentIndex ); |
|
} |
|
|
|
DECLARE_CLIENT_EFFECT( "StriderMuzzleFlash", StriderMuzzleFlashCallback ); |
|
|
|
#define BLOOD_MIN_SPEED 64.0f*2.0f |
|
#define BLOOD_MAX_SPEED 256.0f*8.0f |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &origin - |
|
// &normal - |
|
// scale - |
|
//----------------------------------------------------------------------------- |
|
void StriderBlood( const Vector &origin, const Vector &normal, float scale ) |
|
{ |
|
VPROF_BUDGET( "StriderBlood", VPROF_BUDGETGROUP_PARTICLE_RENDERING ); |
|
|
|
//Find area ambient light color and use it to tint smoke |
|
Vector worldLight = WorldGetLightForPoint( origin, true ); |
|
Vector tint; |
|
float luminosity; |
|
UTIL_GetNormalizedColorTintAndLuminosity( worldLight, &tint, &luminosity ); |
|
|
|
// We only take a portion of the tint |
|
tint = (tint * 0.25f)+(Vector(0.75f,0.75f,0.75f)); |
|
|
|
// Rescale to a character range |
|
luminosity = MAX( 200, luminosity*255 ); |
|
|
|
CSmartPtr<CSplashParticle> pSimple = CSplashParticle::Create( "splish" ); |
|
pSimple->SetSortOrigin( origin ); |
|
|
|
int i; |
|
float flScale = scale / 8.0f; |
|
|
|
PMaterialHandle hMaterial = ParticleMgr()->GetPMaterial( "effects/slime1" ); |
|
|
|
float length = 0.2f; |
|
Vector vForward, vRight, vUp; |
|
Vector offDir; |
|
|
|
TrailParticle *tParticle; |
|
|
|
CSmartPtr<CTrailParticles> sparkEmitter = CTrailParticles::Create( "splash" ); |
|
|
|
if ( !sparkEmitter ) |
|
return; |
|
|
|
sparkEmitter->SetSortOrigin( origin ); |
|
sparkEmitter->m_ParticleCollision.SetGravity( 600.0f ); |
|
sparkEmitter->SetFlag( bitsPARTICLE_TRAIL_VELOCITY_DAMPEN ); |
|
sparkEmitter->SetVelocityDampen( 2.0f ); |
|
|
|
//Dump out drops |
|
Vector offset; |
|
for ( i = 0; i < 64; i++ ) |
|
{ |
|
offset = origin; |
|
offset[0] += random->RandomFloat( -8.0f, 8.0f ) * flScale; |
|
offset[1] += random->RandomFloat( -8.0f, 8.0f ) * flScale; |
|
offset[2] += random->RandomFloat( -8.0f, 8.0f ) * flScale; |
|
|
|
tParticle = (TrailParticle *) sparkEmitter->AddParticle( sizeof(TrailParticle), hMaterial, offset ); |
|
|
|
if ( tParticle == NULL ) |
|
break; |
|
|
|
tParticle->m_flLifetime = 0.0f; |
|
tParticle->m_flDieTime = 1.0f; |
|
|
|
offDir = normal + RandomVector( -1.0f, 1.0f ); |
|
|
|
tParticle->m_vecVelocity = offDir * random->RandomFloat( BLOOD_MIN_SPEED * flScale * 2.0f, BLOOD_MAX_SPEED * flScale * 2.0f ); |
|
tParticle->m_vecVelocity[2] += random->RandomFloat( 8.0f, 32.0f ) * flScale; |
|
|
|
tParticle->m_flWidth = random->RandomFloat( 20.0f, 26.0f ) * flScale; |
|
tParticle->m_flLength = random->RandomFloat( length*0.5f, length ) * flScale; |
|
|
|
int nColor = random->RandomInt( luminosity*0.75f, luminosity ); |
|
tParticle->m_color.r = nColor * tint.x; |
|
tParticle->m_color.g = nColor * tint.y; |
|
tParticle->m_color.b = nColor * tint.z; |
|
tParticle->m_color.a = 255; |
|
} |
|
} |
|
|
|
//----------------------------------------------------------------------------- |
|
// Purpose: |
|
// Input : &data - |
|
//----------------------------------------------------------------------------- |
|
void StriderBloodCallback( const CEffectData &data ) |
|
{ |
|
StriderBlood( data.m_vOrigin, data.m_vNormal, data.m_flScale ); |
|
} |
|
|
|
DECLARE_CLIENT_EFFECT( "StriderBlood", StriderBloodCallback ); |
|
|
|
|