ValveSoftware / halflife

Half-Life 1 engine based games
Other
3.74k stars 629 forks source link

Explosions can go through walls in certain cases #3244

Open SamVanheer opened 2 years ago

SamVanheer commented 2 years ago

Explosions causes by entities that derive from the CGrenade class can sometimes go through walls.

This happens because of faulty logic used to pull explosions out of walls: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/ggrenade.cpp#L60-L64

The problem with this is that the new origin can be outside the range defined by the original entity origin and pTrace->vecEndPos. The higher the damage is, and the closer the trace end position is to the origin, the higher the chance that the explosion will actually end up inside the opposite wall. Explosions that occur outside of a map will penetrate through walls and can kill players that are otherwise shielded by walls. If the wall is thin enough the explosion can kill players on the other side instead.

A good example of this is the ladders on the multiplayer map gasworks. Placing a trip mine in one of the ladder shaft and then detonating it will kill players that are shielded by the walls and ceiling. Another common occurrence is hand grenades exploding in vents. Players can end up killing themselves if they do this because the vent brushes won't always block the explosion.

To fix this the damage value shouldn't be used in the calculation:

// Pull out of the wall a bit
if (pTrace->flFraction != 1.0)
{
    pev->origin = pTrace->vecEndPos + (pTrace->vecPlaneNormal * 0.6);
}

The explosion will be pulled out of the wall by 0.6 units in the direction opposite of the surface that was hit by the trace. Unless the map geometry has less than a unit width this shouldn't result in the explosion piercing through any other surfaces.

Source already has the fix for this, you can see it here: https://github.com/ValveSoftware/source-sdk-2013/blob/0d8dceea4310fde5706b3ce1c70609d72a38efdf/mp/src/game/shared/basegrenade_shared.cpp#L123-L127

Unfortunately fixing this issue introduces a new problem: RadiusDamage moves the explosion up by one unit to pull the explosion out of the floor: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/combat.cpp#L1052

Explosions that hit the underside of a brush will be pushed into that brush causing the explosion to start in a solid. The trace will pierce through the brush and hit whatever is on the other side and will deal full damage because of this: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/combat.cpp#L1080-L1085

To fix this explosions caused by the CGrenade class or derived classes need to counteract this vertical adjustment here: https://github.com/ValveSoftware/halflife/blob/c7240b965743a53a29491dd49320c88eecf6257b/dlls/ggrenade.cpp#L95

By adding this code:

// Counteract the + 1 in RadiusDamage.
Vector origin = pev->origin;
origin.z -= 1;

RadiusDamage(origin, pev, pevOwner, pev->dmg, CLASS_NONE, bitsDamageType);

CGrenade::Explode already pulls the explosion origin out of the surface it hits so the additional upwards movement isn't necessary.

This affects the following entities in Half-Life:

The same logic is also used in other GoldSource engine games including Counter-Strike. Explosions going through walls is a known occurrence in Counter-Strike and may be considered a valid tactic, so i'm not sure if it should be fixed there.

CS-PRO1 commented 2 years ago

Yeah it's better to keep the wall-nade damage untouched in CS/CZ because it's considered more as a quirk or a feature that's unique to the goldsrc CS games, just like extensive wallbanging..

Maxi605 commented 2 years ago

Yeah it's better to keep the wall-nade damage untouched in CS/CZ because it's considered more as a quirk or a feature that's unique to the goldsrc CS games, just like extensive wallbanging..

I believe a cvar would be perfect for this with the damage active by default since i don't like the idea to keep bugs around like this.

SamVanheer commented 1 year ago

Updated the proposed solution with new information about a bug that this fix uncovers along with a solution for that bug.

wootguy commented 5 days ago

The reason pev->dmg is used at all, I think, is to make the explosion sprite look nice. Sprite size scales with damage. If the explosion is created without an offset then the sprite clips through the floor. I might do another trace instead of getting rid of pev->dmg entirely. Anyway, thanks for explaining this glitch.