Adds a new component so that items that are "attached" to walls will now drop/deconstruct on turf destruction. (#77417)

## About The Pull Request

Adds a new component, called wall_mounted, which applies on the
wallframe objects on construction, as well as a number of wall frame
objects and structures to cover mapped in, roundstart objects of the
like.
I might have forgotten a few, but this covers the vast majority that
players will run into in a given round.

This will cover wall destruction, turf explosion, the whole nine yards,
and call that object/structure/machine's deconstruct proc. We have some
special handling for intercoms as well since they're apparently items.

So most basic case is this: You have a wall. that wall holds a sign. If
you examine the wall, it tells you that the wall is currently supporting
the **Example Sign**. It tells you that if the wall is damaged or
destroyed, the sign will **fall off the wall.** So, if you were to
welder, bomb, or hulk your way through that wall, it would call the
deconstruct() proc on that sign, and fall off the wall, leaving an item
sign at the foot of the wall.

## To-Do

- [x] Stop breaking all wallmounts when operating shuttles (Signal
conflict with COMSIG_TURF_CHANGED 😔)
- [x] Confirm that the ~~deconstruct~~ designated proc of each wallmount
falling is sane for the intended object
- [x] Clean up the contents of the wall_mounted component to reduce
copy-paste on object init.
- [x] Add it to more stuff that may just not have a directional helper?
- [x] ~~Change how APC construction is handled to make it easier!~~
- [x] ~~Don't accidently nerf malf AI into the ground I guess~~

## Why It's Good For The Game

Closes #22283.
Helps close more of #47526.
Closes #54983.
Closes https://github.com/wall-nerds/wallening/issues/90.

All of these objects are "wall mounts". It stands to reason that they're
mounted to the walls they appear to be attached to. This attempts to
rectify them by giving them a turf link to the turf they're mounted to,
and then upon changes to that turf, dropping or breaking that object.
It'll need a little more polish to get to 100%, since I can see a few
more issues to iron out first, but I'm dropping this here for now to get
some feedback and put some fire under me to get this completed.

## Changelog

🆑
add: Wall mounted objects (Things like APCs, Air Alarms, Light switches,
Signs, Posters, Newscasters, you name it) will now fall to the ground
and break or deconstruct when their attaching wall is changed or broken.
/🆑
This commit is contained in:
ArcaneMusic
2023-09-16 00:17:38 +00:00
committed by GitHub
parent 5ca3b7d9fd
commit a77ac3e4f1
33 changed files with 205 additions and 23 deletions
+74
View File
@@ -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
+1
View File
@@ -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))
+15
View File
@@ -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."
+2
View File
@@ -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))
@@ -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)]"
@@ -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()
@@ -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)
+1
View File
@@ -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)
+1 -1
View File
@@ -80,7 +80,7 @@
)
)
AddElement(/datum/element/contextual_screentip_mob_typechecks, hovering_mob_typechecks)
find_and_hang_on_wall()
update_appearance()
+1
View File
@@ -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)
. = ..()
+1
View File
@@ -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)
+1
View File
@@ -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()
@@ -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
@@ -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()
+1
View File
@@ -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)
+1
View File
@@ -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)
@@ -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"
@@ -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)
+9 -8
View File
@@ -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)
@@ -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)
. = ..()
+1
View File
@@ -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)
+4
View File
@@ -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"
@@ -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)
+33 -12
View File
@@ -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)
@@ -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)
. = ..()
@@ -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))
@@ -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()
. = ..()
+1
View File
@@ -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)
+1
View File
@@ -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)
+15
View File
@@ -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."
@@ -33,6 +33,7 @@
. = ..()
if(building)
setDir(ndir)
find_and_hang_on_wall()
/obj/structure/light_construct/Destroy()
QDEL_NULL(cell)
@@ -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
+1
View File
@@ -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"