aboutsummaryrefslogtreecommitdiff
path: root/sp/src/game/client/hl2/c_strider.cpp
diff options
context:
space:
mode:
authorJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
committerJoe Ludwig <[email protected]>2013-06-26 15:22:04 -0700
commit39ed87570bdb2f86969d4be821c94b722dc71179 (patch)
treeabc53757f75f40c80278e87650ea92808274aa59 /sp/src/game/client/hl2/c_strider.cpp
downloadsource-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.tar.xz
source-sdk-2013-39ed87570bdb2f86969d4be821c94b722dc71179.zip
First version of the SOurce SDK 2013
Diffstat (limited to 'sp/src/game/client/hl2/c_strider.cpp')
-rw-r--r--sp/src/game/client/hl2/c_strider.cpp1048
1 files changed, 1048 insertions, 0 deletions
diff --git a/sp/src/game/client/hl2/c_strider.cpp b/sp/src/game/client/hl2/c_strider.cpp
new file mode 100644
index 00000000..f05f335a
--- /dev/null
+++ b/sp/src/game/client/hl2/c_strider.cpp
@@ -0,0 +1,1048 @@
+//========= 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 );
+