From 7f2ea1c1b7ffb8028530f7072b94666907193b39 Mon Sep 17 00:00:00 2001
From: Tsar-Salat <62388554+Tsar-Salat@users.noreply.github.com>
Date: Fri, 20 Oct 2023 08:53:52 -0400
Subject: [PATCH] Machines now store components in contents + dumping inventory
cleanup (#9314)
* main pr
* https://github.com/tgstation/tgstation/pull/60417
* fixes call to parent
* remove unused argument
* removecomment
* circuit deletion
* fix missing circuits
* https://github.com/tgstation/tgstation/pull/55126
* crossed removal modernization
---
code/game/machinery/_machinery.dm | 105 +++++++++++++-----
code/game/machinery/computer/_computer.dm | 10 +-
code/game/machinery/computer/arcade.dm | 11 +-
.../game/machinery/computer/buildandrepair.dm | 42 ++++++-
code/game/machinery/constructable_frame.dm | 46 +++++---
code/game/machinery/suit_storage_unit.dm | 24 ++--
code/game/machinery/teleporter.dm | 4 +-
.../items/circuitboards/circuitboard.dm | 29 ++++-
code/game/objects/objs.dm | 4 +
.../structures/crates_lockers/closets.dm | 2 +-
code/modules/antagonists/swarmer/swarmer.dm | 2 +-
.../atmospherics/machinery/atmosmachinery.dm | 1 -
.../components/binary_devices/circulator.dm | 5 +-
.../kitchen_machinery/deep_fryer.dm | 5 +-
.../kitchen_machinery/gibber.dm | 2 +-
.../kitchen_machinery/microwave.dm | 7 +-
.../kitchen_machinery/processor.dm | 11 +-
.../kitchen_machinery/smartfridge.dm | 52 ++++++---
code/modules/power/generator.dm | 3 +-
.../chemistry/machinery/chem_dispenser.dm | 2 +-
code/modules/research/server.dm | 2 -
code/modules/vending/cola.dm | 5 +-
code/modules/vending/snack.dm | 5 +-
23 files changed, 258 insertions(+), 121 deletions(-)
diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm
index fb713dc6abe30..e277af71f3dcb 100644
--- a/code/game/machinery/_machinery.dm
+++ b/code/game/machinery/_machinery.dm
@@ -153,7 +153,7 @@ Class Procs:
GLOB.machines += src
if(ispath(circuit, /obj/item/circuitboard))
- circuit = new circuit
+ circuit = new circuit(src)
circuit.apply_default_parts(src)
if(processing_flags & START_PROCESSING_ON_INIT)
@@ -192,11 +192,9 @@ Class Procs:
GLOB.machines.Remove(src)
if(datum_flags & DF_ISPROCESSING) // A sizeable portion of machines stops processing before qdel
end_processing()
- dropContents()
- if(length(component_parts))
- for(var/atom/A in component_parts)
- qdel(A)
- component_parts.Cut()
+ dump_inventory_contents()
+ QDEL_LIST(component_parts)
+ QDEL_NULL(circuit)
return ..()
/obj/machinery/proc/locate_machinery()
@@ -240,26 +238,65 @@ Class Procs:
//Update power
power_change()
+/**
+ * Opens the machine.
+ *
+ * Will update the machine icon and any user interfaces currently open.
+ * Arguments:
+ * * drop - Boolean. Whether to drop any stored items in the machine. Does not include components.
+ */
/obj/machinery/proc/open_machine(drop = TRUE)
SEND_SIGNAL(src, COMSIG_MACHINE_OPEN, drop)
state_open = TRUE
set_density(FALSE)
if(drop)
- dropContents()
+ dump_inventory_contents()
update_icon()
updateUsrDialog()
ui_update()
-/obj/machinery/proc/dropContents(list/subset = null)
- var/turf/T = get_turf(src)
- for(var/atom/movable/A in contents)
- if(subset && !(A in subset))
- continue
- A.forceMove(T)
- if(isliving(A))
- var/mob/living/L = A
- L.update_mobility()
+/**
+ * Drop every movable atom in the machine's contents list, including any components and circuit.
+ */
+/obj/machinery/dump_contents()
+ // Start by calling the dump_inventory_contents proc. Will allow machines with special contents
+ // to handle their dropping.
+ dump_inventory_contents()
+
+ // Then we can clean up and drop everything else.
+ var/turf/this_turf = get_turf(src)
+ for(var/atom/movable/movable_atom in contents)
+ movable_atom.forceMove(this_turf)
+
+ // We'll have dropped the occupant, circuit and component parts as part of this.
set_occupant(null)
+ circuit = null
+ LAZYCLEARLIST(component_parts)
+
+/**
+ * Drop every movable atom in the machine's contents list that is not a component_part.
+ *
+ * Proc does not drop components and will skip over anything in the component_parts list.
+ * Call dump_contents() to drop all contents including components.
+ * Arguments:
+ * * subset - If this is not null, only atoms that are also contained within the subset list will be dropped.
+ */
+/obj/machinery/proc/dump_inventory_contents(list/subset = null)
+ var/turf/this_turf = get_turf(src)
+ for(var/atom/movable/movable_atom in contents)
+ if(subset && !(movable_atom in subset))
+ continue
+
+ if(movable_atom in component_parts)
+ continue
+
+ movable_atom.forceMove(this_turf)
+ if(isliving(movable_atom))
+ var/mob/living/living_mob = movable_atom
+ living_mob.update_mobility()
+
+ if(occupant == movable_atom)
+ occupant = null
/obj/machinery/proc/can_be_occupant(atom/movable/am)
return occupant_typecache ? is_type_in_typecache(am, occupant_typecache) : isliving(am)
@@ -461,14 +498,18 @@ Class Procs:
deconstruct(TRUE)
/obj/machinery/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- on_deconstruction()
- if(component_parts?.len)
- spawn_frame(disassembled)
- for(var/obj/item/I in component_parts)
- I.forceMove(loc)
- component_parts.Cut()
- qdel(src)
+ if(flags_1 & NODECONSTRUCT_1)
+ return ..()
+
+ on_deconstruction()
+ if(!LAZYLEN(component_parts))
+ return ..() //We have no parts
+ spawn_frame(disassembled)
+
+ for(var/obj/item/I in component_parts)
+ I.forceMove(loc)
+ LAZYCLEARLIST(component_parts)
+ return ..()
/**
* Spawns a frame where this machine is. If the machine was not disassmbled, the
@@ -514,6 +555,17 @@ Class Procs:
if(A == occupant)
set_occupant(null)
update_icon()
+ updateUsrDialog()
+ return ..()
+
+ // The circuit should also be in component parts, so don't early return.
+ if(A == circuit)
+ circuit = null
+ if((A in component_parts) && !QDELETED(src))
+ component_parts.Remove(A)
+ // It would be unusual for a component_part to be qdel'd ordinarily.
+ deconstruct(FALSE)
+ return ..()
/obj/machinery/run_obj_armor(damage_amount, damage_type, damage_flag = NONE, attack_dir)
if(damage_flag == MELEE && damage_amount < damage_deflection)
@@ -632,7 +684,7 @@ Class Procs:
else
if(SEND_SIGNAL(W, COMSIG_TRY_STORAGE_TAKE, B, src))
component_parts += B
- B.moveToNullspace()
+ B.forceMove(src)
SEND_SIGNAL(W, COMSIG_TRY_STORAGE_INSERT, A, null, null, TRUE)
component_parts -= A
to_chat(user, "[capitalize(A.name)] replaced with [B.name].")
@@ -697,6 +749,9 @@ Class Procs:
. = ..()
if (gone == occupant)
set_occupant(null)
+ if(gone == circuit)
+ LAZYREMOVE(component_parts, gone)
+ circuit = null
/obj/machinery/proc/adjust_item_drop_location(atom/movable/AM) // Adjust item drop location to a 3x3 grid inside the tile, returns slot id from 0 to 8
var/md5 = rustg_hash_string(RUSTG_HASH_MD5, AM.name) // Oh, and it's deterministic too. A specific item will always drop from the same slot.
diff --git a/code/game/machinery/computer/_computer.dm b/code/game/machinery/computer/_computer.dm
index cde2b1c065c68..6c9a9abf01450 100644
--- a/code/game/machinery/computer/_computer.dm
+++ b/code/game/machinery/computer/_computer.dm
@@ -28,18 +28,13 @@
///Should the [icon_state]_broken overlay be shown as an emissive or regular overlay?
var/broken_overlay_emissive = FALSE
-/obj/machinery/computer/Initialize(mapload, obj/item/circuitboard/C)
+/obj/machinery/computer/Initialize(mapload)
. = ..()
QUEUE_SMOOTH(src)
QUEUE_SMOOTH_NEIGHBORS(src)
power_change()
- if(!QDELETED(C))
- qdel(circuit)
- circuit = C
- C.moveToNullspace()
/obj/machinery/computer/Destroy()
- QDEL_NULL(circuit)
QUEUE_SMOOTH_NEIGHBORS(src)
return ..()
@@ -149,6 +144,8 @@
var/obj/structure/frame/computer/A = new /obj/structure/frame/computer(src.loc)
A.setDir(dir)
A.circuit = circuit
+ // Circuit removal code is handled in /obj/machinery/Exited()
+ circuit.forceMove(A)
A.setAnchored(TRUE)
if(machine_stat & BROKEN)
if(user)
@@ -164,7 +161,6 @@
to_chat(user, "You disconnect the monitor.")
A.state = 4
A.icon_state = "4"
- circuit = null
for(var/obj/C in src)
C.forceMove(loc)
qdel(src)
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 758be27d3c8da..bdfa906a18bd7 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -88,17 +88,16 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list(
return
/obj/machinery/computer/arcade/Initialize(mapload)
- . = ..()
// If it's a generic arcade machine, pick a random arcade
- // circuit board for it and make the new machine
+ // circuit board for it
if(!circuit)
var/list/gameodds = list(/obj/item/circuitboard/computer/arcade/battle = 49,
/obj/item/circuitboard/computer/arcade/orion_trail = 49,
/obj/item/circuitboard/computer/arcade/amputation = 2)
- var/thegame = pick_weight(gameodds)
- var/obj/item/circuitboard/CB = new thegame()
- new CB.build_path(loc, CB)
- return INITIALIZE_HINT_QDEL
+ circuit = pick_weight(gameodds)
+
+ . = ..()
+
Reset()
/obj/machinery/computer/arcade/proc/prizevend(mob/user)
diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm
index af5eb0246e729..e8c647db1ec4b 100644
--- a/code/game/machinery/computer/buildandrepair.dm
+++ b/code/game/machinery/computer/buildandrepair.dm
@@ -109,9 +109,45 @@
if(P.tool_behaviour == TOOL_SCREWDRIVER)
P.play_tool_sound(src)
to_chat(user, "You connect the monitor.")
- var/obj/B = new circuit.build_path (loc, circuit)
- B.setDir(dir)
- transfer_fingerprints_to(B)
+
+ var/obj/machinery/new_machine = new circuit.build_path(loc)
+ new_machine.setDir(dir)
+ transfer_fingerprints_to(new_machine)
+
+ if(istype(new_machine, /obj/machinery/computer))
+ var/obj/machinery/computer/new_computer = new_machine
+
+ // Machines will init with a set of default components.
+ // Triggering handle_atom_del will make the machine realise it has lost a component_parts and then deconstruct.
+ // Move to nullspace so we don't trigger handle_atom_del, then qdel.
+ // Finally, replace new machine's parts with this frame's parts.
+ if(new_computer.circuit)
+ // Move to nullspace and delete.
+ new_computer.circuit.moveToNullspace()
+ QDEL_NULL(new_computer.circuit)
+ for(var/old_part in new_computer.component_parts)
+ var/atom/movable/movable_part = old_part
+ // Move to nullspace and delete.
+ movable_part.moveToNullspace()
+ qdel(movable_part)
+
+ // Set anchor state and move the frame's parts over to the new machine.
+ // Then refresh parts and call on_construction().
+ new_computer.anchored = anchored
+ new_computer.component_parts = list()
+
+ circuit.forceMove(new_computer)
+ new_computer.component_parts += circuit
+ new_computer.circuit = circuit
+
+ for(var/new_part in src)
+ var/atom/movable/movable_part = new_part
+ movable_part.forceMove(new_computer)
+ new_computer.component_parts += movable_part
+
+ new_computer.RefreshParts()
+ new_computer.on_construction()
+
qdel(src)
return
if(user.a_intent == INTENT_HARM)
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index fe67fb7878ebf..caac7581b2adf 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -172,27 +172,42 @@
return
if(P.tool_behaviour == TOOL_SCREWDRIVER)
- var/component_check = 1
+ var/component_check = TRUE
for(var/R in req_components)
if(req_components[R] > 0)
- component_check = 0
+ component_check = FALSE
break
if(component_check)
P.play_tool_sound(src)
var/obj/machinery/new_machine = new circuit.build_path(loc)
- if(new_machine.circuit)
- QDEL_NULL(new_machine.circuit)
- new_machine.circuit = circuit
- new_machine.setAnchored(anchored)
- new_machine.on_construction()
- for(var/obj/O in new_machine.component_parts)
- qdel(O)
- new_machine.component_parts = list()
- for(var/obj/O in src)
- O.moveToNullspace()
- new_machine.component_parts += O
- circuit.moveToNullspace()
- new_machine.RefreshParts()
+ if(istype(new_machine))
+ // Machines will init with a set of default components. Move to nullspace so we don't trigger handle_atom_del, then qdel.
+ // Finally, replace with this frame's parts.
+ if(new_machine.circuit)
+ // Move to nullspace and delete.
+ new_machine.circuit.moveToNullspace()
+ QDEL_NULL(new_machine.circuit)
+ for(var/obj/old_part in new_machine.component_parts)
+ // Move to nullspace and delete.
+ old_part.moveToNullspace()
+ qdel(old_part)
+
+ // Set anchor state and move the frame's parts over to the new machine.
+ // Then refresh parts and call on_construction().
+
+ new_machine.anchored = anchored
+ new_machine.component_parts = list()
+
+ circuit.forceMove(new_machine)
+ new_machine.component_parts += circuit
+ new_machine.circuit = circuit
+
+ for(var/obj/new_part in src)
+ new_part.forceMove(new_machine)
+ new_machine.component_parts += new_part
+ new_machine.RefreshParts()
+
+ new_machine.on_construction()
qdel(src)
return
@@ -232,6 +247,7 @@
S.merge(NS)
if(!QDELETED(part)) //If we're a stack and we merged we might not exist anymore
components += part
+ part.forceMove(src)
to_chat(user, "You add [part] to [src].")
if(added_components.len)
replacer.play_rped_sound()
diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm
index 08df28c3d5b42..3f286fac82848 100644
--- a/code/game/machinery/suit_storage_unit.dm
+++ b/code/game/machinery/suit_storage_unit.dm
@@ -173,7 +173,7 @@
/obj/machinery/suit_storage_unit/Destroy()
QDEL_NULL(wires)
- dump_contents()
+ dump_inventory_contents()
return ..()
/obj/machinery/suit_storage_unit/update_overlays()
@@ -212,7 +212,7 @@
. = ..()
if(!is_operational && state_open)
open_machine()
- dump_contents()
+ dump_inventory_contents()
update_appearance()
/obj/machinery/suit_storage_unit/RefreshParts()
@@ -222,8 +222,8 @@
laser_strength_hacked = 15 + (5 * (calculated_laser_rating)) //20 on T1, 35 on T4
laser_strength = 12 - (2 * (calculated_laser_rating)) //10 on T1, 4 on T4
-/obj/machinery/suit_storage_unit/proc/dump_contents()
- dropContents()
+/obj/machinery/suit_storage_unit/dump_inventory_contents()
+ . = ..()
helmet = null
suit = null
mask = null
@@ -246,7 +246,7 @@
/obj/machinery/suit_storage_unit/deconstruct(disassembled = TRUE)
if(!(flags_1 & NODECONSTRUCT_1))
open_machine()
- dump_contents()
+ dump_inventory_contents()
spawn_frame(disassembled)
for(var/obj/item/I in component_parts)
I.forceMove(loc)
@@ -456,7 +456,7 @@
qdel(contamination)
open_machine(FALSE)
if(mob_occupant)
- dump_contents()
+ dump_inventory_contents()
/obj/machinery/suit_storage_unit/proc/shock(mob/user, prb)
if(!prob(prb))
@@ -473,12 +473,12 @@
to_chat(user, "[src]'s door won't budge!")
return
open_machine()
- dump_contents()
+ dump_inventory_contents()
/obj/machinery/suit_storage_unit/container_resist(mob/living/user)
if(!locked)
open_machine()
- dump_contents()
+ dump_inventory_contents()
return
user.changeNext_move(CLICK_CD_BREAKOUT)
user.last_special = world.time + CLICK_CD_BREAKOUT
@@ -492,7 +492,7 @@
"You successfully break out of [src]!")
locked = FALSE
open_machine()
- dump_contents()
+ dump_inventory_contents()
add_fingerprint(user)
@@ -512,8 +512,8 @@
else
I.play_tool_sound(src, 50)
visible_message("[user] pulls out the contents of [src] outside!", "You pull [src]'s contents outside!")
- dump_contents()
- update_appearance()
+ dump_inventory_contents()
+ update_icon()
return
if(state_open && is_operational)
if(istype(I, /obj/item/clothing/suit))
@@ -559,7 +559,7 @@
if(default_deconstruction_crowbar(I))
return
if(default_pry_open(I))
- dump_contents()
+ dump_inventory_contents()
return
return ..()
diff --git a/code/game/machinery/teleporter.dm b/code/game/machinery/teleporter.dm
index 7588bd6d19a83..b88c15bb69f28 100644
--- a/code/game/machinery/teleporter.dm
+++ b/code/game/machinery/teleporter.dm
@@ -103,10 +103,10 @@
/obj/machinery/teleport/hub/syndicate/Initialize(mapload)
. = ..()
- component_parts += new /obj/item/stock_parts/matter_bin/super(null)
+ var/obj/item/stock_parts/matter_bin/super/super_bin = new(src)
+ LAZYADD(component_parts, super_bin)
RefreshParts()
-
/obj/machinery/teleport/station
name = "teleporter station"
desc = "The power control station for a bluespace teleporter. Used for toggling power, and can activate a test-fire to prevent malfunctions."
diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm
index 8c1b92172b827..aa09a4dac3d94 100644
--- a/code/game/objects/items/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/circuitboards/circuitboard.dm
@@ -16,6 +16,28 @@
var/build_path = null
/obj/item/circuitboard/proc/apply_default_parts(obj/machinery/M)
+ if(LAZYLEN(M.component_parts))
+ // This really shouldn't happen. If it somehow does, print out a stack trace and gracefully handle it.
+ stack_trace("apply_defauly_parts called on machine that already had component_parts: [M]")
+
+ // Move to nullspace so you don't trigger handle_atom_del logic and remove existing parts.
+ for(var/obj/item/part in M.component_parts)
+ part.moveToNullspace(loc)
+ qdel(part)
+
+ // List of components always contains the circuit board used to build it.
+ M.component_parts = list(src)
+ forceMove(M)
+
+ if(M.circuit != src)
+ // This really shouldn't happen. If it somehow does, print out a stack trace and gracefully handle it.
+ stack_trace("apply_default_parts called from a circuit board that does not belong to machine: [M]")
+
+ // Move to nullspace so you don't trigger handle_atom_del logic, remove old circuit, add new circuit.
+ M.circuit.moveToNullspace()
+ qdel(M.circuit)
+ M.circuit = src
+
return
// Circuitboard/machine
@@ -36,8 +58,7 @@ micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
if(!req_components)
return
- M.component_parts = list(src) // List of components always contains a board
- moveToNullspace()
+ . = ..()
for(var/comp_path in req_components)
var/comp_amt = req_components[comp_path]
@@ -48,10 +69,10 @@ micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells.
comp_path = def_components[comp_path]
if(ispath(comp_path, /obj/item/stack))
- M.component_parts += new comp_path(null, comp_amt)
+ M.component_parts += new comp_path(M, comp_amt)
else
for(var/i in 1 to comp_amt)
- M.component_parts += new comp_path(null)
+ M.component_parts += new comp_path(M)
M.RefreshParts()
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 167899620ac9c..2b46d8dc41960 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -419,6 +419,10 @@
/obj/proc/on_object_saved(var/depth = 0)
return ""
+// Should move all contained objects to it's location.
+/obj/proc/dump_contents()
+ CRASH("Unimplemented.")
+
/obj/handle_ricochet(obj/projectile/P)
. = ..()
if(. && ricochet_damage_mod)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 0c2d20f5d8344..d70ade784ac5b 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -173,7 +173,7 @@
return FALSE
return TRUE
-/obj/structure/closet/proc/dump_contents()
+/obj/structure/closet/dump_contents()
// Generate the contents if we haven't already
if (!contents_initialised)
PopulateContents()
diff --git a/code/modules/antagonists/swarmer/swarmer.dm b/code/modules/antagonists/swarmer/swarmer.dm
index 4a67870fee818..82d5f97117944 100644
--- a/code/modules/antagonists/swarmer/swarmer.dm
+++ b/code/modules/antagonists/swarmer/swarmer.dm
@@ -528,7 +528,7 @@
N.pixel_x = target.pixel_x
N.pixel_y = target.pixel_y
N.pixel_z = target.pixel_z
- target.dropContents()
+ target.dump_contents()
if(istype(target, /obj/machinery/computer))
var/obj/machinery/computer/C = target
if(C.circuit)
diff --git a/code/modules/atmospherics/machinery/atmosmachinery.dm b/code/modules/atmospherics/machinery/atmosmachinery.dm
index 73e6fb5c1b596..2a7638cd6222a 100644
--- a/code/modules/atmospherics/machinery/atmosmachinery.dm
+++ b/code/modules/atmospherics/machinery/atmosmachinery.dm
@@ -70,7 +70,6 @@
SSair.stop_processing_machine(src)
SSair.pipenets_needing_rebuilt -= src
- dropContents()
if(pipe_vision_img)
qdel(pipe_vision_img)
diff --git a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
index 467773a175272..f00ab5cd9f7c6 100644
--- a/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
+++ b/code/modules/atmospherics/machinery/components/binary_devices/circulator.dm
@@ -15,6 +15,7 @@
density = TRUE
+ circuit = /obj/item/circuitboard/machine/circulator
var/flipped = 0
var/mode = CIRCULATOR_HOT
@@ -24,10 +25,6 @@
/obj/machinery/atmospherics/components/binary/circulator/cold
mode = CIRCULATOR_COLD
-/obj/machinery/atmospherics/components/binary/circulator/Initialize(mapload)
- .=..()
- component_parts = list(new /obj/item/circuitboard/machine/circulator)
-
/obj/machinery/atmospherics/components/binary/circulator/ComponentInitialize()
. = ..()
AddComponent(/datum/component/simple_rotation,ROTATION_ALTCLICK | ROTATION_CLOCKWISE | ROTATION_COUNTERCLOCKWISE | ROTATION_VERBS )
diff --git a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
index 6f275fc30bd10..8a32770671cbe 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/deep_fryer.dm
@@ -32,6 +32,7 @@ God bless America.
use_power = IDLE_POWER_USE
idle_power_usage = 5
layer = BELOW_OBJ_LAYER
+ circuit = /obj/item/circuitboard/machine/deep_fryer
var/obj/item/food/deepfryholder/frying //What's being fried RIGHT NOW?
var/cook_time = 0
var/oil_use = 0.025 //How much cooking oil is used per second
@@ -58,10 +59,6 @@ God bless America.
. = ..()
create_reagents(50, OPENCONTAINER)
reagents.add_reagent(/datum/reagent/consumable/cooking_oil, 25)
- component_parts = list()
- component_parts += new /obj/item/circuitboard/machine/deep_fryer(null)
- component_parts += new /obj/item/stock_parts/micro_laser(null)
- RefreshParts()
fry_loop = new(src, FALSE)
/obj/machinery/deepfryer/Destroy()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
index 4ac915e0d52c1..e835d08b41dbe 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/gibber.dm
@@ -132,7 +132,7 @@
return
/obj/machinery/gibber/proc/go_out()
- dropContents()
+ dump_inventory_contents()
update_icon()
/obj/machinery/gibber/proc/startgibbing(mob/user)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
index 06b94e2fe9941..1a6f1a78569fc 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/microwave.dm
@@ -324,11 +324,14 @@
if(prob(max(iron / 2, 33)))
explosion(loc, 0, 1, 2)
else
- dropContents(ingredients)
- ingredients.Cut()
+ dump_inventory_contents()
after_finish_loop()
+/obj/machinery/microwave/dump_inventory_contents()
+ . = ..()
+ ingredients.Cut()
+
/obj/machinery/microwave/proc/pre_fail()
broken = 2
spark()
diff --git a/code/modules/food_and_drinks/kitchen_machinery/processor.dm b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
index 7d4456178bf34..1661c45a71e72 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/processor.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/processor.dm
@@ -138,28 +138,21 @@
var/mob/living/L = usr
if(!(L.mobility_flags & MOBILITY_UI))
return
- empty()
+ dump_inventory_contents()
add_fingerprint(usr)
/obj/machinery/processor/container_resist(mob/living/user)
user.forceMove(drop_location())
user.visible_message("[user] crawls free of the processor!")
-/obj/machinery/processor/proc/empty()
- for (var/obj/O in src)
- O.forceMove(drop_location())
- for (var/mob/M in src)
- M.forceMove(drop_location())
-
/obj/machinery/processor/slime
name = "slime processor"
desc = "An industrial grinder with a sticker saying appropriated for science department. Keep hands clear of intake area while operating."
+ circuit = /obj/item/circuitboard/machine/processor/slime
var/sbacklogged = FALSE
/obj/machinery/processor/slime/Initialize(mapload)
. = ..()
- var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/processor/slime(null)
- B.apply_default_parts(src)
proximity_monitor = new(src, 1)
/obj/machinery/processor/slime/adjust_item_drop_location(atom/movable/AM)
diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
index 465028e272219..58ba0a587ac31 100644
--- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
+++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm
@@ -207,11 +207,15 @@
var/listofitems = list()
for (var/I in src)
+ // We do not vend our own components.
+ if(I in component_parts)
+ continue
+
var/atom/movable/O = I
if (!QDELETED(O))
- var/md5name = rustg_hash_string(RUSTG_HASH_MD5, O.name) // This needs to happen because of a bug in a TGUI component, https://github.com/ractivejs/ractive/issues/744
- if (listofitems[md5name]) // which is fixed in a version we cannot use due to ie8 incompatibility
- listofitems[md5name]["amount"]++ // The good news is, #30519 made smartfridge UIs non-auto-updating
+ var/md5name = rustg_hash_string(RUSTG_HASH_MD5, O.name)
+ if (listofitems[md5name])
+ listofitems[md5name]["amount"]++
else
listofitems[md5name] = list("name" = O.name, "type" = O.type, "amount" = 1)
sort_list(listofitems)
@@ -240,23 +244,28 @@
if (params["amount"])
desired = text2num(params["amount"])
else
- desired = input("How many items?", "How many items would you like to take out?", 1) as null|num
-
- if(!isnum_safe(desired) || desired <= 0)
- return
+ desired = tgui_input_number(usr, "How many items would you like to take out?", "Release", max_value = 50)
+ if(!desired)
+ return FALSE
if(QDELETED(src) || QDELETED(usr) || !usr.Adjacent(src)) // Sanity checkin' in case stupid stuff happens while we wait for input()
- return
+ return FALSE
- for(var/obj/item/O in src)
- if(O.name == params["name"])
- dispense(O, usr)
+ for(var/obj/item/dispensed_item in src)
+ if(desired <= 0)
+ break
+ // Grab the first item in contents which name matches our passed name.
+ // format_text() is used here to strip \improper and \proper from both names,
+ // which is required for correct string comparison between them.
+ if(format_text(dispensed_item.name) == format_text(params["name"]))
+ if(dispensed_item in component_parts)
+ CRASH("Attempted removal of [dispensed_item] component_part from smartfridge via smartfridge interface.")
+ dispense(dispensed_item, usr)
desired--
- . = TRUE
- if(desired <= 0)
- break
- if (visible_contents && .)
- update_icon()
+
+ if (visible_contents)
+ update_appearance()
+ return TRUE
// ----------------------------
@@ -273,9 +282,16 @@
/obj/machinery/smartfridge/drying_rack/Initialize(mapload)
. = ..()
- if(component_parts?.len)
- component_parts.Cut()
+
+ // Cache the old_parts first, we'll delete it after we've changed component_parts to a new list.
+ // This stops handle_atom_del being called on every part when not necessary.
+ var/list/old_parts = component_parts
+
component_parts = null
+ circuit = null
+
+ QDEL_LIST(old_parts)
+ RefreshParts()
/obj/machinery/smartfridge/drying_rack/on_deconstruction()
new /obj/item/stack/sheet/wood(drop_location(), 10)
diff --git a/code/modules/power/generator.dm b/code/modules/power/generator.dm
index c946ed48ea494..d63902f719e78 100644
--- a/code/modules/power/generator.dm
+++ b/code/modules/power/generator.dm
@@ -5,6 +5,8 @@
density = TRUE
use_power = NO_POWER_USE
+ circuit = /obj/item/circuitboard/machine/generator
+
var/obj/machinery/atmospherics/components/binary/circulator/cold_circ
var/obj/machinery/atmospherics/components/binary/circulator/hot_circ
@@ -19,7 +21,6 @@
connect_to_network()
SSair.start_processing_machine(src)
update_appearance()
- component_parts = list(new /obj/item/circuitboard/machine/generator)
/obj/machinery/power/generator/examine()
. = ..()
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index 8f1e9728edaba..3c48bb80900bc 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -483,7 +483,7 @@
/datum/reagent/toxin/staminatoxin
)
-/obj/machinery/chem_dispenser/drinks/fullupgrade //fully ugpraded stock parts, emagged
+/obj/machinery/chem_dispenser/drinks/fullupgrade //fully upgraded stock parts, emagged
desc = "Contains a large reservoir of soft drinks. This model has had its safeties shorted out."
obj_flags = CAN_BE_HIT | EMAGGED
flags_1 = NODECONSTRUCT_1
diff --git a/code/modules/research/server.dm b/code/modules/research/server.dm
index 0acd6edf9a73c..2ea70ed407f99 100644
--- a/code/modules/research/server.dm
+++ b/code/modules/research/server.dm
@@ -47,8 +47,6 @@
name += " [uppertext(num2hex(server_id, -1))]" //gives us a random four-digit hex number as part of the name. Y'know, for fluff.
SSresearch.servers |= src
stored_research = SSresearch.science_tech
- var/obj/item/circuitboard/machine/B = new /obj/item/circuitboard/machine/rdserver(null)
- B.apply_default_parts(src)
// The +10 is so the sparks work
RefreshParts()
diff --git a/code/modules/vending/cola.dm b/code/modules/vending/cola.dm
index 132e1053efe64..5c42add675a49 100644
--- a/code/modules/vending/cola.dm
+++ b/code/modules/vending/cola.dm
@@ -32,9 +32,12 @@
name = "\improper Random Drinkies"
icon_state = "random_cola"
desc = "Uh oh!"
+ circuit = null
/obj/machinery/vending/cola/random/Initialize(mapload)
- ..()
+ // No need to call parent, we're not doing anything with this machine. Just picking a new type of machine to use, spawning it and deleting ourselves.
+ SHOULD_CALL_PARENT(FALSE)
+
var/T = pick(subtypesof(/obj/machinery/vending/cola) - /obj/machinery/vending/cola/random)
new T(loc)
return INITIALIZE_HINT_QDEL
diff --git a/code/modules/vending/snack.dm b/code/modules/vending/snack.dm
index 2da0dfe0a006d..981f8110d34db 100644
--- a/code/modules/vending/snack.dm
+++ b/code/modules/vending/snack.dm
@@ -92,9 +92,12 @@
name = "\improper Random Snackies"
icon_state = "random_snack"
desc = "Uh oh!"
+ circuit = null
/obj/machinery/vending/snack/random/Initialize(mapload)
- ..()
+ // No need to call parent, we're not doing anything with this machine. Just picking a new type of machine to use, spawning it and deleting ourselves.
+ SHOULD_CALL_PARENT(FALSE)
+
var/T = pick(subtypesof(/obj/machinery/vending/snack) - /obj/machinery/vending/snack/random)
new T(loc)
return INITIALIZE_HINT_QDEL