Halftrack passengers are unusually susceptible to explosive damage from outside the vehicle

Issue #293 resolved
Andrew Theel created an issue

A grenade on the outside of a HT on the ground can easily kill passengers within the HT.

Comments (9)

  1. Matt Hands

    Think I see the problem: projectile's DriverRadiusDamage() function calls damage on vehicle driver & all occupants (VehWepPawn Drivers).

    Explosive projectile's DriverRadiusDamage() does a trace for each actor in blast radius to see if a vehicle is in the way - if so, the actor is protected from damage. But same does not apply to vehicle occupants.

    I'll look into it properly tomorrow.

    RO code, not changed by us, so must be an old bug?

  2. Matt Hands

    Exploding projectiles call HurtRadius(), which handles the blast damage. It iterates for visible, colliding actor within the blast radius & causes them damage, which is reduced pro-rata based on distance from explosion origin. But for each hit actor, it does a trace to see if a vehicle is in the way - if it is, no damage is done.

    Our DHPawns in vehicles don't have collision, so they aren't directly affected by HurtRadius(). We have kept their whip attachment actors active when they are in an exposed position, but although the whip actor does have collision, the DHPawn in a vehicle does not.

    To deal with this, if HurtRadius() hits a vehicle it calls DriverRadiusDamage() on the vehicle. That causes damage to any vehicle occupant who is in an exposed position, as the function is passed on to each VWPawn and its 'Driver'. But damage is only done if the Driver does not have collision; the rationale being that if the player pawn has collision, HurtRadius() will hit him & do damage anyway. DRDamage() is specifically to handle damage to vehicle occupants that do not collide.

    Options:

    1. What I want to do is keep DHPawns collidable when they are in a vehicle, at least in an exposed position (it would simply be linked to toggling the whip attachment on/off). That way HurtRadius() will work effectively, with a vehicle collision box blocking damage to a player inside, and with DRDamage() neutralised. I tried it quickly and believe it works, but keeping collision on the occupant has some screwball effects on a couple of infantry vehicles, which get flipped or worse (Bren carrier being the most screwball !). I'll see if I can solve that, as I think this would be the perfect solution, with wider benefits.

    2. Have DRDamage() mimic the vehicle trace between explosion point and Driver, blocking damage if trace hits a vehicle in the way. DRDamage() has the necessary info, so I think this will work, with no more overhead than HurtRadius(). I suspect this is the most likely solution.

    3. If all else fails, neutralise DRDamage(). Would leave vehicle occupants immune to explosives, but better than them all being blown up by a grenade outside an APC. DOunt it will come to that.

    Makes me think - should all vehicles block blast damage, or better to limit it to those with armour, so avoid the damage block it for soft-skinned DHWheeledVehicles?

  3. Matt Hands

    Some extra info/explanation/background to this problem:

    It doesn't affect vehicles in RO - but only because RO sets DriverDamageMultiplier to zero for all vehicle passengers, meaning you can't damage them in any way with anything. So clearly not a solution. If RO didn't zero passenger damage, this underlying problem in DriverRadiusDamage() would manifest itself.

    It is there in DH 5.1 & is not a new bug (tested that). It shows up solely because DH correctly allows damage to passengers.

    Likely solution as above, probably option 2. And I'm going to try using a HitPointTrace, for more accurate locational damage to a hit player.

  4. Matt Hands

    Have it working on my PC using option 2, although didn't turn out to be as simple (when does it?). But better functionality and the cod solution ends up being pretty simple, even if the process of getting there was a pig. Complicating factors:

    • Calling Trace functions related to projectiles on other actors (e.g. the vehicle) can also give incorrect results, as any Trace uses the collision properties of the other actor and not the projectile collision.
    • Native RO function HitPointTrace(), which gives unreliable results that can have serious consequences.
    • Trace returns an actor 'in the way' that collides but does not block, including the exposed player's bullet whip attachment.

    But can work around all these. Just finalising the best, cleanest method and should get it committed tomorrow (Sat) morning.

  5. Matt Hands

    Fixed in commit 78bc6be.

    Problem is fundamental to UT2004 & new/re-worked functionality is added to handle blast damage to vehicle occupants.

    Explosive projectiles call HurtRadius() in the proj calss, which does a foreach iteration to find all VisibleCollidingActors within blast radius. Damage is reduced pro-rata based on distance from explosion. But vehicle occupants don't have collision - it gets turned off when entering - so HurtRadius() doesn't find them. To handle that, it calls DriverRadiusDamage() on any Vehicle within the blast radius.

    DriverRadiusDamage() damages the vehicle's driver or occupant of a VWPawn, if they are exposed & their location is within the blast radius. Actually, it only does that if the occupant has no collision, otherwise HurtRadius() will get them anyway, but occupants don't have collision. This system works, except it takes account of the occupant possibly being shielded from the blast by parts of the vehicle.

    To fix this, when HurtRadius() finds a Vehicle, it now calls CheckVehicleOccupantsRadiusDamage() in the proj class, instead of DriverRadiusDamage() on the Vehicle. DriverRadiusDamage() is deprecated.

    CheckVehicleOccupantsRadiusDamage() checks for any exposed occupants and calls VehicleOccupantRadiusDamage() for each one. VehicleOccupantRadiusDamage() is where the business gets done. It does a foreach TraceActors iteration, from the blast centre to the occupant's head (specifically a point 3 inches below the top of their head).

    Any Trace won't actually hit the occupant pawn, as it has no collision. But this 'trace' is in reverse - it's checking whether anything is in the way, so a negative result means positive damage. The trace continues until it hits a blocking actor, which usually means part of the Vehicle, in which case no damage is done to the occupant. Or it continues to the end of the trace, meaning nothing blocked it so the occupant is damaged.

    A foreach iteration may raise eyebrows, but TraceActors is quick, like any trace, especially as it's a very short trace, which is abandoned if it hits any blocker. A normal Trace would be stopped by the player's bullet whit attachment, which has collision but doesn't block. It's possible to look for such actors in the bTrace result and then re-Trace from the new HitLocation, but that can go on and it gets messy.

    And a big advantage of doing the 'Trace' in the proj class, is that any Trace function uses the collision properties of the actor being Traced from. In this case it uses the projectile collision properties, specifically including bUseCollisionStaticMesh, so it checks collision accurately against a vehicle's collision static mesh.

    Where as if the trace was done in the vehicle class, say in DriverRadiusDamage(), it would use the vehicle's collision props, meaning not using bUseCollisionStaticMesh & inaccurate collision vs the blocky vehicle collision box. That is a significant flaw in a number of areas, although I will shortly commit a fix for the most obvious.

  6. Matt Hands

    Above fix/functionality added to all explosive classes used by projectiles in DH: cannon shell, mortar shell, arty shell & throwable explosive (grenades, satchel).

    Includes UpdateInstigator(), standardised to what I think is the best/correct format. Applied same to DHBullet.

    HurtRadius() & associated GetClosestMortarTargetController() function moved from mortar HE projectile to parent DHMortarProjectile. Better to have such functionality in the highest level class to guarantee maximum inheritance. For example, if we added some radius damage to WP smoke shells, it would inherit the correct code from DHMortarProjectile.

    In the mortar class I have also deprecated the DamageInstigator variable, which was doing the same job as InstigatorController. The problem was that ROBallisticProjectile removes the PostBeginPlay() code that sets InstigatorController, probably just by mistake by not calling the super. I've now added back, as in bullet & cannon shell, so DamageInstigator is no longer required.

  7. Matt Hands

    Forgot to say: I chose to trace to near the top of the player's head because we need to pick one point and the head seems to work pretty well & logically. If his head is exposed then he can assume he's going to take damage. While in most vehicles, like halftracks, if the head is shielded from the blast point, the player's body usually will be too.

    Unlike projectiles, which obviously have a single trace line along the projectile's path, with a blast we need to choose one trace line, which is always going to be arbitrary. But the head seems good. I suppose to be truly realistic, we'd trace to multiple body parts & then calculate what proportion of the body is exposed and either scale damage accordingly or apply a random damage chance based on exposure. But that would be OTT and take up too much resource.

    Using a loaded M3 halftrack as an example, the effect of tracing the top of the head is like this:

    • Grenade dropped near the vehicle - won't damage anyone, as they are shielded by the side/rear armoured panels
    • Grenade dropped further away from the vehicle - may cause some damage to players on the blast side (scaled down by distance), but no damage to players on the other side (they are shielded).
    • Grenade tossed into the vehicle - wipeout !
    • Grenade air-bursting above the vehicle - also wipeout, as everyone is exposed.
  8. Log in to comment