diff options
Diffstat (limited to 'game/client/tf2/fx_tf2_impacts.cpp')
| -rw-r--r-- | game/client/tf2/fx_tf2_impacts.cpp | 453 |
1 files changed, 453 insertions, 0 deletions
diff --git a/game/client/tf2/fx_tf2_impacts.cpp b/game/client/tf2/fx_tf2_impacts.cpp new file mode 100644 index 0000000..e22c70d --- /dev/null +++ b/game/client/tf2/fx_tf2_impacts.cpp @@ -0,0 +1,453 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: Game-specific impact effect hooks +// +//=============================================================================// +#include "cbase.h" +#include "fx_impact.h" +#include "decals.h" +#include "IEffects.h" +#include "c_breakableprop.h" +#include "tempent.h" +#include "c_te_legacytempents.h" +#include "tf_shareddefs.h" +#include "fx.h" + +void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MakeHurt( const CEffectData &data, bool bBlood ) +{ + 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 ) ) + { + // Throw out shards to show the player he's hurting it + ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood ); + + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 1.0 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactCallback( const CEffectData &data ) +{ + MakeHurt( data, true ); +} + +DECLARE_CLIENT_EFFECT( "Impact", ImpactCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Bloodless Impact for: +// Bullets hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactNoBloodCallback( const CEffectData &data ) +{ + MakeHurt( data, false ); +} + +DECLARE_CLIENT_EFFECT( "ImpactNoBlood", ImpactNoBloodCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting targets that CANNOT be hurt +//----------------------------------------------------------------------------- +void ImpactUnhurtCallback( 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 + // Don't decal team members, but decal everything else + + bool bShouldDecal = !( pEntity && pEntity->IsPlayer() ); + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) ) + { + // Check for custom effects based on the Decal index + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 0 ); + } + + PlayImpactSound( pEntity, tr, vecOrigin, nSurfaceProp ); +} + +DECLARE_CLIENT_EFFECT( "ImpactUnhurt", ImpactUnhurtCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Bullets hitting player's handheld shields +//----------------------------------------------------------------------------- +void ImpactShieldCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + // Don't call Impact() because we don't want to decal the player + Vector reflect = -vecShotDir; + reflect[0] += random->RandomFloat( -0.5f, 0.5f ); + reflect[1] += random->RandomFloat( -0.5f, 0.5f ); + reflect[2] += random->RandomFloat( 0, 0.5f ); + FX_MetalSpark( vecOrigin, reflect, -vecShotDir, 3 ); +} + +DECLARE_CLIENT_EFFECT( "ImpactShield", ImpactShieldCallback ); + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void MakePlasmaHurt( const CEffectData &data, bool bBlood ) +{ + 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, play our splash + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + // Throw out shards to show the player he's hurting it + ImpactCreateHurtShards( vecOrigin, tr, vecShotDir, iMaterial, false, bBlood ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaCallback( const CEffectData &data ) +{ + MakePlasmaHurt( data, true ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaHurt", ImpactPlasmaCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CAN be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaNoBloodCallback( const CEffectData &data ) +{ + MakePlasmaHurt( data, false ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaHurtNoBlood", ImpactPlasmaNoBloodCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting targets that CANNOT be hurt +//----------------------------------------------------------------------------- +void ImpactPlasmaUnhurtCallback( 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, play our splash + + bool bShouldDecal = !( pEntity && pEntity->IsPlayer() ); + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr, bShouldDecal ? 0 : IMPACT_NODECAL ) ) + { + g_pEffects->EnergySplash( vecOrigin, tr.plane.normal, false ); + } +} + +DECLARE_CLIENT_EFFECT( "PlasmaUnhurt", ImpactPlasmaUnhurtCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Plasma hitting player's handheld shields +//----------------------------------------------------------------------------- +void ImpactPlasmaShieldCallback( const CEffectData &data ) +{ + trace_t tr; + Vector vecOrigin, vecStart, vecShotDir; + int iMaterial, iDamageType, iHitbox; + short nSurfaceProp; + ParseImpactData( data, &vecOrigin, &vecStart, &vecShotDir, nSurfaceProp, iMaterial, iDamageType, iHitbox ); + + // Bounce sparks away from the shield + // Don't call Impact() because we don't want to decal the player + Vector offset = vecOrigin - ( vecShotDir * 1.0f ); + Vector vecDir = -vecShotDir + Vector(0,0,1.5); + g_pEffects->Sparks( offset, 2, 2, &vecDir ); +} + +DECLARE_CLIENT_EFFECT( "PlasmaShield", ImpactPlasmaShieldCallback ); + +//----------------------------------------------------------------------------- +// Purpose: Impact for: +// Strider hitting anything +//----------------------------------------------------------------------------- +void ImpactStriderCallback( 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, play our splash + if ( Impact( vecOrigin, vecStart, iMaterial, iDamageType, iHitbox, pEntity, tr ) ) + { + PerformCustomEffects( vecOrigin, tr, vecShotDir, iMaterial, 5 ); + } +} + +DECLARE_CLIENT_EFFECT( "Strider", ImpactStriderCallback ); + + +//===================================================================================== +// SHARDS. +// Models for small impact tempents (not vphysics simulated) +//-------------------------------------------------------------------- +// WOOD +//-------------------------------------------------------------------- +#define WOOD_SHARDS 5 +const char *ImpactHurtShards_Wood_Small_Models[ WOOD_SHARDS ] = +{ +"models/props_debris/wood_shard_001.mdl", +"models/props_debris/wood_shard_002.mdl", +"models/props_debris/wood_shard_003.mdl", +"models/props_debris/wood_shard_004.mdl", +"models/props_debris/wood_shard_005.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Wood_Small[ WOOD_SHARDS ]; + +//-------------------------------------------------------------------- +// FOLIAGE +//-------------------------------------------------------------------- +#define FOLIAGE_SHARDS 5 +const char *ImpactHurtShards_Foliage_Small_Models[ FOLIAGE_SHARDS ] = +{ +"models/props_debris/foliage_shard_001.mdl", +"models/props_debris/foliage_shard_002.mdl", +"models/props_debris/foliage_shard_003.mdl", +"models/props_debris/foliage_shard_004.mdl", +"models/props_debris/foliage_shard_005.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Foliage_Small[ FOLIAGE_SHARDS ]; + +//-------------------------------------------------------------------- +// CONCRETE +//-------------------------------------------------------------------- +#define CONCRETE_SHARDS 1 +const char *ImpactHurtShards_Concrete_Small_Models[ CONCRETE_SHARDS ] = +{ +"models/props_debris/metal_shard_001.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Concrete_Small[ CONCRETE_SHARDS ]; + +//-------------------------------------------------------------------- +// METAL +//-------------------------------------------------------------------- +#define METAL_SHARDS 6 +const char *ImpactHurtShards_Metal_Small_Models[ METAL_SHARDS ] = +{ +"models/props_debris/metal_shard_001.mdl", +"models/props_debris/metal_shard_002.mdl", +"models/props_debris/metal_shard_003.mdl", +"models/props_debris/metal_shard_004.mdl", +"models/props_debris/metal_shard_005.mdl", +"models/props_debris/metal_shard_006.mdl", +}; +// Model pointers for the above +model_t *ImpactHurtShards_Metal_Small[ METAL_SHARDS ]; + +//----------------------------------------------------------------------------- +// Purpose: Precache all our shards +//----------------------------------------------------------------------------- +void PrecacheImpactShards(void *pUser) +{ + int i; + + // Wood + for ( i = 0; i < WOOD_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Wood_Small_Models[i]; + ImpactHurtShards_Wood_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Foliage + for ( i = 0; i < FOLIAGE_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Foliage_Small_Models[i]; + ImpactHurtShards_Foliage_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Concrete + for ( i = 0; i < CONCRETE_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Concrete_Small_Models[i]; + ImpactHurtShards_Concrete_Small[i] = (model_t *)engine->LoadModel( sFile ); + } + + // Metal + for ( i = 0; i < METAL_SHARDS; i++ ) + { + const char *sFile = ImpactHurtShards_Metal_Small_Models[i]; + ImpactHurtShards_Metal_Small[i] = (model_t *)engine->LoadModel( sFile ); + } +} +PRECACHE_REGISTER_FN(PrecacheImpactShards); + +//----------------------------------------------------------------------------- +// Purpose: Throw out shards from the impact point to show we can hurt the target +//----------------------------------------------------------------------------- +void ImpactCreateHurtShards( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge, bool bBlood ) +{ + // Throw out the effect if any of these are true + if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) + return; + + float flShardSpread = 0.5; + + Vector vecSpawnOrigin = vecOrigin; + + int iNumGibs = random->RandomInt( 1, 2 ); + for ( int i = 0; i < iNumGibs; i++ ) + { + QAngle vecAngles; + vecAngles[0] = random->RandomFloat(-255, 255); + vecAngles[1] = random->RandomFloat(-255, 255); + vecAngles[2] = random->RandomFloat(-255, 255); + Vector vecForceDir; + float spreadOfs = random->RandomFloat( 3.0f, 4.0f ); + vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flShardSpread*spreadOfs), (flShardSpread*spreadOfs) ); + // Add some extra vertical height + vecForceDir[2] += random->RandomFloat( 0, 5 ); + vecForceDir *= random->RandomFloat( 30.0,60.0 ); + + model_t *pModel = NULL; + int iFlags = ( FTENT_COLLIDEWORLD | FTENT_FADEOUT | FTENT_GRAVITY ); + + // Select the right chunk for the job + switch ( iMaterial ) + { + case CHAR_TEX_WOOD: + iFlags |= FTENT_ROTATE; + pModel = ImpactHurtShards_Wood_Small[ random->RandomInt(0,WOOD_SHARDS-1) ]; + break; + + case CHAR_TEX_FOLIAGE: + pModel = ImpactHurtShards_Foliage_Small[ random->RandomInt(0,FOLIAGE_SHARDS-1) ]; + break; + + case CHAR_TEX_METAL: + case CHAR_TEX_VENT: + case CHAR_TEX_GRATE: + + case CHAR_TEX_CONCRETE: + default: + pModel = ImpactHurtShards_Metal_Small[ random->RandomInt(0,METAL_SHARDS-1) ]; + break; + + case CHAR_TEX_FLESH: + // Spray some blood out + if ( !bBlood ) + return; + + CEffectData data; + data.m_vOrigin = vecOrigin; + data.m_vNormal = tr.plane.normal; + data.m_flScale = 4; + data.m_fFlags = FX_BLOODSPRAY_ALL; + data.m_nEntIndex = tr.m_pEnt ? tr.m_pEnt->entindex() : 0; + DispatchEffect( "tf2blood", data ); + return; + break; + /* + case CHAR_TEX_CONCRETE: + default: + pModel = ImpactHurtShards_Concrete_Small[ random->RandomInt(0,CONCRETE_SHARDS-1) ]; + break; + */ + } + Assert( pModel ); + + // ROBIN: Removed until optimized + return; + + // Throw it out + tempents->SpawnTempModel( pModel, vecSpawnOrigin, vecAngles, vecForceDir, random->RandomFloat(0.5,1.5), iFlags ); + } +} + +//----------------------------------------------------------------------------- +// Purpose: Throw out breakable, vphysics gibs from the surface we hit +//----------------------------------------------------------------------------- +void ImpactCreateHurtGibs( Vector &vecOrigin, trace_t &tr, Vector &shotDir, int iMaterial, bool bLarge ) +{ + // Throw out the effect if any of these are true + if ( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) + return; + + Vector vecSpawnOrigin = vecOrigin - (shotDir * 32); + float flGibSpread = 0.8; + + // Custom TF2 impact effects + if ( iMaterial == CHAR_TEX_FOLIAGE ) + { + int iNumGibs = random->RandomInt( 1, 2 ); + for ( int i = 0; i < iNumGibs; i++ ) + { + AngularImpulse angVel; + angVel.Random( -400.0f, 400.0f ); + Vector vecForceDir; + float spreadOfs = random->RandomFloat( 3.0f, 4.0f ); + vecForceDir[0] = -shotDir[0] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + vecForceDir[1] = -shotDir[1] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + vecForceDir[2] = -shotDir[2] + random->RandomFloat( -(flGibSpread*spreadOfs), (flGibSpread*spreadOfs) ); + // Add some extra vertical height + vecForceDir[2] += 5; + vecForceDir *= random->RandomFloat( 10.0,30.0 ); + + //C_BreakableProp *pProp = new C_BreakableProp; + //pProp->CreateClientsideProp( ImpactHurtGibs_Wood_Small[ random->RandomInt(0,NUM_WOOD_GIBS_SMALL-1) ], vecSpawnOrigin, vecForceDir, angVel ); + } + } + else + { + PerformCustomEffects( vecOrigin, tr, shotDir, iMaterial, 1 ); + } +} |