From 0fb5a097e03ec6575b6511ccefac2383241bcf22 Mon Sep 17 00:00:00 2001 From: Sierra Helper <125094432+SierraHelper@users.noreply.github.com> Date: Tue, 26 Nov 2024 16:54:40 +0300 Subject: [PATCH] [MIRROR] Click Refactor - Machinery States (#2860) Co-authored-by: SierraKomodo <11140088+SierraKomodo@users.noreply.github.com> Co-authored-by: Lexanx <61974560+Lexanx@users.noreply.github.com> --- .../machine_construction/_construction.dm | 20 +- .../machine_construction/computer.dm | 2 +- .../machine_construction/default.dm | 84 +++++--- .../machine_construction/frame.dm | 183 ++++++++++++------ .../machine_construction/item_chassis.dm | 15 +- .../machine_construction/tcomms.dm | 146 +++++++++----- .../_machines_base/machinery_components.dm | 119 +++++++----- 7 files changed, 385 insertions(+), 184 deletions(-) diff --git a/code/game/machinery/_machines_base/machine_construction/_construction.dm b/code/game/machinery/_machines_base/machine_construction/_construction.dm index 05f5bffc1a37d..fd2d6093feb34 100644 --- a/code/game/machinery/_machines_base/machine_construction/_construction.dm +++ b/code/game/machinery/_machines_base/machine_construction/_construction.dm @@ -78,15 +78,23 @@ machine.attack_hand(user) return TRUE -/* -This returning FALSE means if component_attackby under use_tool called this it will also return FALSE; which means the use_tool call will proceed. -In that same vein, the attackby() children of this proc will also continue the rest of its code if this crashes; since this check is called at the beginning. -*/ -/singleton/machine_construction/proc/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(!validate_state(machine)) + +/** + * Handles tool usage on the parent machine. Has the same return rules as `/atom/proc/use_tool()`. + * + * **Parameters**: + * - `tool` - The item being used. + * - `user` - The mob performing the interaction. + * - `machine` - The parent machine being interacted with. + * + * Returns boolean. Indicates whether the interaction was handled or not. If `TRUE`, no other interactions will occur. + */ +/singleton/machine_construction/proc/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + if (!validate_state(machine)) crash_with("Machine [log_info_line(machine)] violated the state assumptions of the construction state [type]!") return FALSE + /singleton/machine_construction/proc/mechanics_info() // Used to transfer state as needed post-construction. diff --git a/code/game/machinery/_machines_base/machine_construction/computer.dm b/code/game/machinery/_machines_base/machine_construction/computer.dm index 7e6baff142488..5c1cf86865782 100644 --- a/code/game/machinery/_machines_base/machine_construction/computer.dm +++ b/code/game/machinery/_machines_base/machine_construction/computer.dm @@ -4,7 +4,7 @@ down_state = /singleton/machine_construction/default/panel_open/computer needs_board = "computer" -/singleton/machine_construction/default/panel_closed/computer/no_deconstruct/attackby(obj/item/I, mob/user, obj/machinery/machine) +/singleton/machine_construction/default/panel_closed/computer/no_deconstruct/use_tool(obj/item/tool, mob/user, obj/machinery/machine) return FALSE /singleton/machine_construction/default/panel_open/computer diff --git a/code/game/machinery/_machines_base/machine_construction/default.dm b/code/game/machinery/_machines_base/machine_construction/default.dm index 1429da282eb74..b08baa12fba8b 100644 --- a/code/game/machinery/_machines_base/machine_construction/default.dm +++ b/code/game/machinery/_machines_base/machine_construction/default.dm @@ -5,8 +5,10 @@ var/up_state var/down_state -/singleton/machine_construction/default/no_deconstruct/attackby(obj/item/I, mob/user, obj/machinery/machine) - . = FALSE + +/singleton/machine_construction/default/no_deconstruct/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + return FALSE + /singleton/machine_construction/default/panel_closed down_state = /singleton/machine_construction/default/panel_open @@ -19,23 +21,38 @@ if(!.) try_change_state(machine, down_state) -/singleton/machine_construction/default/panel_closed/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) - return + +/singleton/machine_construction/default/panel_closed/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + . = ..() + if (.) + return TRUE + if (!machine.can_use_tools) - to_chat(user, SPAN_WARNING("\The [src] cannot be modified!")) + USE_FEEDBACK_FAILURE("\The [src] cannot be modified.") return TRUE - if(isScrewdriver(I)) + + // Screwdriver - Open maintenance panel + if (isScrewdriver(tool)) TRANSFER_STATE(down_state) - playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) + playsound(machine, 'sound/items/Screwdriver.ogg', 50, TRUE) machine.panel_open = TRUE - to_chat(user, SPAN_NOTICE("You open the maintenance hatch of \the [machine].")) + user.visible_message( + SPAN_NOTICE("\The [user] opens \a [machine]'s maintenance panel with \a [tool]."), + SPAN_NOTICE("You open \the [machine]'s maintenance panel with \the [tool].") + ) machine.update_icon() - return - if(istype(I, /obj/item/storage/part_replacer)) + return TRUE + + // Part Replacer - List parts. + if (istype(tool, /obj/item/storage/part_replacer)) + user.visible_message( + SPAN_NOTICE("\The [user] scans \a [machine] with \a [tool]."), + SPAN_NOTICE("You scan \the [machine] with \the [tool].") + ) machine.display_parts(user) return TRUE + /singleton/machine_construction/default/panel_closed/post_construct(obj/machinery/machine) try_change_state(machine, down_state) machine.panel_open = TRUE @@ -61,29 +78,46 @@ if(!.) try_change_state(machine, up_state) -/singleton/machine_construction/default/panel_open/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) + +/singleton/machine_construction/default/panel_open/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + . = ..() + if (.) return - if(isCrowbar(I)) + + // Crowbar - Dismantle machine. + if (isCrowbar(tool)) TRANSFER_STATE(down_state) + user.visible_message( + SPAN_NOTICE("\The [user] dismantles \a [machine] with \a [tool]."), + SPAN_NOTICE("You dismantle \the [machine] with \the [tool].") + ) machine.dismantle() - return - if(isScrewdriver(I)) + return TRUE + + // Screwdriver - Close panel. + if (isScrewdriver(tool)) TRANSFER_STATE(up_state) - playsound(get_turf(machine), 'sound/items/Screwdriver.ogg', 50, 1) + playsound(machine, 'sound/items/Screwdriver.ogg', 50, TRUE) machine.panel_open = FALSE - to_chat(user, SPAN_NOTICE("You close the maintenance hatch of \the [machine].")) + user.visible_message( + SPAN_NOTICE("\The [user] closes \a [machine]'s maintenance hatch with \a [tool]."), + SPAN_NOTICE("You close \the [machine]'s maintenance panel with \the [tool].") + ) machine.update_icon() - return + return TRUE + + // Part replacer - Replace parts. + if (istype(tool, /obj/item/storage/part_replacer)) + return machine.part_replacement(user, tool) - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(user, I) + // Wrench - Remove individual part. + if (isWrench(tool)) + return machine.part_removal(user, tool) - if(isWrench(I)) - return machine.part_removal(user) + // Items - Attempt part insertion. + if (istype(tool)) + return machine.part_insertion(user, tool) - if(istype(I)) - return machine.part_insertion(user, I) /singleton/machine_construction/default/panel_open/mechanics_info() . = list() diff --git a/code/game/machinery/_machines_base/machine_construction/frame.dm b/code/game/machinery/_machines_base/machine_construction/frame.dm index 268b709d7194e..3c70256df2499 100644 --- a/code/game/machinery/_machines_base/machine_construction/frame.dm +++ b/code/game/machinery/_machines_base/machine_construction/frame.dm @@ -11,24 +11,46 @@ else try_change_state(machine, /singleton/machine_construction/frame/wrenched) -/singleton/machine_construction/frame/unwrenched/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) - playsound(machine.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, (I.toolspeed * 2) SECONDS, machine, DO_REPAIR_CONSTRUCT)) - TRANSFER_STATE(/singleton/machine_construction/frame/wrenched) - to_chat(user, SPAN_NOTICE("You wrench \the [machine] into place.")) - machine.anchored = TRUE - if(isWelder(I)) - var/obj/item/weldingtool/WT = I - if(!WT.can_use(3, user)) + +/singleton/machine_construction/frame/unwrenched/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + // Wrench - Anchor machine. + if (isWrench(tool)) + user.visible_message( + SPAN_NOTICE("\The [user] begins securing \the [machine] to the floor with \a [tool]."), + SPAN_NOTICE("You begin securing \the [machine] to the floor with \the [tool].") + ) + playsound(machine, 'sound/items/Ratchet.ogg', 50, TRUE) + if (!user.do_skilled((tool.toolspeed * 2 SECONDS), SKILL_CONSTRUCTION, machine, do_flags = DO_REPAIR_CONSTRUCT) || !user.use_sanity_check(machine, tool)) + return TRUE + TRANSFER_STATE(/singleton/machine_construction/frame/unwrenched) + user.visible_message( + SPAN_NOTICE("\The [user] secures \a [machine] to the floor with \a [tool]."), + SPAN_NOTICE("You secure \the [machine] to the floor with \the [tool].") + ) + machine.anchored = FALSE + machine.post_anchor_change() + return TRUE + + if (isWelder(tool)) + var/obj/item/weldingtool/welder = tool + if (!welder.can_use(3, user)) + return TRUE + playsound(machine, 'sound/items/Welder.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] starts dismantling \a [machine] with \a [tool]."), + SPAN_NOTICE("You start dismantling \the [machine] with \the [tool].") + ) + if (!user.do_skilled(tool.toolspeed * 2 SECONDS, SKILL_CONSTRUCTION, machine, do_flags = DO_REPAIR_CONSTRUCT) || !user.use_sanity_check(machine, tool)) + return TRUE + if (!welder.remove_fuel(3, user)) return TRUE - playsound(machine.loc, 'sound/items/Welder.ogg', 50, 1) - if(do_after(user, (I.toolspeed * 2) SECONDS, machine, DO_REPAIR_CONSTRUCT)) - if (!WT.remove_fuel(3, user)) - return TRUE - TRANSFER_STATE(/singleton/machine_construction/default/deconstructed) - to_chat(user, SPAN_NOTICE("You deconstruct \the [machine].")) - machine.dismantle() + TRANSFER_STATE(/singleton/machine_construction/default/deconstructed) + user.visible_message( + SPAN_NOTICE("\The [user] dismantles \a [machine] with \a [tool]."), + SPAN_NOTICE("You dismantle \the [machine] with \the [tool].") + ) + machine.dismantle() + return TRUE /singleton/machine_construction/frame/unwrenched/mechanics_info() @@ -47,24 +69,47 @@ else try_change_state(machine, /singleton/machine_construction/frame/unwrenched) -/singleton/machine_construction/frame/wrenched/attackby(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) - playsound(machine.loc, 'sound/items/Ratchet.ogg', 50, 1) - if(do_after(user, (I.toolspeed * 2) SECONDS, machine, DO_REPAIR_CONSTRUCT)) - TRANSFER_STATE(/singleton/machine_construction/frame/unwrenched) - to_chat(user, SPAN_NOTICE("You unfasten \the [machine].")) - machine.anchored = FALSE - return - if(isCoil(I)) - var/obj/item/stack/cable_coil/C = I - if(C.get_amount() < 5) - to_chat(user, SPAN_WARNING("You need five lengths of cable to add them to \the [machine].")) + +/singleton/machine_construction/frame/wrenched/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + // Wrench. Anchor machine. + if (isWrench(tool)) + user.visible_message( + SPAN_NOTICE("\The [user] begins unsecuring \the [machine] from the floor with \a [tool]."), + SPAN_NOTICE("You begin unsecuring \the [machine] from the floor with \the [tool].") + ) + playsound(machine, 'sound/items/Ratchet.ogg', 50, TRUE) + if (!user.do_skilled((tool.toolspeed * 2 SECONDS), SKILL_CONSTRUCTION, machine, do_flags = DO_REPAIR_CONSTRUCT) || !user.use_sanity_check(machine, tool)) return TRUE - playsound(machine.loc, 'sound/items/Deconstruct.ogg', 50, 1) - to_chat(user, SPAN_NOTICE("You start to add cables to the frame.")) - if(do_after(user, 2 SECONDS, machine, DO_REPAIR_CONSTRUCT) && C.use(5)) - TRANSFER_STATE(/singleton/machine_construction/frame/awaiting_circuit) - to_chat(user, SPAN_NOTICE("You add cables to the frame.")) + TRANSFER_STATE(/singleton/machine_construction/frame/unwrenched) + user.visible_message( + SPAN_NOTICE("\The [user] unsecures \a [machine] from the floor with \a [tool]."), + SPAN_NOTICE("You unsecure \the [machine] from the floor with \the [tool].") + ) + machine.anchored = FALSE + machine.post_anchor_change() + return TRUE + + // Cable coil. Wire machine. + if (isCoil(tool)) + var/obj/item/stack/cable_coil/cable_coil = tool + if (!cable_coil.can_use(5)) + USE_FEEDBACK_STACK_NOT_ENOUGH(cable_coil, 5, "to wire \the [machine].") + return TRUE + playsound(machine, 'sound/items/Deconstruct.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] starts wiring \a [machine] with [cable_coil.get_vague_name(TRUE)]."), + SPAN_NOTICE("You start wiring \the [machine] with [cable_coil.get_exact_name(5)].") + ) + if (!user.do_skilled(2 SECONDS, SKILL_ELECTRICAL, machine, do_flags = DO_REPAIR_CONSTRUCT) || !user.use_sanity_check(machine, tool)) + return TRUE + if (!cable_coil.use(5)) + USE_FEEDBACK_STACK_NOT_ENOUGH(cable_coil, 5, "to wire \the [machine].") + return TRUE + TRANSFER_STATE(/singleton/machine_construction/frame/awaiting_circuit) + user.visible_message( + SPAN_NOTICE("\The [user] wires \a [machine] with [cable_coil.get_vague_name(TRUE)]."), + SPAN_NOTICE("You wire \the [machine] with [cable_coil.get_exact_name(5)].") + ) return TRUE @@ -84,26 +129,38 @@ else try_change_state(machine, /singleton/machine_construction/frame/unwrenched) -/singleton/machine_construction/frame/awaiting_circuit/attackby(obj/item/I, mob/user, obj/machinery/constructable_frame/machine) - if(istype(I, /obj/item/stock_parts/circuitboard)) - var/obj/item/stock_parts/circuitboard/circuit = I - if(circuit.board_type == machine.expected_machine_type) - if(!user.canUnEquip(I)) - return FALSE - TRANSFER_STATE(/singleton/machine_construction/frame/awaiting_parts) - user.unEquip(I, machine) - playsound(machine.loc, 'sound/items/Deconstruct.ogg', 50, 1) - to_chat(user, SPAN_NOTICE("You add the circuit board to \the [machine].")) - machine.circuit = I - return - else - to_chat(user, SPAN_WARNING("This frame does not accept circuit boards of this type!")) + +/singleton/machine_construction/frame/awaiting_circuit/use_tool(obj/item/tool, mob/user, obj/machinery/constructable_frame/machine) + // Circuitboard - Install circuits. + if (istype(tool, /obj/item/stock_parts/circuitboard)) + var/obj/item/stock_parts/circuitboard/circuit = tool + if (circuit.board_type != machine.expected_machine_type) + USE_FEEDBACK_FAILURE("\The [machine] does not accept \the [circuit]'s board type.") + return TRUE + if (!user.canUnEquip(tool)) + FEEDBACK_UNEQUIP_FAILURE(user, tool) return TRUE - if(isWirecutter(I)) + TRANSFER_STATE(/singleton/machine_construction/frame/awaiting_parts) + user.unEquip(tool, machine) + playsound(machine, 'sound/items/Deconstruct.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] adds \a [tool] to \a [machine]."), + SPAN_NOTICE("You add \the [tool] to \the [machine].") + ) + machine.circuit = tool + return TRUE + + // Wirecutter - Remove wiring. + if (isWirecutter(tool)) TRANSFER_STATE(/singleton/machine_construction/frame/wrenched) - playsound(machine.loc, 'sound/items/Wirecutter.ogg', 50, 1) - to_chat(user, SPAN_NOTICE("You remove the cables.")) + playsound(machine, 'sound/items/Wirecutter.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] removes \a [machine]'s wiring with \a [tool]."), + SPAN_NOTICE("You remove \the [machine]'s wiring with \the [tool].") + ) new /obj/item/stack/cable_coil(machine.loc, 5) + return TRUE + /singleton/machine_construction/frame/awaiting_circuit/mechanics_info() . = list() @@ -121,16 +178,22 @@ else try_change_state(machine, /singleton/machine_construction/frame/unwrenched) -/singleton/machine_construction/frame/awaiting_parts/attackby(obj/item/I, mob/user, obj/machinery/constructable_frame/machine) - if(isCrowbar(I)) +/singleton/machine_construction/frame/awaiting_parts/use_tool(obj/item/tool, mob/user, obj/machinery/constructable_frame/machine) + // Crowbar. Remove circuit board. + if (isCrowbar(tool)) TRANSFER_STATE(/singleton/machine_construction/frame/awaiting_circuit) - playsound(machine.loc, 'sound/items/Crowbar.ogg', 50, 1) + playsound(machine, 'sound/items/Crowbar.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] removes \a [machine]'s circuit board with \a [tool]."), + SPAN_NOTICE("You remove \the [machine]'s [machine.circuit.name] with \the [tool].") + ) machine.circuit.dropInto(machine.loc) machine.circuit = null - to_chat(user, SPAN_NOTICE("You remove the circuit board.")) - return - if(isScrewdriver(I)) - playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) + return TRUE + + // Screwdriver. Finish construction. + if (isScrewdriver(tool)) + playsound(machine, 'sound/items/Screwdriver.ogg', 50, TRUE) var/obj/machinery/new_machine = new machine.circuit.build_path(machine.loc, machine.dir, FALSE) machine.circuit.construct(new_machine) new_machine.install_component(machine.circuit, refresh_parts = FALSE) @@ -140,6 +203,10 @@ new_machine.construct_state.post_construct(new_machine) else crash_with("Machine of type [new_machine.type] was built from a circuit and frame, but had no construct state set.") + user.visible_message( + SPAN_NOTICE("\The [user] finishes \a [new_machine] with \a [tool]."), + SPAN_NOTICE("You finish \the [new_machine] with \the [tool].") + ) qdel(machine) return TRUE diff --git a/code/game/machinery/_machines_base/machine_construction/item_chassis.dm b/code/game/machinery/_machines_base/machine_construction/item_chassis.dm index e05dfe7e583e3..b265537229e23 100644 --- a/code/game/machinery/_machines_base/machine_construction/item_chassis.dm +++ b/code/game/machinery/_machines_base/machine_construction/item_chassis.dm @@ -4,13 +4,20 @@ needs_board = null down_state = /singleton/machine_construction/default/deconstructed -/singleton/machine_construction/default/item_chassis/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) +/singleton/machine_construction/default/item_chassis/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + . = ..() + if (.) return - if(isWrench(I)) + + // Wrench - Dismantle + if (isWrench(tool)) TRANSFER_STATE(down_state) + user.visible_message( + SPAN_NOTICE("\The [user] dismantles \a [machine] with \a [tool]."), + SPAN_NOTICE("You dismantle \the [machine] with \the [tool].") + ) machine.dismantle() - return + return TRUE /singleton/machine_construction/default/item_chassis/state_is_valid(obj/machinery/machine) return TRUE diff --git a/code/game/machinery/_machines_base/machine_construction/tcomms.dm b/code/game/machinery/_machines_base/machine_construction/tcomms.dm index 9bd6e33f07038..3644322c5cedf 100644 --- a/code/game/machinery/_machines_base/machine_construction/tcomms.dm +++ b/code/game/machinery/_machines_base/machine_construction/tcomms.dm @@ -11,14 +11,23 @@ if(!.) try_change_state(machine, /singleton/machine_construction/tcomms/panel_open) -/singleton/machine_construction/tcomms/panel_closed/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) + +/singleton/machine_construction/tcomms/panel_closed/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + . = ..() + if (.) return - if(isScrewdriver(I)) + + // Screwdriver - Open panel + if (isScrewdriver(tool)) TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open) machine.panel_open = TRUE - to_chat(user, "You unfasten the bolts.") - playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) + user.visible_message( + SPAN_NOTICE("\The [user] opens \the [machine]'s panel with \a [tool]."), + SPAN_NOTICE("You open \the [machine]'s panel with \the [tool].") + ) + playsound(machine, 'sound/items/Screwdriver.ogg', 50, TRUE) + return TRUE + /singleton/machine_construction/tcomms/panel_closed/post_construct(obj/machinery/machine) try_change_state(machine, /singleton/machine_construction/tcomms/panel_open/no_cable) @@ -40,72 +49,119 @@ if(!.) try_change_state(machine, /singleton/machine_construction/tcomms/panel_closed) -/singleton/machine_construction/tcomms/panel_open/attackby(obj/item/I, mob/user, obj/machinery/machine) - if((. = ..())) + +/singleton/machine_construction/tcomms/panel_open/use_tool(obj/item/tool, mob/user, obj/machinery/machine) + . = ..() + if (.) return - return state_interactions(I, user, machine) -/singleton/machine_construction/tcomms/panel_open/proc/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isScrewdriver(I)) + return state_interactions(tool, user, machine) + + +/** + * Tool interactions specifically for tcomms sub-states. Called by `/singleton/machine_construction/tcomms/panel_open/use_tool()`. + * + * **Parameters**: + * - `tool` - The item being used. + * - `user` - The mob performing the interaction. + * - `machine` - The parent machine being interacted with. + * + * Returns boolean. Indicates whether the interaction was handled or not. If `TRUE`, no other interactions will occur. + */ +/singleton/machine_construction/tcomms/panel_open/proc/state_interactions(obj/item/tool, mob/user, obj/machinery/machine) + // Screwdriver - Close panel + if (isScrewdriver(tool)) TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_closed) machine.panel_open = FALSE - to_chat(user, "You fasten the bolts.") - playsound(machine.loc, 'sound/items/Screwdriver.ogg', 50, 1) - return - if(isWrench(I)) + user.visible_message( + SPAN_NOTICE("\The [user] closes \a [machine]'s maintenance panel with \a [tool]."), + SPAN_NOTICE("You close \the [machine]'s maintenance panel with \the [tool].") + ) + playsound(machine, 'sound/items/Screwdriver.ogg', 50, TRUE) + return TRUE + + // Wrench - Unwrench external plating + if (isWrench(tool)) TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open/unwrenched) - to_chat(user, "You dislodge the external plating.") - playsound(machine.loc, 'sound/items/Ratchet.ogg', 75, 1) + user.visible_message( + SPAN_NOTICE("\The [user] dislodges \a [machine]'s external plating with \a [tool]."), + SPAN_NOTICE("You dislodge \the [machine]'s external plating with \the [tool].") + ) + playsound(machine, 'sound/items/Ratchet.ogg', 75, TRUE) + return TRUE + /singleton/machine_construction/tcomms/panel_open/mechanics_info() . = list() . += "Use a screwdriver to close the panel." . += "Use a wrench to remove the external plating." -/singleton/machine_construction/tcomms/panel_open/unwrenched/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isWrench(I)) +/singleton/machine_construction/tcomms/panel_open/unwrenched/state_interactions(obj/item/tool, mob/user, obj/machinery/machine) + // Wrench - Secure external plating. + if (isWrench(tool)) TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open) - to_chat(user, "You secure the external plating.") - playsound(machine.loc, 'sound/items/Ratchet.ogg', 75, 1) - return - if(isWirecutter(I)) + user.visible_message( + SPAN_NOTICE("\The [user] secures \a [machine]'s external plating with \a [tool]."), + SPAN_NOTICE("You secure \the [machine]'s external plating with \the [tool].") + ) + playsound(machine, 'sound/items/Ratchet.ogg', 75, TRUE) + return TRUE + + // Wirecutter - Remove wiring. + if (isWirecutter(tool)) TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open/no_cable) - playsound(machine.loc, 'sound/items/Wirecutter.ogg', 50, 1) - to_chat(user, "You remove the cables.") - var/obj/item/stack/cable_coil/A = new /obj/item/stack/cable_coil( user.loc ) - A.amount = 5 + playsound(machine.loc, 'sound/items/Wirecutter.ogg', 50, TRUE) + user.visible_message( + SPAN_NOTICE("\The [user] removes \a [machine]'s wiring with \a [tool]."), + SPAN_NOTICE("You remove \the [machine]'s wiring with \the [tool].") + ) + new /obj/item/stack/cable_coil(get_turf(machine), 5) machine.set_broken(TRUE, TRUE) // the machine's been borked! + return TRUE /singleton/machine_construction/tcomms/panel_open/unwrenched/mechanics_info() . = list() . += "Use a wrench to secure the external plating." . += "Use wirecutters to remove the cabling." -/singleton/machine_construction/tcomms/panel_open/no_cable/state_interactions(obj/item/I, mob/user, obj/machinery/machine) - if(isCoil(I)) - var/obj/item/stack/cable_coil/A = I - if (A.can_use(5)) - TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open/unwrenched) - A.use(5) - to_chat(user, SPAN_NOTICE("You insert the cables.")) - machine.set_broken(FALSE, TRUE) // the machine's not borked anymore! - return - else - to_chat(user, SPAN_WARNING("You need five coils of wire for this.")) + +/singleton/machine_construction/tcomms/panel_open/no_cable/state_interactions(obj/item/tool, mob/user, obj/machinery/machine) + // Cable Coil - Add wiring. + if (isCoil(tool)) + var/obj/item/stack/cable_coil/cable_coil = tool + if (!cable_coil.use(5)) + USE_FEEDBACK_STACK_NOT_ENOUGH(cable_coil, 5, "to wire \the [machine].") return TRUE - if(isCrowbar(I)) + TRANSFER_STATE(/singleton/machine_construction/tcomms/panel_open/unwrenched) + user.visible_message( + SPAN_NOTICE("\The [user] wires \a [machine] with [cable_coil.get_vague_name(TRUE)]."), + SPAN_NOTICE("You wire \the [machine] with [cable_coil.get_exact_name(5)].") + ) + machine.set_broken(FALSE, TRUE) + return TRUE + + // Crowbar - Dismantle frame. + if (isCrowbar(tool)) TRANSFER_STATE(/singleton/machine_construction/default/deconstructed) + user.visible_message( + SPAN_NOTICE("\The [user] dismanles \a [machine] with \a [tool]."), + SPAN_NOTICE("You dismantle \the [machine] with \the [tool].") + ) machine.dismantle() - return + return TRUE + + // Part Replacer - Replace parts. + if (istype(tool, /obj/item/storage/part_replacer)) + return machine.part_replacement(tool, user) - if(istype(I, /obj/item/storage/part_replacer)) - return machine.part_replacement(I, user) + // Wrench - Remove individual part. + if (isWrench(tool)) + return machine.part_removal(user, tool) - if(isWrench(I)) - return machine.part_removal(user) + // Item - Attempt part insertion. + if (istype(tool)) + return machine.part_insertion(user, tool) - if(istype(I)) - return machine.part_insertion(user, I) /singleton/machine_construction/tcomms/panel_open/no_cable/mechanics_info() . = list() diff --git a/code/game/machinery/_machines_base/machinery_components.dm b/code/game/machinery/_machines_base/machinery_components.dm index e6f6037afb6a9..b22a3e7447fac 100644 --- a/code/game/machinery/_machines_base/machinery_components.dm +++ b/code/game/machinery/_machines_base/machinery_components.dm @@ -265,7 +265,7 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) continue if((. = part.use_tool(I, user))) return - return construct_state && construct_state.attackby(I, user, src) + return construct_state && construct_state.use_tool(I, user, src) /// Passes `attack_hand()` calls through to components within the machine, if they are accessible. /obj/machinery/proc/component_attack_hand(mob/user) @@ -280,52 +280,70 @@ GLOBAL_LIST_INIT(machine_path_to_circuit_type, cache_circuits_by_build_path()) Standard helpers for users interacting with machinery parts. */ + /// Handles replacement of components by a user using a part replacer. Returns boolean. /obj/machinery/proc/part_replacement(mob/user, obj/item/storage/part_replacer/part_replacer) - for(var/obj/item/stock_parts/component_part in component_parts) - if(!component_part.base_type) + . = FALSE + + for (var/obj/item/stock_parts/component_part as anything in component_parts) + if (!component_part.base_type) continue - if(!(component_part.part_flags & PART_FLAG_HAND_REMOVE)) + if (!HAS_FLAGS(component_part.part_flags, PART_FLAG_HAND_REMOVE)) continue - for(var/obj/item/stock_parts/new_component_part in part_replacer.contents) - if(istype(new_component_part, component_part.base_type) && new_component_part.rating > component_part.rating) - replace_part(user, part_replacer, component_part, new_component_part) - . = TRUE - playsound(loc, 'sound/items/rped.ogg', 70) - break + for (var/obj/item/stock_parts/new_component_part in part_replacer.contents) + if (!istype(new_component_part, component_part.base_type)) + continue + if (new_component_part.rating <= component_part.rating) + continue + replace_part(user, part_replacer, component_part, new_component_part) + . = TRUE + break - for(var/path in uncreated_component_parts) + for (var/path in uncreated_component_parts) var/obj/item/stock_parts/component_part = path var/part_count = uncreated_component_parts[path] - if(!(initial(component_part.part_flags) & PART_FLAG_HAND_REMOVE)) + if (!HAS_FLAGS(initial(component_part.part_flags), PART_FLAG_HAND_REMOVE)) continue var/base_type = initial(component_part.base_type) - if(base_type) - for (var/i = 1 to part_count) - for(var/obj/item/stock_parts/new_component_part in part_replacer.contents) - if(istype(new_component_part, base_type) && new_component_part.rating > initial(component_part.rating)) - replace_part(user, part_replacer, component_part, new_component_part) - . = TRUE - playsound(loc, 'sound/items/rped.ogg', 70) - break + if (!base_type) + continue + for (var/i = 1 to part_count) + for (var/obj/item/stock_parts/new_component_part in part_replacer.contents) + if (!istype(new_component_part, base_type)) + continue + if (new_component_part.rating <= initial(component_part.rating)) + continue + replace_part(user, part_replacer, component_part, new_component_part) + . = TRUE + break + + if (.) + playsound(src, 'sound/items/rped.ogg', 70) + user.visible_message( + SPAN_NOTICE("\The [user] replaces some parts in \a [src] with \a [part_replacer]."), + SPAN_NOTICE("You replace some parts in \the [src] with \the [part_replacer].") + ) + return /// Handles inserting a component or item into the machine by a user. Returns boolean. `TRUE` should halt further processing in `attack*()` procs. /obj/machinery/proc/part_insertion(mob/user, obj/item/stock_parts/part) // Second argument may actually be an arbitrary item. - if(!user.canUnEquip(part) && !isstack(part)) + if (!user.canUnEquip(part) && !isstack(part)) return FALSE var/number = can_add_component(part, user) - if(!number) - return istype(part) // If it's not a stock part, we don't block further interactions; presumably the user meant to do something else. - if(isstack(part)) + if (!number) + return TRUE + if (isstack(part)) var/obj/item/stack/stack = part if (!stack.can_use(number)) USE_FEEDBACK_STACK_NOT_ENOUGH(stack, number, "to install into \the [src].") - return FALSE + return TRUE install_component(stack.split(number, TRUE)) else - user.unEquip(part, src) + if (!user.unEquip(part, src)) + FEEDBACK_UNEQUIP_FAILURE(user, part) + return TRUE install_component(part) user.visible_message( SPAN_NOTICE("\The [user] installs \the [part] in \the [src]!"), @@ -333,34 +351,45 @@ Standard helpers for users interacting with machinery parts. ) return TRUE + /// Handles removal of a component by a user. Returns boolean. -/obj/machinery/proc/part_removal(mob/user) +/obj/machinery/proc/part_removal(mob/user, obj/item/tool) var/list/removable_parts = list() - for(var/path in types_of_component(/obj/item/stock_parts)) + for (var/path in types_of_component(/obj/item/stock_parts)) var/obj/item/stock_parts/part = path - if(!(initial(part.part_flags) & PART_FLAG_HAND_REMOVE)) + if (!HAS_FLAGS(initial(part.part_flags), PART_FLAG_HAND_REMOVE)) continue - if(components_are_accessible(path)) - removable_parts[initial(part.name)] = path - if(length(removable_parts)) - var/input = input(user, "Which part would you like to uninstall from \the [src]?", "Part Removal") as null|anything in removable_parts - if(!input || QDELETED(src) || !Adjacent(user) || user.incapacitated()) - return TRUE - var/path = removable_parts[input] - if(!path || !components_are_accessible(path)) - return TRUE - remove_part_and_give_to_user(path, user) + if (!components_are_accessible(path)) + continue + removable_parts[initial(part.name)] = path + + if (!length(removable_parts)) + USE_FEEDBACK_FAILURE("\The [src] has no more removable parts.") return TRUE + var/input = input(user, "Which part would you like to uninstall from \the [src]?", "Part Removal") as null|anything in removable_parts + if (!input || !user.use_sanity_check(src, tool)) + return TRUE + + var/path = removable_parts[input] + if (!path || !components_are_accessible(path)) + return TRUE + + remove_part_and_give_to_user(path, user) + return TRUE + + /// Removes a part of the given `path` and places it in the hands of `user`. /obj/machinery/proc/remove_part_and_give_to_user(path, mob/user) var/obj/item/stock_parts/part = uninstall_component(get_component_of_type(path, TRUE)) - if(part) - user.put_in_hands(part) // Already dropped at loc, so that's the fallback. - user.visible_message( - SPAN_NOTICE("\The [user] removes \the [part] from \the [src]."), - SPAN_NOTICE("You remove \the [part] from \the [src].") - ) + if (!part) + return + user.put_in_hands(part) // Already dropped at loc, so that's the fallback. + user.visible_message( + SPAN_NOTICE("\The [user] removes \a [part] from \a [src]."), + SPAN_NOTICE("You remove \the [part] from \the [src].") + ) + /// Returns a list of required components that are missing from the machine, or `null` if no components are missing or the machine lacks a `construct_state`. /obj/machinery/proc/missing_parts()