Make switches invulnerable to blast_nearby_glass

`blast_nearby_glass` calls `check_effect_blowup`, but ignores the result.
If `check_effect_blowup` executes a blow-up effect, and the blown object
is a switch, the return value will instruct the caller to execute the
associated trigger.  Since `blast_nearby_glass` ignores the return
value, it never executes a trigger.  This was originally masked by a bug
that passed undefined data from `blast_nearby_glass` to
`check_effect_blowup`, which usually confused `check_effect_blowup` into
treating the explosion as not originating from the player.  This
confusion then forced an early return when a switch was hit, effectively
accidentally making switches invulnerable to `blast_nearby_glass`.
Commit f6352e7 fixed the data confusion, allowing `check_effect_blowup`
to recognize that the explosion came from a player's weapon.  However,
it did not add handling for the trigger, so now `blast_nearby_glass` can
destroy the switch without activating the trigger.  This is at the least
annoying, and in some levels may make progress impossible.  There are
two ways to resolve this:

- Fix the logic to always execute the switch when the switch is
  destroyed, whether by direct hit or by `blast_nearby_glass`.
- Restore the quirk that switches are invulnerable to
  `blast_nearby_glass`.

Conveniently, the `force_blowup_flag` is set by `blast_nearby_glass` and
clear for all other callers, so it can be used to recognize that the
caller will not handle the switch.  Use this to implement choice 2.

Even with this change, a direct hit by a missile can still destroy a
switch and activate its trigger, since that is handled through
`collide_weapon_and_wall`.  Thus, players can still use the technique of
using a guided missile to activate an otherwise impossible switch.

Fixes: f6352e7957 ("Pass correct object to check_effect_blowup")
Reported-by: wm4 <https://github.com/dxx-rebirth/dxx-rebirth/issues/419>
This commit is contained in:
Kp 2019-05-11 20:18:29 +00:00
parent 48527630dd
commit f79f6ab1cc

View file

@ -560,23 +560,22 @@ int check_effect_blowup(const d_level_shared_destructible_light_state &LevelShar
#elif defined(DXX_BUILD_DESCENT_II)
auto &Objects = LevelUniqueObjectState.Objects;
auto &vcobjptr = Objects.vcptr;
int trigger_check = 0, is_trigger = 0;
const auto wall_num = seg->shared_segment::sides[side].wall_num;
// If this wall has a trigger and the blower-upper is not the player or the buddy, abort!
trigger_check = !(blower.parent_type == OBJ_PLAYER || effect_parent_is_guidebot(vcobjptr, blower));
// For Multiplayer perform an additional check to see if it's a local-player hit. If a remote player hits, a packet is expected (remote 1) which would be followed by MULTI_TRIGGER to ensure sync with the switch and the actual trigger.
if (Game_mode & GM_MULTI)
trigger_check = (!(blower.parent_type == OBJ_PLAYER && (blower.parent_num == get_local_player().objnum || remote)));
if ( wall_num != wall_none )
auto &Walls = LevelUniqueWallSubsystemState.Walls;
auto &vcwallptr = Walls.vcptr;
const auto is_trigger = wall_num != wall_none && vcwallptr(wall_num)->trigger != trigger_none;
if (is_trigger)
{
auto &Walls = LevelUniqueWallSubsystemState.Walls;
auto &vcwallptr = Walls.vcptr;
if (vcwallptr(wall_num)->trigger != trigger_none)
is_trigger = 1;
if (force_blowup_flag || (
(Game_mode & GM_MULTI)
// If this wall has a trigger and the blower-upper is not the player or the buddy, abort!
// For Multiplayer perform an additional check to see if it's a local-player hit. If a remote player hits, a packet is expected (remote 1) which would be followed by MULTI_TRIGGER to ensure sync with the switch and the actual trigger.
? (!(blower.parent_type == OBJ_PLAYER && (blower.parent_num == get_local_player().objnum || remote)))
: !(blower.parent_type == OBJ_PLAYER || effect_parent_is_guidebot(vcobjptr, blower)))
)
return(0);
}
if (trigger_check && is_trigger)
return(0);
#endif
if ((tm=seg->unique_segment::sides[side].tmap_num2) != 0) {