diff options
Diffstat (limited to 'game/client/hl2/c_npc_combinegunship.cpp')
| -rw-r--r-- | game/client/hl2/c_npc_combinegunship.cpp | 476 |
1 files changed, 476 insertions, 0 deletions
diff --git a/game/client/hl2/c_npc_combinegunship.cpp b/game/client/hl2/c_npc_combinegunship.cpp new file mode 100644 index 0000000..b42ca04 --- /dev/null +++ b/game/client/hl2/c_npc_combinegunship.cpp @@ -0,0 +1,476 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//=============================================================================// + +#include "cbase.h" +#include "c_basehelicopter.h" +#include "fx_impact.h" +#include "IEffects.h" +#include "simple_keys.h" +#include "fx_envelope.h" +#include "fx_line.h" +#include "iefx.h" +#include "dlight.h" +#include "c_sprite.h" +#include "clienteffectprecachesystem.h" +#include <bitbuf.h> + +// memdbgon must be the last include file in a .cpp file!!! +#include "tier0/memdbgon.h" + +#define GUNSHIP_MSG_BIG_SHOT 1 +#define GUNSHIP_MSG_STREAKS 2 +#define GUNSHIP_MSG_DEAD 3 + +#define GUNSHIPFX_BIG_SHOT_TIME 3.0f + +CLIENTEFFECT_REGISTER_BEGIN( PrecacheGunshipFX ) +CLIENTEFFECT_MATERIAL( "sprites/bluelaser1" ) +CLIENTEFFECT_REGISTER_END() + +//----------------------------------------------------------------------------- +// Big belly shot FX +//----------------------------------------------------------------------------- + +class C_GunshipFX : public C_EnvelopeFX +{ +public: + typedef C_EnvelopeFX BaseClass; + + C_GunshipFX(); + 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 int DrawModel( int flags ); + + C_BaseEntity *m_pOwner; + Vector m_targetPosition; + Vector m_beamEndPosition; +}; + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_GunshipFX::C_GunshipFX( void ) +{ + m_pOwner = NULL; +} + +enum +{ + GUNSHIPFX_WARP_SCALE = 0, + GUNSHIPFX_DARKNESS, + GUNSHIPFX_FLARE_COLOR, + GUNSHIPFX_FLARE_SIZE, + + GUNSHIPFX_NARROW_BEAM_COLOR, + GUNSHIPFX_NARROW_BEAM_SIZE, + + GUNSHIPFX_WIDE_BEAM_COLOR, + GUNSHIPFX_WIDE_BEAM_SIZE, + + GUNSHIPFX_AFTERGLOW_COLOR, + + GUNSHIPFX_WIDE_BEAM_LENGTH, + + // must be last + GUNSHIPFX_PARAMETERS, +}; + +class CGunshipFXEnvelope +{ +public: + CGunshipFXEnvelope(); + + void AddKey( int parameterIndex, const CSimpleKeyInterp &key ) + { + Assert( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS ); + + if ( parameterIndex >= 0 && parameterIndex < GUNSHIPFX_PARAMETERS ) + { + m_parameters[parameterIndex].Insert( key ); + } + + } + + CSimpleKeyList m_parameters[GUNSHIPFX_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 = 32; +const float WIDE_BEAM_WIDTH = 2; +const float FLARE_SIZE = 128; +const float DARK_SIZE = 16; +const float AFTERGLOW_SIZE = 64; + +CGunshipFXEnvelope::CGunshipFXEnvelope() +{ + // Glow flare + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 0.5, KEY_SPLINE, 1 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 2.9, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_FLARE_COLOR, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) ); + + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 2.9, KEY_ACCELERATE, 1 ) ); + AddKey( GUNSHIPFX_FLARE_SIZE, CSimpleKeyInterp( 5.0, KEY_LINEAR, 1 ) ); + + // Ground beam + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0.0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 2.5, KEY_SPLINE, 1.0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_COLOR, CSimpleKeyInterp( 3.2, KEY_ACCELERATE, 0 ) ); + + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.5, KEY_SPLINE, 0.25 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 2.8, KEY_ACCELERATE, 1 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.0, KEY_ACCELERATE, 4 ) ); + AddKey( GUNSHIPFX_NARROW_BEAM_SIZE, CSimpleKeyInterp( 3.2, KEY_DECELERATE, 0 ) ); + + // Glow color on the ship + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 0.0, KEY_LINEAR, 0 ) ); + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 3.0, KEY_LINEAR, 1 ) ); + AddKey( GUNSHIPFX_AFTERGLOW_COLOR, CSimpleKeyInterp( 5.0, KEY_SPLINE, 0 ) ); +} + +CGunshipFXEnvelope g_GunshipCannonEnvelope; + +static 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); +} + +static 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; + + CMatRenderContextPtr pRenderContext( materials ); + + CMeshBuilder meshBuilder; + Vector point; + 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 Gunship_DrawSprite( const Vector &vecOrigin, float size, const color32 &color, bool glow ) +{ + if ( glow ) + { + pixelvis_queryparams_t params; + params.Init( vecOrigin ); + if ( PixelVisibility_FractionVisible( params, NULL ) <= 0.0f ) + return; + } + + DrawSpriteTangentSpace( vecOrigin, size, size, color ); +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : int - +//----------------------------------------------------------------------------- +int C_GunshipFX::DrawModel( int ) +{ + static color32 white = {255,255,255,255}; + Vector params[GUNSHIPFX_PARAMETERS]; + bool hasParam[GUNSHIPFX_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 ); + } + + Vector test; + 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 < GUNSHIPFX_PARAMETERS; i++ ) + { + hasParam[i] = g_GunshipCannonEnvelope.m_parameters[i].Interp( params[i], t ); + hasAny = hasAny || hasParam[i]; + } + + // draw the narrow beam + if ( hasParam[GUNSHIPFX_NARROW_BEAM_COLOR] && hasParam[GUNSHIPFX_NARROW_BEAM_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "sprites/bluelaser1", TEXTURE_GROUP_CLIENT_EFFECTS ); + float width = NARROW_BEAM_WIDTH * params[GUNSHIPFX_NARROW_BEAM_SIZE].x; + color32 color; + float bright = params[GUNSHIPFX_NARROW_BEAM_COLOR].x; + ScaleColor( color, white, bright ); + + //Gunship_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); + FX_DrawLine( m_beamEndPosition, m_targetPosition, width, pMat, color ); + } + + // glowy blue flare sprite + if ( hasParam[GUNSHIPFX_FLARE_COLOR] && hasParam[GUNSHIPFX_FLARE_SIZE] ) + { + IMaterial *pMat = materials->FindMaterial( "effects/blueblackflash", TEXTURE_GROUP_CLIENT_EFFECTS ); + float size = FLARE_SIZE * params[GUNSHIPFX_FLARE_SIZE].x; + color32 color; + float bright = params[GUNSHIPFX_FLARE_COLOR].x; + ScaleColor( color, white, bright ); + color.a = (int)(255 * params[GUNSHIPFX_DARKNESS].x); + CMatRenderContextPtr pRenderContext( materials ); + pRenderContext->Bind( pMat, (IClientRenderable*)this ); + Gunship_DrawSprite( m_worldPosition, size, color, true ); + } + + if ( hasParam[GUNSHIPFX_AFTERGLOW_COLOR] ) + { + // Muzzle effect + dlight_t *dl = effects->CL_AllocDlight( m_entityIndex ); + dl->origin = m_worldPosition; + dl->color.r = 40*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.g = 60*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.b = 255*params[GUNSHIPFX_AFTERGLOW_COLOR].x; + dl->color.exponent = 5; + dl->radius = 128.0f; + dl->die = gpGlobals->curtime + 0.001; + } + + if ( m_t >= 4.0 && !hasAny ) + { + EffectShutdown(); + } + + return 1; +} + +//----------------------------------------------------------------------------- +// Purpose: +// Input : *pOwner - +// &targetPos - +//----------------------------------------------------------------------------- +void C_GunshipFX::Update( C_BaseEntity *pOwner, const Vector &targetPos ) +{ + BaseClass::Update(); + + m_pOwner = pOwner; + + if ( m_active ) + { + m_targetPosition = targetPos; + } +} + +//----------------------------------------------------------------------------- +// Gunship +//----------------------------------------------------------------------------- + +class C_CombineGunship : public C_BaseHelicopter +{ + DECLARE_CLASS( C_CombineGunship, C_BaseHelicopter ); +public: + DECLARE_CLIENTCLASS(); + + C_CombineGunship( void ) {} + + virtual ~C_CombineGunship( void ) + { + m_cannonFX.EffectShutdown(); + } + + C_GunshipFX m_cannonFX; + Vector m_vecHitPos; + + //----------------------------------------------------------------------------- + // Purpose: + // Input : length - + // *data - + // Output : void + //----------------------------------------------------------------------------- + void 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 GUNSHIP_MSG_STREAKS: + { + Vector pos; + msg.ReadBitVec3Coord( pos ); + m_cannonFX.SetRenderOrigin( pos ); + m_cannonFX.EffectInit( entindex(), LookupAttachment( "BellyGun" ) ); + m_cannonFX.LimitTime( GUNSHIPFX_BIG_SHOT_TIME ); + } + break; + + case GUNSHIP_MSG_BIG_SHOT: + { + Vector tmp; + msg.ReadBitVec3Coord( tmp ); + m_cannonFX.SetTime( GUNSHIPFX_BIG_SHOT_TIME ); + m_cannonFX.LimitTime( 0 ); + } + break; + + case GUNSHIP_MSG_DEAD: + { + m_cannonFX.EffectShutdown(); + } + break; + } + } + + void OnDataChanged( DataUpdateType_t updateType ) + { + BaseClass::OnDataChanged( updateType ); + + m_cannonFX.Update( this, m_vecHitPos ); + } + + virtual RenderGroup_t GetRenderGroup() + { + if ( hl2_episodic.GetBool() == true ) + { + return RENDER_GROUP_TWOPASS; + } + else + { + return BaseClass::GetRenderGroup(); + } + } + +private: + C_CombineGunship( const C_CombineGunship & ) {} +}; + +IMPLEMENT_CLIENTCLASS_DT( C_CombineGunship, DT_CombineGunship, CNPC_CombineGunship ) + RecvPropVector(RECVINFO(m_vecHitPos)), +END_RECV_TABLE() + +//----------------------------------------------------------------------------- +// Purpose: Handle gunship impacts +//----------------------------------------------------------------------------- +void ImpactGunshipCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + C_BaseEntity *pEntity = ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + if ( !pEntity ) + return; + + // If we hit, perform our custom effects and play the sound + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 3 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactGunship", ImpactGunshipCallback ); + |