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.
453 lines
16 KiB
453 lines
16 KiB
//========= 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 ); |
|
} |
|
}
|
|
|