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.
476 lines
13 KiB
476 lines
13 KiB
//========= 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 ); |
|
|
|
|