diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm index e3df50bca7c..7dbe0a1d1bf 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_movable.dm @@ -47,8 +47,6 @@ #define COMSIG_MOVABLE_THROW_LANDED "movable_throw_landed" ///from base of atom/movable/on_changed_z_level(): (turf/old_turf, turf/new_turf, same_z_layer) #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" ///from base of atom/movable/Hear(): (proc args list(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list())) #define COMSIG_MOVABLE_HEAR "movable_hear" #define HEARING_MESSAGE 1 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index 363b8233f4f..c859d4a69a8 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -409,6 +409,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// `do_teleport` will not allow this atom to teleport #define TRAIT_NO_TELEPORT "no-teleport" +/// This atom is a secluded location, which is counted as out of bounds. +/// Anything that enters this atom's contents should react if it wants to stay in bounds. +#define TRAIT_SECLUDED_LOCATION "secluded_loc" /// Trait used by fugu glands to avoid double buffing #define TRAIT_FUGU_GLANDED "fugu_glanded" diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm index ee110a96853..a5bbb3c7ce5 100644 --- a/code/datums/brain_damage/special.dm +++ b/code/datums/brain_damage/special.dm @@ -332,10 +332,6 @@ "Do you even exist?",\ "You simply fade away.")]") owner.forceMove(veil) - SEND_SIGNAL(owner, COMSIG_MOVABLE_SECLUDED_LOCATION) - for(var/thing in owner) - var/atom/movable/AM = thing - SEND_SIGNAL(AM, COMSIG_MOVABLE_SECLUDED_LOCATION) COOLDOWN_START(src, crisis_cooldown, 1 MINUTES) addtimer(CALLBACK(src, .proc/fade_in), duration) diff --git a/code/datums/components/chasm.dm b/code/datums/components/chasm.dm index 34e38aed609..b02b8e60a22 100644 --- a/code/datums/components/chasm.dm +++ b/code/datums/components/chasm.dm @@ -178,7 +178,6 @@ GLOBAL_LIST_INIT(chasm_storage, list()) if (dropped_thing.forceMove(storage)) if (isliving(dropped_thing)) RegisterSignal(dropped_thing, COMSIG_LIVING_REVIVE, .proc/on_revive) - SEND_SIGNAL(dropped_thing, COMSIG_MOVABLE_SECLUDED_LOCATION) else parent.visible_message(span_boldwarning("[parent] spits out [dropped_thing]!")) dropped_thing.throw_at(get_edge_target_turf(parent, pick(GLOB.alldirs)), rand(1, 10), rand(1, 10)) @@ -233,3 +232,7 @@ GLOBAL_LIST_INIT(chasm_storage, list()) desc = "The bottom of a hole. You shouldn't be able to interact with this." anchored = TRUE mouse_opacity = MOUSE_OPACITY_TRANSPARENT + +/obj/effect/abstract/chasm_storage/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SECLUDED_LOCATION, INNATE_TRAIT) diff --git a/code/datums/components/stationloving.dm b/code/datums/components/stationloving.dm index b684ad913a3..a07c35ad8c4 100644 --- a/code/datums/components/stationloving.dm +++ b/code/datums/components/stationloving.dm @@ -10,11 +10,6 @@ /datum/component/stationloving/Initialize(inform_admins = FALSE, allow_item_destruction = FALSE) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE - 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_item_destruction = allow_item_destruction @@ -22,6 +17,30 @@ if(!atom_in_bounds(parent)) relocate() +/datum/component/stationloving/RegisterWithParent() + 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) + // Relocate when we become unreachable + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, .proc/on_parent_moved) + // Relocate when our loc, or any of our loc's locs, becomes unreachable + var/static/list/loc_connections = list( + COMSIG_MOVABLE_MOVED = .proc/on_parent_moved, + SIGNAL_ADDTRAIT(TRAIT_SECLUDED_LOCATION) = .proc/on_loc_secluded, + ) + AddComponent(/datum/component/connect_containers, parent, loc_connections) + +/datum/component/stationloving/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_MOVABLE_Z_CHANGED, + COMSIG_PARENT_PREQDELETED, + COMSIG_ITEM_IMBUE_SOUL, + COMSIG_ITEM_MARK_RETRIEVAL, + COMSIG_MOVABLE_MOVED, + )) + + qdel(GetComponent(/datum/component/connect_containers)) + /datum/component/stationloving/InheritComponent(datum/component/stationloving/newc, original, inform_admins, allow_death) if (original) if (newc) @@ -38,30 +57,59 @@ if(GLOB.blobstart.len > 0) target_turf = get_turf(pick(GLOB.blobstart)) else - CRASH("Unable to find a blobstart landmark") + CRASH("Unable to find a blobstart landmark for [type] to relocate [parent].") var/atom/movable/movable_parent = parent playsound(movable_parent, 'sound/machines/synth_no.ogg', 5, TRUE) + + var/mob/holder = get(movable_parent, /mob) + if(holder) + to_chat(holder, span_danger("You can't help but feel that you just lost something back there...")) + holder.temporarilyRemoveItemFromInventory(parent, TRUE) // prevents ghost diskie + 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...")) 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 proc for [COMSIG_MOVABLE_MOVED], called when our parent moves, or our parent's loc, or our parent's loc loc... +/// To check if our disk is moving somewhere it shouldn't be, such as off Z level, or into an invalid area +/datum/component/stationloving/proc/on_parent_moved(atom/movable/source, turf/old_turf) SIGNAL_HANDLER - if(atom_in_bounds(parent)) + if(atom_in_bounds(source)) return - var/turf/current_turf = get_turf(parent) + var/turf/current_turf = get_turf(source) 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)].") + // Our turf actually didn't change, so it's more likely we became secluded + if(current_turf == old_turf) + log_game("[parent] moved out of bounds at [loc_name(current_turf)], becoming inaccessible / secluded. \ + Moving it to [loc_name(new_destination)].") - return COMPONENT_MOVABLE_BLOCK_PRE_MOVE + if(inform_admins) + message_admins("[parent] moved out of bounds at [ADMIN_VERBOSEJMP(current_turf)], becoming inaccessible / secluded. \ + Moving it to [ADMIN_VERBOSEJMP(new_destination)].") + + // Our locs changes, we did in fact move somewhere + else + 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)].") + +/// Signal proc for [SIGNAL_ADDTRAIT], via [TRAIT_SECLUDED_LOCATION] on our locs, to ensure nothing funky happens +/datum/component/stationloving/proc/on_loc_secluded(atom/movable/source) + SIGNAL_HANDLER + + var/turf/new_destination = relocate() + log_game("[parent] moved out of bounds at [loc_name(source)], becoming inaccessible / secluded. \ + Moving it to [loc_name(new_destination)].") + + if(inform_admins) + message_admins("[parent] moved out of bounds at [ADMIN_VERBOSEJMP(source)], becoming inaccessible / secluded. \ + Moving it to [ADMIN_VERBOSEJMP(new_destination)].") /datum/component/stationloving/proc/check_soul_imbue(datum/source) SIGNAL_HANDLER @@ -76,14 +124,32 @@ /// Checks whether a given atom's turf is within bounds. Returns TRUE if it is, FALSE if it isn't. /datum/component/stationloving/proc/atom_in_bounds(atom/atom_to_check) - 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/centcom/abductor_ship, /area/awaymission/errorroom)) + // Typecache of shuttles that we allow the disk to stay on + 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, + )) + // Typecache of areas on the centcom Z-level that we allow the disk to stay on + var/static/list/disallowed_centcom_areas = typecacheof(list( + /area/centcom/abductor_ship, + /area/awaymission/errorroom, + )) + + // Our loc is a secluded location = not in bounds + if (atom_to_check.loc && HAS_TRAIT(atom_to_check.loc, TRAIT_SECLUDED_LOCATION)) + return FALSE + // No turf below us = nullspace = not in bounds var/turf/destination_turf = get_turf(atom_to_check) if (!destination_turf) return FALSE - var/area/destination_area = destination_turf.loc if (is_station_level(destination_turf.z)) return TRUE + + var/area/destination_area = destination_turf.loc if (is_centcom_level(destination_turf.z)) if (is_type_in_typecache(destination_area, disallowed_centcom_areas)) return FALSE @@ -100,28 +166,17 @@ var/turf/current_turf = get_turf(parent) - if(inform_admins && force) + if(force && inform_admins) 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_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)].") + 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)].") + 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/datums/elements/trait_loc.dm b/code/datums/elements/trait_loc.dm new file mode 100644 index 00000000000..e86db69bd7c --- /dev/null +++ b/code/datums/elements/trait_loc.dm @@ -0,0 +1,34 @@ +/** + * # Trait Loc Element + * + * Adds a trait to the movable's loc, and handles relocating the trait if the movable itself moves. + */ +/datum/element/trait_loc + element_flags = ELEMENT_BESPOKE|ELEMENT_DETACH // handles if our movable is deleted + id_arg_index = 2 + /// What trait to apply to the movable's loc. + var/trait_to_give + +/datum/element/trait_loc/Attach(atom/movable/target, trait_to_give) + . = ..() + if(!ismovable(target)) + return ELEMENT_INCOMPATIBLE + + src.trait_to_give = trait_to_give + + RegisterSignal(target, COMSIG_MOVABLE_MOVED, .proc/on_movable_relocated) + if(target.loc) + ADD_TRAIT(target.loc, trait_to_give, REF(target)) + +/datum/element/trait_loc/Detach(atom/movable/source, ...) + . = ..() + UnregisterSignal(source, COMSIG_MOVABLE_MOVED) + if(source.loc) + REMOVE_TRAIT(source.loc, trait_to_give, REF(source)) + +/datum/element/trait_loc/proc/on_movable_relocated(atom/movable/source, atom/old_loc) + SIGNAL_HANDLER + + REMOVE_TRAIT(old_loc, trait_to_give, REF(source)) + if(source.loc) + ADD_TRAIT(source.loc, trait_to_give, REF(source)) diff --git a/code/game/objects/items/devices/desynchronizer.dm b/code/game/objects/items/devices/desynchronizer.dm index 49925f6b1ce..26706adf5b1 100644 --- a/code/game/objects/items/devices/desynchronizer.dm +++ b/code/game/objects/items/devices/desynchronizer.dm @@ -48,10 +48,6 @@ new /obj/effect/temp_visual/desynchronizer(drop_location()) to_chat(user, span_notice("You activate [src], desynchronizing yourself from the present. You can still see your surroundings, but you feel eerily dissociated from reality.")) user.forceMove(sync_holder) - SEND_SIGNAL(user, COMSIG_MOVABLE_SECLUDED_LOCATION) - for(var/thing in user) - var/atom/movable/AM = thing - SEND_SIGNAL(AM, COMSIG_MOVABLE_SECLUDED_LOCATION) last_use = world.time icon_state = "desynchronizer-on" resync_timer = addtimer(CALLBACK(src, .proc/resync), duration , TIMER_STOPPABLE) @@ -81,6 +77,10 @@ anchored = TRUE resistance_flags = INDESTRUCTIBLE +/obj/effect/abstract/sync_holder/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_SECLUDED_LOCATION, INNATE_TRAIT) + /obj/effect/abstract/sync_holder/relaymove(mob/living/user, direction) // While faded out of spacetime, no, you cannot move. return diff --git a/code/game/objects/structures/holosign.dm b/code/game/objects/structures/holosign.dm index 317bc86b77c..05dd1eb73b8 100644 --- a/code/game/objects/structures/holosign.dm +++ b/code/game/objects/structures/holosign.dm @@ -106,16 +106,13 @@ /obj/structure/holosign/barrier/atmos/Initialize(mapload) . = ..() - var/turf/local = get_turf(loc) - ADD_TRAIT(local, TRAIT_FIREDOOR_STOP, TRAIT_GENERIC) air_update_turf(TRUE, TRUE) + AddElement(/datum/element/trait_loc, TRAIT_FIREDOOR_STOP) /obj/structure/holosign/barrier/atmos/block_superconductivity() //Didn't used to do this, but it's "normal", and will help ease heat flow transitions with the players. return TRUE /obj/structure/holosign/barrier/atmos/Destroy() - var/turf/local = get_turf(loc) - REMOVE_TRAIT(local, TRAIT_FIREDOOR_STOP, TRAIT_GENERIC) air_update_turf(TRUE, FALSE) return ..() diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_core.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_core.dm index da629ebad66..127fd6d85a6 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_core.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_core.dm @@ -175,14 +175,8 @@ radio.recalculateChannels() investigate_log("has been created.", INVESTIGATE_HYPERTORUS) - RegisterSignal(src.loc, COMSIG_ATOM_ENTERED, .proc/on_entered) - - for(var/atom/movable/movable_object in src.loc) - SEND_SIGNAL(movable_object, COMSIG_MOVABLE_SECLUDED_LOCATION) - -/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/on_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs) - SIGNAL_HANDLER - SEND_SIGNAL(arrived, COMSIG_MOVABLE_SECLUDED_LOCATION) // to prevent stationloving items (eg. nuke disk) being teleported onto core + // Our center is unreachable, so prevent stuff from getting stuck in there + AddElement(/datum/element/trait_loc, TRAIT_SECLUDED_LOCATION) /obj/machinery/atmospherics/components/unary/hypertorus/core/Destroy() unregister_signals(TRUE) diff --git a/tgstation.dme b/tgstation.dme index e0939614aea..e747d013f7e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1079,6 +1079,7 @@ #include "code\datums\elements\swabbable.dm" #include "code\datums\elements\tenacious.dm" #include "code\datums\elements\tool_flash.dm" +#include "code\datums\elements\trait_loc.dm" #include "code\datums\elements\turf_transparency.dm" #include "code\datums\elements\undertile.dm" #include "code\datums\elements\update_icon_blocker.dm"