diff --git a/code/game/machinery/computer/buildandrepair.dm b/code/game/machinery/computer/buildandrepair.dm index 66a66efe991..556847b2477 100644 --- a/code/game/machinery/computer/buildandrepair.dm +++ b/code/game/machinery/computer/buildandrepair.dm @@ -113,9 +113,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) - 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.set_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 58f3eaf7f62..7d0e787e6ce 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -185,25 +185,33 @@ P.play_tool_sound(src) var/obj/machinery/new_machine = new circuit.build_path(loc) if(istype(new_machine)) - // Machines will init with a set of default components. Move to nullspace to we don't trigger handle_atom_del, then qdel. + // 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) - circuit.forceMove(new_machine) - new_machine.circuit = circuit - new_machine.set_anchored(anchored) - new_machine.on_construction() 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.set_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 diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm index e4c5549cb8e..be2112fb719 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 - forceMove(M) + . = ..() for(var/comp_path in req_components) var/comp_amt = req_components[comp_path] diff --git a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm index 050bfa19ab0..29f38c66189 100644 --- a/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/kitchen_machinery/smartfridge.dm @@ -173,6 +173,10 @@ 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 = md5(O.name) // This needs to happen because of a bug in a TGUI component, https://github.com/ractivejs/ractive/issues/744 @@ -213,6 +217,8 @@ if(desired == 1 && Adjacent(usr) && !issilicon(usr)) for(var/obj/item/O in src) if(O.name == params["name"]) + if(O in component_parts) + CRASH("Attempted removal of [O] component_part from vending machine via vending interface.") dispense(O, usr) break if (visible_contents) @@ -223,6 +229,8 @@ if(desired <= 0) break if(O.name == params["name"]) + if(O in component_parts) + CRASH("Attempted removal of [O] component_part from vending machine via vending interface.") dispense(O, usr) desired-- if (visible_contents)