diff --git a/src/game/shared/tf/tf_gamerules.cpp b/src/game/shared/tf/tf_gamerules.cpp index c3ec6c0d99..c71e96f8db 100644 --- a/src/game/shared/tf/tf_gamerules.cpp +++ b/src/game/shared/tf/tf_gamerules.cpp @@ -5752,6 +5752,8 @@ void CTFRadiusDamageInfo::CalculateFalloff( void ) //----------------------------------------------------------------------------- // Purpose: Attempt to apply the radius damage to the specified entity //----------------------------------------------------------------------------- +ConVar tf_radiusdamage_los_simple( "tf_radiusdamage_los_simple", "0", FCVAR_NONE, "Use simpler line-of-sight checks for radius damage" ); +ConVar tf_radiusdamage_los_debug( "tf_radiusdamage_los_debug", "0", FCVAR_CHEAT ); int CTFRadiusDamageInfo::ApplyToEntity( CBaseEntity *pEntity ) { if ( pEntity == pEntityIgnore || pEntity->m_takedamage == DAMAGE_NO ) @@ -5780,11 +5782,77 @@ int CTFRadiusDamageInfo::ApplyToEntity( CBaseEntity *pEntity ) UTIL_TraceLine( vecSrc, vecSpot, MASK_RADIUS_DAMAGE, &filterSelf, &tr ); } + bool bDebugLoS = tf_radiusdamage_los_debug.GetBool() && ( pEntity->IsPlayer() || tf_radiusdamage_los_debug.GetInt() == 2 ); + + if ( bDebugLoS ) + { + NDebugOverlay::Line( tr.startpos, tr.endpos, 255, 0, 0, true, 3 ); + NDebugOverlay::Line( tr.endpos, vecSpot, 96, 0, 0, true, 3 ); + } + // If we don't trace the whole way to the target, and we didn't hit the target entity, we're blocked if ( tr.fraction != 1.f && tr.m_pEnt != pEntity ) { - // Don't let projectiles block damage - return 0; + if ( tf_radiusdamage_los_simple.GetBool() ) + return 0; + + if ( pEntity == dmgInfo->GetAttacker() ) + return 0; + + if ( tr.startsolid ) + return 0; + + // explosions can get blocked by bits of ground geometry such as stair steps, which is frustrating for players + // so when the initial LoS-check fails, let's try to find a raised position to perform a second LoS-check from + + float flStepHeight = 18.f; + + Vector vecStartPos = tr.endpos; + Vector vecTarget = vecStartPos; + vecTarget.z -= flStepHeight; + + // trace down to find walkable ground + trace_t trStep; + UTIL_TraceLine( vecStartPos, vecTarget, MASK_RADIUS_DAMAGE, &filter, &trStep ); + + if ( bDebugLoS ) + { + NDebugOverlay::Line( trStep.startpos, trStep.endpos, 0, 128, 255, true, 3 ); + } + + if ( trStep.fraction == 1.f || trStep.plane.normal.z < 0.7 ) + // don't splash if we can't find walkable ground + // this stops Soldiers from splashing high-ground targets by shooting at the edge of the ledge from below + return 0; + + if ( trStep.endpos.z > vecSpot.z ) + // this is higher than the target's position + return 0; + + vecStartPos = trStep.endpos; + vecTarget = vecStartPos; + vecTarget.z += flStepHeight; + + // trace up from the floor to simulate step up + UTIL_TraceLine( vecStartPos, vecTarget, MASK_RADIUS_DAMAGE, &filter, &trStep ); + + if ( bDebugLoS ) + { + NDebugOverlay::Line( trStep.startpos, trStep.endpos, 0, 255, 255, true, 3 ); + } + + // check if explosion can see target from this raised position + UTIL_TraceLine( trStep.endpos, vecSpot, MASK_RADIUS_DAMAGE, &filter, &trStep ); + + if ( bDebugLoS ) + { + NDebugOverlay::Line( trStep.startpos, trStep.endpos, 0, 255, 0, true, 3 ); + NDebugOverlay::Line( trStep.endpos, vecSpot, 0, 96, 0, true, 3 ); + } + + if ( trStep.startsolid || trStep.fraction != 1.f && trStep.m_pEnt != pEntity ) + // target is still blocked + return 0; } // Adjust the damage - apply falloff.