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()