diff options
| author | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
|---|---|---|
| committer | FluorescentCIAAfricanAmerican <[email protected]> | 2020-04-22 12:56:21 -0400 |
| commit | 3bf9df6b2785fa6d951086978a3e66f49427166a (patch) | |
| tree | 2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /game/client/hl2/c_strider.cpp | |
| download | archived-source-engine-2018-hl2-src-master.tar.xz archived-source-engine-2018-hl2-src-master.zip | |
Diffstat (limited to 'game/client/hl2/c_strider.cpp')
| -rw-r--r-- | game/client/hl2/c_strider.cpp | 1048 |
1 files changed, 1048 insertions, 0 deletions
diff --git a/game/client/hl2/c_strider.cpp b/game/client/hl2/c_strider.cpp new file mode 100644 index 0000000..3ea3f73 --- /dev/null +++ b/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 ); + |