diff --git a/code/datums/components/wall_mounted.dm b/code/datums/components/wall_mounted.dm new file mode 100644 index 00000000000..67ba52feeea --- /dev/null +++ b/code/datums/components/wall_mounted.dm @@ -0,0 +1,74 @@ +// This element should be applied to wall-mounted machines/structures, so that if the wall it's "hanging" from is broken or deconstructed, the wall-hung structure will deconstruct. +/datum/component/wall_mounted + dupe_mode = COMPONENT_DUPE_ALLOWED + /// The wall our object is currently linked to. + var/turf/hanging_wall_turf + /// Callback to the parent's proc to call on the linked object when the wall disappear's or changes. + var/datum/callback/on_drop + +/datum/component/wall_mounted/Initialize(target_wall, on_drop_callback) + . = ..() + if(!isobj(parent)) + return COMPONENT_INCOMPATIBLE + if(!isturf(target_wall)) + return COMPONENT_INCOMPATIBLE + if(!on_drop_callback) + on_drop = TYPE_PROC_REF(/obj, deconstruct) + hanging_wall_turf = target_wall + on_drop = on_drop_callback + +/datum/component/wall_mounted/RegisterWithParent() + RegisterSignal(hanging_wall_turf, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(hanging_wall_turf, COMSIG_TURF_CHANGE, PROC_REF(drop_wallmount)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(drop_wallmount)) + RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(on_linked_destroyed)) + +/datum/component/wall_mounted/UnregisterFromParent() + UnregisterSignal(hanging_wall_turf, list(COMSIG_ATOM_EXAMINE, COMSIG_TURF_CHANGE)) + UnregisterSignal(parent, list(COMSIG_QDELETING, COMSIG_MOVABLE_MOVED)) + hanging_wall_turf = null + +/** + * Basic reference handling if the hanging/linked object is destroyed first. + */ +/datum/component/wall_mounted/proc/on_linked_destroyed() + SIGNAL_HANDLER + if(!QDELING(src)) + qdel(src) + +/** + * When the wall is examined, explains that it's supporting the linked object. + */ +/datum/component/wall_mounted/proc/on_examine(datum/source, mob/user, list/examine_list) + SIGNAL_HANDLER + examine_list += span_notice("\The [hanging_wall_turf] is currently supporting [span_bold("[parent]")]. Deconstruction or excessive damage would cause it to [span_bold("fall to the ground")].") + +/** + * Handles the dropping of the linked object. This is done via deconstruction, as that should be the most sane way to handle it for most objects. + * Except for intercoms, which are handled by creating a new wallframe intercom, as they're apparently items. + */ +/datum/component/wall_mounted/proc/drop_wallmount() + SIGNAL_HANDLER + var/obj/hanging_parent = parent + hanging_parent.visible_message(message = span_warning("\The [hanging_parent] falls off the wall!"), vision_distance = 5) + on_drop?.Invoke(hanging_parent) + if(!QDELING(src)) + qdel(src) //Well, we fell off the wall, so we're done here. +/** + * Checks object direction and then verifies if there's a wall in that direction. Finally, applies a wall_mounted component to the object. + * + * @param directional If TRUE, will use the direction of the object to determine the wall to attach to. If FALSE, will use the object's loc. + * @param custom_drop_callback If set, will use this callback instead of the default deconstruct callback. + */ +/obj/proc/find_and_hang_on_wall(directional = TRUE, custom_drop_callback) + if(istype(get_area(src), /area/shuttle)) + return FALSE //For now, we're going to keep the component off of shuttles to avoid the turf changing issue. We'll hit that later really; + var/turf/attachable_wall + if(directional) + attachable_wall = get_step(src, dir) + else + attachable_wall = loc ///Pull from the curent object loc + if(!iswallturf(attachable_wall)) + return FALSE//Nothing to latch onto, or not the right thing. + src.AddComponent(/datum/component/wall_mounted, attachable_wall, custom_drop_callback) + return TRUE diff --git a/code/game/machinery/barsigns.dm b/code/game/machinery/barsigns.dm index 16686b23c77..b8cee255356 100644 --- a/code/game/machinery/barsigns.dm +++ b/code/game/machinery/barsigns.dm @@ -24,6 +24,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/barsign, 32) /obj/machinery/barsign/Initialize(mapload) . = ..() set_sign(new /datum/barsign/hiddensigns/signoff) + find_and_hang_on_wall() /obj/machinery/barsign/proc/set_sign(datum/barsign/sign) if(!istype(sign)) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 21a718d8705..5824f93dcc7 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -55,6 +55,7 @@ board.accesses = req_one_access setup_device() + find_and_hang_on_wall() /obj/machinery/button/Destroy() QDEL_NULL(device) @@ -233,6 +234,20 @@ device.pulsed(user) SEND_GLOBAL_SIGNAL(COMSIG_GLOB_BUTTON_PRESSED,src) +/** + * Called when the mounted button's wall is knocked down. + */ +/obj/machinery/button/proc/knock_down() + if(device) + device.forceMove(get_turf(src)) + device = null + if(board) + board.forceMove(get_turf(src)) + req_access = list() + req_one_access = list() + board = null + qdel(src) + /obj/machinery/button/door name = "door button" desc = "A door remote control switch." diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm index d0792e8c617..da13377b2f5 100644 --- a/code/game/machinery/camera/camera.dm +++ b/code/game/machinery/camera/camera.dm @@ -103,6 +103,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/camera/xray, 0) update_appearance() alarm_manager = new(src) + find_and_hang_on_wall(directional = TRUE, \ + custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), FALSE)) RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) diff --git a/code/game/machinery/camera/camera_assembly.dm b/code/game/machinery/camera/camera_assembly.dm index 37907a5ba29..786a2c3a39a 100644 --- a/code/game/machinery/camera/camera_assembly.dm +++ b/code/game/machinery/camera/camera_assembly.dm @@ -67,6 +67,7 @@ . = ..() if(building) setDir(ndir) + find_and_hang_on_wall() /obj/structure/camera_assembly/update_icon_state() icon_state = "[xray_module ? "xray" : null][initial(icon_state)]" diff --git a/code/game/machinery/computer/telescreen.dm b/code/game/machinery/computer/telescreen.dm index b03ed092269..ceb3c2e923e 100644 --- a/code/game/machinery/computer/telescreen.dm +++ b/code/game/machinery/computer/telescreen.dm @@ -56,6 +56,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/computer/security/telescreen/entertai /obj/machinery/computer/security/telescreen/entertainment/Initialize(mapload) . = ..() RegisterSignal(src, COMSIG_CLICK, PROC_REF(BigClick)) + find_and_hang_on_wall() // Bypass clickchain to allow humans to use the telescreen from a distance /obj/machinery/computer/security/telescreen/entertainment/proc/BigClick() diff --git a/code/game/machinery/defibrillator_mount.dm b/code/game/machinery/defibrillator_mount.dm index d212f2ba45d..cb12a399260 100644 --- a/code/game/machinery/defibrillator_mount.dm +++ b/code/game/machinery/defibrillator_mount.dm @@ -23,6 +23,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) /obj/machinery/defibrillator_mount/loaded/Initialize(mapload) //loaded subtype for mapping use . = ..() defib = new/obj/item/defibrillator/loaded(src) + find_and_hang_on_wall() MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/defibrillator_mount, 28) diff --git a/code/game/machinery/digital_clock.dm b/code/game/machinery/digital_clock.dm index 0bfb8aeba72..d0b695428af 100644 --- a/code/game/machinery/digital_clock.dm +++ b/code/game/machinery/digital_clock.dm @@ -83,6 +83,7 @@ /obj/machinery/digital_clock/Initialize(mapload) . = ..() START_PROCESSING(SSdigital_clock, src) + find_and_hang_on_wall() /obj/machinery/digital_clock/Destroy() STOP_PROCESSING(SSdigital_clock, src) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 680a7a837d5..82c5ce56a16 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -80,7 +80,7 @@ ) ) AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) - + find_and_hang_on_wall() update_appearance() diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm index 8d3c4febd70..8075b51dcab 100644 --- a/code/game/machinery/flasher.dm +++ b/code/game/machinery/flasher.dm @@ -28,6 +28,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/flasher, 26) . = ..() // ..() is EXTREMELY IMPORTANT, never forget to add it if(!built) bulb = new(src) + find_and_hang_on_wall() /obj/machinery/flasher/vv_edit_var(vname, vval) . = ..() diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm index 73f527ca7d5..060b29c4d20 100644 --- a/code/game/machinery/igniter.dm +++ b/code/game/machinery/igniter.dm @@ -162,6 +162,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/sparker, 26) spark_system.set_up(2, 1, src) spark_system.attach(src) register_context() + find_and_hang_on_wall() /obj/machinery/sparker/Destroy() QDEL_NULL(spark_system) diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm index f9275794853..54c098de9fd 100644 --- a/code/game/machinery/lightswitch.dm +++ b/code/game/machinery/lightswitch.dm @@ -31,6 +31,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/light_switch, 26) area = get_area(src) if(!name) name = "light switch ([area.name])" + find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(deconstruct), TRUE)) update_appearance() diff --git a/code/game/machinery/newscaster/newscaster_machine.dm b/code/game/machinery/newscaster/newscaster_machine.dm index 98cce390010..1ae08c066f0 100644 --- a/code/game/machinery/newscaster/newscaster_machine.dm +++ b/code/game/machinery/newscaster/newscaster_machine.dm @@ -73,6 +73,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/newscaster, 30) GLOB.allCasters += src GLOB.allbountyboards += src update_appearance() + find_and_hang_on_wall() /obj/machinery/newscaster/Destroy() GLOB.allCasters -= src diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm index b19a8032e7d..9fae5086989 100644 --- a/code/game/machinery/porta_turret/portable_turret.dm +++ b/code/game/machinery/porta_turret/portable_turret.dm @@ -919,6 +919,7 @@ DEFINE_BITFIELD(turret_flags, list( if(built) locked = FALSE power_change() //Checks power and initial settings + find_and_hang_on_wall() /obj/machinery/turretid/Destroy() turrets.Cut() diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index cb2c541d72b..06837cc961d 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -127,6 +127,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) radio = new /obj/item/radio(src) radio.set_listening(FALSE) + find_and_hang_on_wall() /obj/machinery/requests_console/Destroy() QDEL_NULL(radio) diff --git a/code/game/machinery/status_display.dm b/code/game/machinery/status_display.dm index 102159bbbb9..cbfb61a4a03 100644 --- a/code/game/machinery/status_display.dm +++ b/code/game/machinery/status_display.dm @@ -319,6 +319,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/status_display/evac, 32) AddComponent(/datum/component/usb_port, list( /obj/item/circuit_component/status_display, )) + find_and_hang_on_wall() /obj/machinery/status_display/evac/Destroy() SSradio.remove_object(src,frequency) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index 3e261b9eabb..7cba8e9bbac 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -34,6 +34,9 @@ return RegisterSignal(current_area, COMSIG_AREA_POWER_CHANGE, PROC_REF(AreaPowerCheck)) GLOB.intercoms_list += src + if(!unscrewed) + find_and_hang_on_wall(directional = TRUE, \ + custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) /obj/item/radio/intercom/Destroy() . = ..() @@ -79,8 +82,7 @@ if(tool.use_tool(src, user, 80)) user.visible_message(span_notice("[user] unsecures [src]!"), span_notice("You detach [src] from the wall.")) playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) - new/obj/item/wallframe/intercom(get_turf(src)) - qdel(src) + knock_down() /** * Override attack_tk_grab instead of attack_tk because we actually want attack_tk's @@ -174,6 +176,13 @@ set_on(current_area.powered(AREA_USAGE_EQUIP)) // set "on" to the equipment power status of our area. update_appearance() +/** + * Called by the wall mount component and reused during the tool deconstruction proc. + */ +/obj/item/radio/intercom/proc/knock_down() + new/obj/item/wallframe/intercom(get_turf(src)) + qdel(src) + //Created through the autolathe or through deconstructing intercoms. Can be applied to wall to make a new intercom on it! /obj/item/wallframe/intercom name = "intercom frame" diff --git a/code/game/objects/items/storage/secure.dm b/code/game/objects/items/storage/secure.dm index 46eb8356c79..ad4be8d6e40 100644 --- a/code/game/objects/items/storage/secure.dm +++ b/code/game/objects/items/storage/secure.dm @@ -181,6 +181,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/storage/secure/safe, 32) . = ..() atom_storage.set_holdable(cant_hold_list = list(/obj/item/storage/secure/briefcase)) atom_storage.max_specific_storage = WEIGHT_CLASS_GIGANTIC + find_and_hang_on_wall() /obj/item/storage/secure/safe/PopulateContents() new /obj/item/paper(src) diff --git a/code/game/objects/items/wall_mounted.dm b/code/game/objects/items/wall_mounted.dm index 3cfafe74f97..1467c8eb62a 100644 --- a/code/game/objects/items/wall_mounted.dm +++ b/code/game/objects/items/wall_mounted.dm @@ -40,21 +40,22 @@ span_hear("You hear clicking.")) var/floor_to_wall = get_dir(user, on_wall) - var/obj/O = new result_path(get_turf(user), floor_to_wall, TRUE) - O.setDir(floor_to_wall) + var/obj/hanging_object = new result_path(get_turf(user), floor_to_wall, TRUE) + hanging_object.setDir(floor_to_wall) + on_wall.AddComponent(/datum/component/wall_mounted, hanging_object) if(pixel_shift) switch(floor_to_wall) if(NORTH) - O.pixel_y = pixel_shift + hanging_object.pixel_y = pixel_shift if(SOUTH) - O.pixel_y = -pixel_shift + hanging_object.pixel_y = -pixel_shift if(EAST) - O.pixel_x = pixel_shift + hanging_object.pixel_x = pixel_shift if(WEST) - O.pixel_x = -pixel_shift - after_attach(O) - + hanging_object.pixel_x = -pixel_shift + after_attach(hanging_object) + hanging_object.find_and_hang_on_wall() qdel(src) /obj/item/wallframe/proc/after_attach(obj/attached_to) diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm index 5eca5026776..91b63314eb3 100644 --- a/code/game/objects/structures/extinguisher.dm +++ b/code/game/objects/structures/extinguisher.dm @@ -20,6 +20,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/extinguisher_cabinet, 29) stored_extinguisher = new /obj/item/extinguisher(src) update_appearance(UPDATE_ICON) register_context() + find_and_hang_on_wall() /obj/structure/extinguisher_cabinet/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() diff --git a/code/game/objects/structures/fireaxe.dm b/code/game/objects/structures/fireaxe.dm index 75294549ebe..59a00618b0e 100644 --- a/code/game/objects/structures/fireaxe.dm +++ b/code/game/objects/structures/fireaxe.dm @@ -36,6 +36,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/fireaxecabinet, 32) if(populate_contents) held_item = new item_path(src) update_appearance() + find_and_hang_on_wall() /obj/structure/fireaxecabinet/Destroy() if(held_item) diff --git a/code/game/objects/structures/mirror.dm b/code/game/objects/structures/mirror.dm index 2fcaefd3575..2a4f44cc0a8 100644 --- a/code/game/objects/structures/mirror.dm +++ b/code/game/objects/structures/mirror.dm @@ -27,6 +27,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/mirror, 28) +/obj/structure/mirror/Initialize(mapload) + . = ..() + find_and_hang_on_wall() + /obj/structure/mirror/broken icon_state = "mirror_broke" diff --git a/code/game/objects/structures/noticeboard.dm b/code/game/objects/structures/noticeboard.dm index 9d09a747018..534622619d1 100644 --- a/code/game/objects/structures/noticeboard.dm +++ b/code/game/objects/structures/noticeboard.dm @@ -26,6 +26,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/noticeboard, 32) I.forceMove(src) notices++ update_appearance(UPDATE_ICON) + find_and_hang_on_wall() //attaching papers!! /obj/structure/noticeboard/attackby(obj/item/O, mob/user, params) diff --git a/code/game/objects/structures/signs/_signs.dm b/code/game/objects/structures/signs/_signs.dm index cdb7ba0811f..b8709334c37 100644 --- a/code/game/objects/structures/signs/_signs.dm +++ b/code/game/objects/structures/signs/_signs.dm @@ -14,6 +14,8 @@ var/is_editable = FALSE ///sign_change_name is used to make nice looking, alphebetized and categorized names when you use a pen on any sign item or structure which is_editable. var/sign_change_name + ///Callback to the knock down proc for wallmounting behavior. + var/knock_down_callback /datum/armor/structure_sign melee = 50 @@ -23,6 +25,12 @@ /obj/structure/sign/Initialize(mapload) . = ..() register_context() + knock_down_callback = CALLBACK(src, PROC_REF(knock_down)) + find_and_hang_on_wall(custom_drop_callback = knock_down_callback) + +/obj/structure/sign/Destroy() + . = ..() + knock_down_callback = null /obj/structure/sign/add_context(atom/source, list/context, obj/item/held_item, mob/user) . = ..() @@ -55,18 +63,7 @@ playsound(src, 'sound/items/deconstruct.ogg', 50, TRUE) user.visible_message(span_notice("[user] unfastens [src]."), \ span_notice("You unfasten [src].")) - var/obj/item/sign/unwrenched_sign = new (get_turf(user)) - if(type != /obj/structure/sign/blank) //If it's still just a basic sign backing, we can (and should) skip some of the below variable transfers. - unwrenched_sign.name = name //Copy over the sign structure variables to the sign item we're creating when we unwrench a sign. - unwrenched_sign.desc = "[desc] It can be placed on a wall." - unwrenched_sign.icon = icon - unwrenched_sign.icon_state = icon_state - unwrenched_sign.sign_path = type - unwrenched_sign.set_custom_materials(custom_materials) //This is here so picture frames and wooden things don't get messed up. - unwrenched_sign.is_editable = is_editable - unwrenched_sign.update_integrity(get_integrity()) //Transfer how damaged it is. - unwrenched_sign.setDir(dir) - qdel(src) //The sign structure on the wall goes poof and only the sign item from unwrenching remains. + knock_down(user) return TRUE /obj/structure/sign/welder_act(mob/living/user, obj/item/I) @@ -115,6 +112,29 @@ return return ..() +/** + * This is called when a sign is removed from a wall, either through deconstruction or being knocked down. + * @param mob/living/user The user who removed the sign, if it was knocked down by a mob. + */ +/obj/structure/sign/proc/knock_down(mob/living/user) + var/turf/drop_turf + if(user) + drop_turf = get_turf(user) + else + drop_turf = drop_location() + var/obj/item/sign/unwrenched_sign = new (drop_turf) + if(type != /obj/structure/sign/blank) //If it's still just a basic sign backing, we can (and should) skip some of the below variable transfers. + unwrenched_sign.name = name //Copy over the sign structure variables to the sign item we're creating when we unwrench a sign. + unwrenched_sign.desc = "[desc] It can be placed on a wall." + unwrenched_sign.icon = icon + unwrenched_sign.icon_state = icon_state + unwrenched_sign.sign_path = type + unwrenched_sign.set_custom_materials(custom_materials) //This is here so picture frames and wooden things don't get messed up. + unwrenched_sign.is_editable = is_editable + unwrenched_sign.update_integrity(get_integrity()) //Transfer how damaged it is. + unwrenched_sign.setDir(dir) + qdel(src) //The sign structure on the wall goes poof and only the sign item from unwrenching remains. + /obj/structure/sign/blank //This subtype is necessary for now because some other things (posters, picture frames, paintings) inheret from the parent type. icon_state = "backing" name = "sign backing" @@ -211,6 +231,7 @@ playsound(target_turf, 'sound/items/deconstruct.ogg', 50, TRUE) placed_sign.update_integrity(get_integrity()) placed_sign.setDir(dir) + placed_sign.find_and_hang_on_wall(TRUE, placed_sign.knock_down_callback) qdel(src) /obj/item/sign/welder_act(mob/living/user, obj/item/I) diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm index ec0ae01fbf6..b991bc0c274 100644 --- a/code/game/objects/structures/watercloset.dm +++ b/code/game/objects/structures/watercloset.dm @@ -168,6 +168,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/urinal, 32) /obj/structure/urinal/Initialize(mapload) . = ..() hidden_item = new /obj/item/food/urinalcake + find_and_hang_on_wall() /obj/structure/urinal/attack_hand(mob/living/user, list/modifiers) . = ..() diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index 3ef5c9a4d33..a11f439ec31 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -124,6 +124,7 @@ GLOBAL_LIST_EMPTY_TYPED(air_alarms, /obj/machinery/airalarm) GLOB.air_alarms += src update_appearance() + find_and_hang_on_wall() /obj/machinery/airalarm/process() if(!COOLDOWN_FINISHED(src, warning_cooldown)) diff --git a/code/modules/atmospherics/machinery/bluespace_vendor.dm b/code/modules/atmospherics/machinery/bluespace_vendor.dm index 7ea5b827d4a..84753354018 100644 --- a/code/modules/atmospherics/machinery/bluespace_vendor.dm +++ b/code/modules/atmospherics/machinery/bluespace_vendor.dm @@ -69,6 +69,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/bluespace_vendor, 30) /obj/machinery/bluespace_vendor/Initialize(mapload) . = ..() AddComponent(/datum/component/payment, tank_cost, SSeconomy.get_dep_account(ACCOUNT_ENG), PAYMENT_ANGRY) + find_and_hang_on_wall( FALSE) /obj/machinery/bluespace_vendor/LateInitialize() . = ..() diff --git a/code/modules/paperwork/ticketmachine.dm b/code/modules/paperwork/ticketmachine.dm index 8d62bf784cb..f41e780e4a9 100644 --- a/code/modules/paperwork/ticketmachine.dm +++ b/code/modules/paperwork/ticketmachine.dm @@ -31,6 +31,7 @@ /obj/machinery/ticket_machine/Initialize(mapload) . = ..() update_appearance() + find_and_hang_on_wall() /obj/machinery/ticket_machine/Destroy() for(var/obj/item/ticket_machine_ticket/ticket in tickets) diff --git a/code/modules/power/apc/apc_main.dm b/code/modules/power/apc/apc_main.dm index e2a1b956590..9bfdaf1e249 100644 --- a/code/modules/power/apc/apc_main.dm +++ b/code/modules/power/apc/apc_main.dm @@ -212,6 +212,7 @@ AddElement(/datum/element/contextual_screentip_bare_hands, rmb_text = "Toggle interface lock") AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks) + find_and_hang_on_wall() /obj/machinery/power/apc/Destroy() if(malfai && operating) diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm index aabaced17d8..747010fc6c0 100644 --- a/code/modules/power/lighting/light.dm +++ b/code/modules/power/lighting/light.dm @@ -116,6 +116,7 @@ RegisterSignal(src, COMSIG_LIGHT_EATER_ACT, PROC_REF(on_light_eater)) RegisterSignal(src, COMSIG_HIT_BY_SABOTEUR, PROC_REF(on_saboteur)) AddElement(/datum/element/atmos_sensitive, mapload) + find_and_hang_on_wall(custom_drop_callback = CALLBACK(src, PROC_REF(knock_down))) return INITIALIZE_HINT_LATELOAD /obj/machinery/light/LateInitialize() @@ -688,6 +689,20 @@ continue INVOKE_ASYNC(src, PROC_REF(flicker)) +/** + * All the effects that occur when a light falls off a wall that it was hung onto. + */ +/obj/machinery/light/proc/knock_down() + new /obj/item/wallframe/light_fixture(drop_location()) + new /obj/item/stack/cable_coil(drop_location(), 1, "red") + if(status != LIGHT_BROKEN) + break_light_tube(FALSE) + if(status != LIGHT_EMPTY) + drop_light_tube() + if(cell) + cell.forceMove(drop_location()) + qdel(src) + /obj/machinery/light/floor name = "floor light" desc = "A lightbulb you can walk on without breaking it, amazing." diff --git a/code/modules/power/lighting/light_construct.dm b/code/modules/power/lighting/light_construct.dm index 5a8f406b86c..05d9533c79e 100644 --- a/code/modules/power/lighting/light_construct.dm +++ b/code/modules/power/lighting/light_construct.dm @@ -33,6 +33,7 @@ . = ..() if(building) setDir(ndir) + find_and_hang_on_wall() /obj/structure/light_construct/Destroy() QDEL_NULL(cell) diff --git a/code/modules/reagents/reagent_dispenser.dm b/code/modules/reagents/reagent_dispenser.dm index 9e3fe883b2e..d1b7afd4b78 100644 --- a/code/modules/reagents/reagent_dispenser.dm +++ b/code/modules/reagents/reagent_dispenser.dm @@ -1,3 +1,5 @@ +#define REAGENT_SPILL_DIVISOR 200 + /obj/structure/reagent_dispensers name = "Dispenser" desc = "..." @@ -203,6 +205,15 @@ return TRUE return FALSE +/obj/structure/reagent_dispensers/proc/knock_down() + var/datum/effect_system/fluid_spread/smoke/chem/smoke = new () + var/range = reagents.total_volume / REAGENT_SPILL_DIVISOR + smoke.attach(drop_location()) + smoke.set_up(round(range), holder = drop_location(), location = drop_location(), carry = reagents, silent = FALSE) + smoke.start(log = TRUE) + reagents.clear_reagents() + qdel(src) + /obj/structure/reagent_dispensers/wrench_act(mob/living/user, obj/item/tool) . = ..() if(!openable) @@ -322,6 +333,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 . = ..() if(prob(1)) desc = "IT'S PEPPER TIME, BITCH!" + find_and_hang_on_wall() /obj/structure/reagent_dispensers/water_cooler name = "liquid cooler" @@ -373,6 +385,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/peppertank, 3 MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30) +/obj/structure/reagent_dispensers/wall/virusfood/Initialize(mapload) + . = ..() + find_and_hang_on_wall() + /obj/structure/reagent_dispensers/cooking_oil name = "vat of cooking oil" desc = "A huge metal vat with a tap on the front. Filled with cooking oil for use in frying food." @@ -435,3 +451,5 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/reagent_dispensers/wall/virusfood, 30 desc = "A stationary, plumbed, fuel tank." reagent_id = /datum/reagent/fuel accepts_rig = TRUE + +#undef REAGENT_SPILL_DIVISOR diff --git a/tgstation.dme b/tgstation.dme index 49b9b0ec7a9..66ebdccabd0 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -1106,6 +1106,7 @@ #include "code\datums\components\uplink.dm" #include "code\datums\components\usb_port.dm" #include "code\datums\components\vacuum.dm" +#include "code\datums\components\wall_mounted.dm" #include "code\datums\components\wearertargeting.dm" #include "code\datums\components\weatherannouncer.dm" #include "code\datums\components\wet_floor.dm"