From 24be009e96a1d207cf7fbb73d2bb60aa3dc0d2bb Mon Sep 17 00:00:00 2001 From: zxaber <37497534+zxaber@users.noreply.github.com> Date: Mon, 28 Jun 2021 07:03:22 -0700 Subject: [PATCH] Jaunting no longer allows you to end up inside a wall (#59520) Jaunting now keeps track of the last five non-blocked tiles you moved across while in the jaunt. Upon exit, it will attempt to deposit you into the last unblocked tile. Should it run out of tiles to try, you will be returned to your starting location. As such, jaunting mobs can no longer end up inside walls or dense objects. Tables, and anything else with the climbable element, are still allowed. Added support to /turf/proc/is_blocked_turf() to allow ignoring climbable atoms. Added the TRAIT_CLIMBABLE trait, applied by the climbable element, to accomplish the above. --- code/__DEFINES/traits.dm | 3 ++ code/datums/elements/climbable.dm | 2 ++ code/game/turfs/turf.dm | 14 ++++++++ .../spells/spell_types/ethereal_jaunt.dm | 36 +++++++++++++++++++ 4 files changed, 55 insertions(+) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index c1dcfb07e85..3b2cc98097d 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -380,6 +380,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai */ #define TRAIT_AREA_SENSITIVE "area-sensitive" +/// Climbable trait, given and taken by the climbable element when added or removed. Exists to be easily checked via HAS_TRAIT(). +#define TRAIT_CLIMBABLE "trait_climbable" + ///Used for managing KEEP_TOGETHER in [/atom/var/appearance_flags] #define TRAIT_KEEP_TOGETHER "keep-together" diff --git a/code/datums/elements/climbable.dm b/code/datums/elements/climbable.dm index 8084247669a..1a036412b17 100644 --- a/code/datums/elements/climbable.dm +++ b/code/datums/elements/climbable.dm @@ -22,9 +22,11 @@ RegisterSignal(target, COMSIG_PARENT_EXAMINE, .proc/on_examine) RegisterSignal(target, COMSIG_MOUSEDROPPED_ONTO, .proc/mousedrop_receive) RegisterSignal(target, COMSIG_ATOM_BUMPED, .proc/try_speedrun) + ADD_TRAIT(target, TRAIT_CLIMBABLE, src) /datum/element/climbable/Detach(datum/target) UnregisterSignal(target, list(COMSIG_ATOM_ATTACK_HAND, COMSIG_PARENT_EXAMINE, COMSIG_MOUSEDROPPED_ONTO, COMSIG_ATOM_BUMPED)) + REMOVE_TRAIT(target, TRAIT_CLIMBABLE, src) return ..() /datum/element/climbable/proc/on_examine(atom/source, mob/user, list/examine_texts) diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm index 7c045fbfa86..a0e20a787eb 100755 --- a/code/game/turfs/turf.dm +++ b/code/game/turfs/turf.dm @@ -212,6 +212,20 @@ GLOBAL_LIST_EMPTY(station_turfs) return TRUE return FALSE +/** + * Checks whether the specified turf is blocked by something dense inside it, but ignores anything with the climbable trait + * + * Works similar to is_blocked_turf(), but ignores climbables and has less options. Primarily added for jaunting checks + */ +/turf/proc/is_blocked_turf_ignore_climbable() + if(density) + return TRUE + + for(var/atom/movable/atom_content as anything in contents) + if(atom_content.density && !(atom_content.flags_1 & ON_BORDER_1) && !HAS_TRAIT(atom_content, TRAIT_CLIMBABLE)) + return TRUE + return FALSE + //zPassIn doesn't necessarily pass an atom! //direction is direction of travel of air /turf/proc/zPassIn(atom/movable/A, direction, turf/source) diff --git a/code/modules/spells/spell_types/ethereal_jaunt.dm b/code/modules/spells/spell_types/ethereal_jaunt.dm index e68b64a1a5d..ca1a1e6997b 100644 --- a/code/modules/spells/spell_types/ethereal_jaunt.dm +++ b/code/modules/spells/spell_types/ethereal_jaunt.dm @@ -22,6 +22,8 @@ var/jaunt_in_type = /obj/effect/temp_visual/wizard /// Visual for exiting the jaunt var/jaunt_out_type = /obj/effect/temp_visual/wizard/out + /// List of valid exit points + var/list/exit_point_list /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/cast_check(skipcharge = 0,mob/user = usr) . = ..() @@ -51,11 +53,28 @@ ADD_TRAIT(target, TRAIT_IMMOBILIZED, type) sleep(jaunt_out_time) REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, type) + var/turf/exit_point = get_turf(holder) //Hopefully this gets updated, otherwise this is our fallback + LAZYINITLIST(exit_point_list) + RegisterSignal(holder, COMSIG_MOVABLE_MOVED, .proc/update_exit_point, target) sleep(jaunt_duration) + UnregisterSignal(holder, COMSIG_MOVABLE_MOVED) if(target.loc != holder) //mob warped out of the warp qdel(holder) return + + var/found_exit = FALSE + for(var/turf/possible_exit as anything in exit_point_list) + if(possible_exit.is_blocked_turf_ignore_climbable()) + continue + exit_point = possible_exit + found_exit = TRUE + break + if(!found_exit) + to_chat(target, "Unable to find an unobstructed space, you find yourself ripped back to where you started.") + exit_point_list.Cut() + holder.forceMove(exit_point) + mobloc = get_turf(target.loc) jaunt_steam(mobloc) ADD_TRAIT(target, TRAIT_IMMOBILIZED, type) @@ -75,6 +94,23 @@ break REMOVE_TRAIT(target, TRAIT_IMMOBILIZED, type) +/** + * Updates the exit point of the jaunt + * + * Called when the jaunting mob holder moves, this updates the backup exit-jaunt + * location, in case the jaunt ends with the mob still in a wall. Five + * spots are kept in the list, in case the last few changed since we passed + * by (doors closing, engineers building walls, etc) + */ +/obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/update_exit_point(mob/living/target) + SIGNAL_HANDLER + var/turf/location = get_turf(target) + if(location.is_blocked_turf_ignore_climbable()) + return + exit_point_list.Insert(1, location) + if(length(exit_point_list) >= 5) + exit_point_list.Cut(5) + /obj/effect/proc_holder/spell/targeted/ethereal_jaunt/proc/jaunt_steam(mobloc) var/datum/effect_system/steam_spread/steam = new /datum/effect_system/steam_spread() steam.set_up(10, 0, mobloc)