From f79f6ab1ccfb0fec841a13c3b2b2a65d087c686e Mon Sep 17 00:00:00 2001 From: Kp Date: Sat, 11 May 2019 20:18:29 +0000 Subject: [PATCH] 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: f6352e7957368975c56e74d2010fc2beb1cd6826 ("Pass correct object to check_effect_blowup") Reported-by: wm4 --- similar/main/collide.cpp | 25 ++++++++++++------------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/similar/main/collide.cpp b/similar/main/collide.cpp index 94cd66f3c..a7d8b6370 100644 --- a/similar/main/collide.cpp +++ b/similar/main/collide.cpp @@ -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) {