From 2c682cf83e791cfa0a003a284b91d8dff453e6bb Mon Sep 17 00:00:00 2001 From: SkyratBot <59378654+SkyratBot@users.noreply.github.com> Date: Sat, 18 Sep 2021 22:45:42 +0200 Subject: [PATCH] [MIRROR] Things that love the station may no longer leave the station, even when Dr. Anomaly says they should. (#8254) * Things that love the station may no longer leave the station, even when Dr. Anomaly says they should. (#61335) Bluespace anomalies detonating Move() things. When something is Move()d, none of the logic in forceMove() or doMove() is called, and thus stationloving things can't tell when they've left the z-level (since that's where the logic for it is). There are a number of approaches I could have taken: Refactoring anomalies to use different movement code. Refactoring Movement code to send more signals in various scenarios. Refactoring the stationloving component. I settled on two steps. First, refactoring the component to bring it up to modern code standards. Second, moving the logic for COMSIG_MOVABLE_Z_CHANGED to Moved() so the signal always fires regardless of if Move() or forceMove() or doMove() is used, with an optional var for whether the z-change is communicated to contents. This means the ore box was changed to actually send the signal instead of just returning with no parent call or signal sent. Stationloving ore boxes when? stationloving procs no longer call SIGNAL_HANDLERs directly. Var names are now more descriptive. Things are renamed and documented. At least for the parts of the code I know. Probably some other code cleanups. * Things that love the station may no longer leave the station, even when Dr. Anomaly says they should. Co-authored-by: Timberpoes --- code/__DEFINES/dcs/signals.dm | 2 +- code/datums/components/stationloving.dm | 122 +++++++++++------- code/game/atoms_movable.dm | 32 +++-- code/game/machinery/navbeacon.dm | 10 +- .../antagonists/blob/structures/core.dm | 4 +- code/modules/lighting/emissive_blocker.dm | 2 +- code/modules/mining/satchel_ore_boxdm.dm | 5 +- code/modules/mob/dead/dead.dm | 6 +- code/modules/mob/living/living.dm | 4 +- .../mob/living/simple_animal/simple_animal.dm | 4 +- code/modules/shuttle/on_move.dm | 3 +- 11 files changed, 114 insertions(+), 80 deletions(-) diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index 4b79590b39d..998ba9ed80a 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -467,7 +467,7 @@ #define COMSIG_MOVABLE_POST_THROW "movable_post_throw" ///from base of datum/thrownthing/finalize(): (obj/thrown_object, datum/thrownthing) used for when a throw is finished #define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed" -///from base of atom/movable/onTransitZ(): (old_z, new_z) +///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf) #define COMSIG_MOVABLE_Z_CHANGED "movable_ztransit" ///called when the movable is placed in an unaccessible area, used for stationloving: () #define COMSIG_MOVABLE_SECLUDED_LOCATION "movable_secluded" diff --git a/code/datums/components/stationloving.dm b/code/datums/components/stationloving.dm index 6c431ff237e..a0080254fa4 100644 --- a/code/datums/components/stationloving.dm +++ b/code/datums/components/stationloving.dm @@ -1,57 +1,67 @@ +/// Teleports the movable atom back to a safe turf on the station if it leaves the z-level or becomes inaccessible. /datum/component/stationloving dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// If TRUE, notifies admins when parent is teleported back to the station. var/inform_admins = FALSE var/disallow_soul_imbue = TRUE - var/allow_death = FALSE + /// If FALSE, prevents parent from being qdel'd unless it's a force = TRUE qdel. + var/allow_item_destruction = FALSE -/datum/component/stationloving/Initialize(inform_admins = FALSE, allow_death = FALSE) +/datum/component/stationloving/Initialize(inform_admins = FALSE, allow_item_destruction = FALSE) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE - RegisterSignal(parent, list(COMSIG_MOVABLE_Z_CHANGED), .proc/check_in_bounds) - RegisterSignal(parent, list(COMSIG_MOVABLE_SECLUDED_LOCATION), .proc/relocate) - RegisterSignal(parent, list(COMSIG_PARENT_PREQDELETED), .proc/check_deletion) - RegisterSignal(parent, list(COMSIG_ITEM_IMBUE_SOUL), .proc/check_soul_imbue) - RegisterSignal(parent, list(COMSIG_ITEM_MARK_RETRIEVAL), .proc/check_mark_retrieval) + RegisterSignal(parent, COMSIG_MOVABLE_Z_CHANGED, .proc/on_parent_z_change) + RegisterSignal(parent, COMSIG_MOVABLE_SECLUDED_LOCATION, .proc/on_parent_unreachable) + RegisterSignal(parent, COMSIG_PARENT_PREQDELETED, .proc/on_parent_pre_qdeleted) + RegisterSignal(parent, COMSIG_ITEM_IMBUE_SOUL, .proc/check_soul_imbue) + RegisterSignal(parent, COMSIG_ITEM_MARK_RETRIEVAL, .proc/check_mark_retrieval) src.inform_admins = inform_admins - src.allow_death = allow_death - check_in_bounds() // Just in case something is being created outside of station/centcom + src.allow_item_destruction = allow_item_destruction + + // Just in case something is being created outside of station/centcom + if(!destination_in_bounds(parent)) + relocate() /datum/component/stationloving/InheritComponent(datum/component/stationloving/newc, original, inform_admins, allow_death) if (original) if (newc) inform_admins = newc.inform_admins - allow_death = newc.allow_death + allow_death = newc.allow_item_destruction else inform_admins = inform_admins +/// Teleports parent to a safe turf on the station z-level. /datum/component/stationloving/proc/relocate() - SIGNAL_HANDLER + var/target_turf = find_safe_turf() - var/targetturf = find_safe_turf() - if(!targetturf) + if(!target_turf) if(GLOB.blobstart.len > 0) - targetturf = get_turf(pick(GLOB.blobstart)) + target_turf = get_turf(pick(GLOB.blobstart)) else CRASH("Unable to find a blobstart landmark") - var/atom/movable/AM = parent - playsound(AM, 'sound/machines/synth_no.ogg', 5, TRUE) //hey dumbass, you failed at your MOST IMPORTANT JOB, maybe you should check your chat log to see what could have caused that strange buzzing noise - AM.forceMove(targetturf) + var/atom/movable/movable_parent = parent + playsound(movable_parent, 'sound/machines/synth_no.ogg', 5, TRUE) + movable_parent.forceMove(target_turf) to_chat(get(parent, /mob), span_danger("You can't help but feel that you just lost something back there...")) - // move the disc, so ghosts remain orbiting it even if it's "destroyed" - return targetturf -/datum/component/stationloving/proc/check_in_bounds() + return target_turf + +/// Signal handler when the parent has changed z-levels. +/// Checks to make sure it's a valid destination, if it's not then it relacates the parent instead. +/datum/component/stationloving/proc/on_parent_z_change(datum/source, turf/old_turf, turf/new_turf) SIGNAL_HANDLER - if(in_bounds()) + if(destination_in_bounds(parent)) return - else - var/turf/currentturf = get_turf(src) - var/turf/targetturf = relocate() - log_game("[parent] has been moved out of bounds in [loc_name(currentturf)]. Moving it to [loc_name(targetturf)].") - if(inform_admins) - message_admins("[parent] has been moved out of bounds in [ADMIN_VERBOSEJMP(currentturf)]. Moving it to [ADMIN_VERBOSEJMP(targetturf)].") + + var/turf/current_turf = get_turf(parent) + var/turf/new_destination = relocate() + log_game("[parent] attempted to be moved out of bounds from [loc_name(old_turf)] to [loc_name(current_turf)]. Moving it to [loc_name(new_destination)].") + if(inform_admins) + message_admins("[parent] attempted to be moved out of bounds from [ADMIN_VERBOSEJMP(old_turf)] to [ADMIN_VERBOSEJMP(current_turf)]. Moving it to [ADMIN_VERBOSEJMP(new_destination)].") + + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE /datum/component/stationloving/proc/check_soul_imbue() SIGNAL_HANDLER @@ -63,40 +73,54 @@ return COMPONENT_BLOCK_MARK_RETRIEVAL -/datum/component/stationloving/proc/in_bounds() +/// Checks whether a given destination is within bounds. Returns TRUE if it is, FALSE if it isn't. +/datum/component/stationloving/proc/destination_in_bounds(atom/destination) var/static/list/allowed_shuttles = typecacheof(list(/area/shuttle/syndicate, /area/shuttle/escape, /area/shuttle/pod_1, /area/shuttle/pod_2, /area/shuttle/pod_3, /area/shuttle/pod_4)) var/static/list/disallowed_centcom_areas = typecacheof(list(/area/abductor_ship, /area/awaymission/errorroom)) - var/turf/T = get_turf(parent) - if (!T) + var/turf/destination_turf = get_turf(destination) + if (!destination_turf) return FALSE - var/area/A = T.loc - if (is_station_level(T.z)) + var/area/destination_area = destination_turf.loc + if (is_station_level(destination_turf.z)) return TRUE - if (is_centcom_level(T.z)) - if (is_type_in_typecache(A, disallowed_centcom_areas)) + if (is_centcom_level(destination_turf.z)) + if (is_type_in_typecache(destination_area, disallowed_centcom_areas)) return FALSE return TRUE - if (is_reserved_level(T.z)) - if (is_type_in_typecache(A, allowed_shuttles)) + if (is_reserved_level(destination.z)) + if (is_type_in_typecache(destination_area, allowed_shuttles)) return TRUE return FALSE -/datum/component/stationloving/proc/check_deletion(datum/source, force) // TRUE = interrupt deletion, FALSE = proceed with deletion - +/// Signal handler for before the parent is qdel'd. Can prevent the parent from being deleted where allow_item_destruction is FALSE and force is FALSE. +/datum/component/stationloving/proc/on_parent_pre_qdeleted(datum/source, force) SIGNAL_HANDLER - - var/turf/T = get_turf(parent) + var/turf/current_turf = get_turf(parent) if(inform_admins && force) - message_admins("[parent] has been !!force deleted!! in [ADMIN_VERBOSEJMP(T)].") - log_game("[parent] has been !!force deleted!! in [loc_name(T)].") + message_admins("[parent] has been !!force deleted!! in [ADMIN_VERBOSEJMP(current_turf)].") + log_game("[parent] has been !!force deleted!! in [loc_name(current_turf)].") - if(!force && !allow_death) - var/turf/targetturf = relocate() - log_game("[parent] has been destroyed in [loc_name(T)]. Moving it to [loc_name(targetturf)].") - if(inform_admins) - message_admins("[parent] has been destroyed in [ADMIN_VERBOSEJMP(T)]. Moving it to [ADMIN_VERBOSEJMP(targetturf)].") - return TRUE - return FALSE + if(force || allow_item_destruction) + UnregisterSignal(parent, list(COMSIG_MOVABLE_PRE_MOVE, COMSIG_MOVABLE_SECLUDED_LOCATION)) + return FALSE + + var/turf/new_turf = relocate() + log_game("[parent] has been destroyed in [loc_name(current_turf)]. Preventing destruction and moving it to [loc_name(new_turf)].") + if(inform_admins) + message_admins("[parent] has been destroyed in [ADMIN_VERBOSEJMP(current_turf)]. Preventing destruction and moving it to [ADMIN_VERBOSEJMP(new_turf)].") + return TRUE + +/// Signal handler for when the parent enters an unreachable location. Always relocates the parent. +/datum/component/stationloving/proc/on_parent_unreachable() + SIGNAL_HANDLER + + var/turf/current_turf = get_turf(parent) + var/turf/new_turf = relocate() + log_game("[parent] has been moved to unreachable location in [loc_name(current_turf)]. Moving it to [loc_name(new_turf)].") + if(inform_admins) + message_admins("[parent] has been moved to unreachable location in [ADMIN_VERBOSEJMP(current_turf)]. Moving it to [ADMIN_VERBOSEJMP(new_turf)].") + + return COMPONENT_MOVABLE_BLOCK_PRE_MOVE diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e205bd7a026..de028649494 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -582,6 +582,12 @@ SEND_SIGNAL(src, COMSIG_MOVABLE_MOVED, old_loc, movement_dir, forced, old_locs) + var/turf/old_turf = get_turf(old_loc) + var/turf/new_turf = get_turf(src) + + if (old_turf?.z != new_turf?.z) + on_changed_z_level(old_turf, new_turf) + return TRUE @@ -733,12 +739,6 @@ oldloc.Exited(src, movement_dir) if(old_area && old_area != destarea) old_area.Exited(src, movement_dir) - var/turf/oldturf = get_turf(oldloc) - var/turf/destturf = get_turf(destination) - var/old_z = (oldturf ? oldturf.z : null) - var/dest_z = (destturf ? destturf.z : null) - if (old_z != dest_z) - onTransitZ(old_z, dest_z) destination.Entered(src, oldloc) if(destarea && old_area != destarea) destarea.Entered(src, old_area) @@ -757,11 +757,21 @@ Moved(oldloc, NONE, TRUE) -/atom/movable/proc/onTransitZ(old_z,new_z) - SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED, old_z, new_z) - for (var/item in src) // Notify contents of Z-transition. This can be overridden IF we know the items contents do not care. - var/atom/movable/AM = item - AM.onTransitZ(old_z,new_z) +/** + * Called when a movable changes z-levels. + * + * Arguments: + * * old_z - The previous z-level they were on before. + * * notify_contents - Whether or not to notify the movable's contents that their z-level has changed. + */ +/atom/movable/proc/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = TRUE) + SEND_SIGNAL(src, COMSIG_MOVABLE_Z_CHANGED, old_turf, new_turf) + + if(!notify_contents) + return + + for (var/atom/movable/content as anything in src) // Notify contents of Z-transition. + content.on_changed_z_level(old_turf, new_turf) /** * Called whenever an object moves and by mobs when they attempt to move themselves through space diff --git a/code/game/machinery/navbeacon.dm b/code/game/machinery/navbeacon.dm index 2e416b9515b..ec8fd2f51fa 100644 --- a/code/game/machinery/navbeacon.dm +++ b/code/game/machinery/navbeacon.dm @@ -44,11 +44,11 @@ glob_lists_deregister() return ..() -/obj/machinery/navbeacon/onTransitZ(old_z, new_z) - if (GLOB.navbeacons["[old_z]"]) - GLOB.navbeacons["[old_z]"] -= src - if (GLOB.navbeacons["[new_z]"]) - GLOB.navbeacons["[new_z]"] += src +/obj/machinery/navbeacon/on_changed_z_level(turf/old_turf, turf/new_turf) + if (GLOB.navbeacons["[old_turf?.z]"]) + GLOB.navbeacons["[old_turf?.z]"] -= src + if (GLOB.navbeacons["[new_turf?.z]"]) + GLOB.navbeacons["[new_turf?.z]"] += src ..() // set the transponder codes assoc list from codes_txt diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm index 43da78f64a1..d49ec0220cf 100644 --- a/code/modules/antagonists/blob/structures/core.dm +++ b/code/modules/antagonists/blob/structures/core.dm @@ -79,7 +79,7 @@ . = ..() AddComponent(/datum/component/stationloving, FALSE, TRUE) -/obj/structure/blob/special/core/onTransitZ(old_z, new_z) - if(overmind && is_station_level(new_z)) +/obj/structure/blob/special/core/on_changed_z_level(turf/old_turf, turf/new_turf) + if(overmind && is_station_level(new_turf?.z)) overmind.forceMove(get_turf(src)) return ..() diff --git a/code/modules/lighting/emissive_blocker.dm b/code/modules/lighting/emissive_blocker.dm index 9e3decae0e1..1fb2dba0e1f 100644 --- a/code/modules/lighting/emissive_blocker.dm +++ b/code/modules/lighting/emissive_blocker.dm @@ -37,7 +37,7 @@ /atom/movable/emissive_blocker/blob_act() return -/atom/movable/emissive_blocker/onTransitZ() +/atom/movable/emissive_blocker/on_changed_z_level(turf/old_turf, turf/new_turf) return //Prevents people from moving these after creation, because they shouldn't be. diff --git a/code/modules/mining/satchel_ore_boxdm.dm b/code/modules/mining/satchel_ore_boxdm.dm index 591af53e750..8ae5943f066 100644 --- a/code/modules/mining/satchel_ore_boxdm.dm +++ b/code/modules/mining/satchel_ore_boxdm.dm @@ -98,5 +98,6 @@ dump_box_contents() qdel(src) -/obj/structure/ore_box/onTransitZ() - return +/// Special override for notify_contents = FALSE. +/obj/structure/ore_box/on_changed_z_level(turf/old_turf, turf/new_turf, notify_contents = FALSE) + return ..() diff --git a/code/modules/mob/dead/dead.dm b/code/modules/mob/dead/dead.dm index 84a500ef476..1529258bc0b 100644 --- a/code/modules/mob/dead/dead.dm +++ b/code/modules/mob/dead/dead.dm @@ -30,7 +30,7 @@ INITIALIZE_IMMEDIATE(/mob/dead) var/turf/old_turf = get_turf(src) var/turf/new_turf = get_turf(destination) if (old_turf?.z != new_turf?.z) - onTransitZ(old_turf?.z, new_turf?.z) + on_changed_z_level(old_turf, new_turf) return ..() /mob/dead/get_status_tab_items() @@ -119,6 +119,6 @@ INITIALIZE_IMMEDIATE(/mob/dead) update_z(null) return ..() -/mob/dead/onTransitZ(old_z,new_z) +/mob/dead/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - update_z(new_z) + update_z(new_turf?.z) diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm index 3667338d48f..d194cc26014 100644 --- a/code/modules/mob/living/living.dm +++ b/code/modules/mob/living/living.dm @@ -1596,9 +1596,9 @@ else registered_z = null -/mob/living/onTransitZ(old_z,new_z) +/mob/living/on_changed_z_level(turf/old_turf, turf/new_turf) ..() - update_z(new_z) + update_z(new_turf?.z) /mob/living/MouseDrop_T(atom/dropping, atom/user) var/mob/living/U = user diff --git a/code/modules/mob/living/simple_animal/simple_animal.dm b/code/modules/mob/living/simple_animal/simple_animal.dm index 20fa0be40b5..9ae075ec30c 100644 --- a/code/modules/mob/living/simple_animal/simple_animal.dm +++ b/code/modules/mob/living/simple_animal/simple_animal.dm @@ -662,10 +662,10 @@ if (pulledby || shouldwakeup) toggle_ai(AI_ON) -/mob/living/simple_animal/onTransitZ(old_z, new_z) +/mob/living/simple_animal/on_changed_z_level(turf/old_turf, turf/new_turf) ..() if (AIStatus == AI_Z_OFF) - SSidlenpcpool.idle_mobs_by_zlevel[old_z] -= src + SSidlenpcpool.idle_mobs_by_zlevel[old_turf?.z] -= src toggle_ai(initial(AIStatus)) ///This proc is used for adding the swabbale element to mobs so that they are able to be biopsied and making sure holograpic and butter-based creatures don't yield viable cells samples. diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 363103d0181..569d6be11bb 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -127,10 +127,9 @@ All ShuttleMove procs go here // Called on atoms after everything has been moved /atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) - var/turf/newT = get_turf(src) if (newT.z != oldT.z) - onTransitZ(oldT.z, newT.z) + on_changed_z_level(oldT, newT) if(light) update_light()