mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 06:29:23 +01:00
[MIRROR] General maintenance for frames (#26651)
* General maintenance for frames (#81473) ## About The Pull Request Builds upon the changes in https://github.com/tgstation/tgstation/pull/81477 **1. Qol** - Adds detailed examines & screentips for building & deconstructing both machine & computer frames - Adding a circuitboard from a rped to a computer frame will automatically screw it in place like before **2. Code Improvements** - Merged procs like `update_path_names()` , `get_requested_amt()` etc into their required places to reduce proc calls - Autodocs procs like `add_cable()`, `add_glass()` etc. makes them private - Moved code for machine frame into its own file * General maintenance for frames --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
This commit is contained in:
@@ -62,7 +62,7 @@
|
||||
#define GEAR_SECURE 1
|
||||
#define GEAR_LOOSE 2
|
||||
|
||||
// Stationary gas tanks
|
||||
//Stationary gas tanks
|
||||
#define TANK_FRAME 0
|
||||
#define TANK_PLATING_UNSECURED 1
|
||||
|
||||
|
||||
@@ -9,6 +9,92 @@
|
||||
/obj/structure/frame/computer/Initialize(mapload)
|
||||
. = ..()
|
||||
AddComponent(/datum/component/simple_rotation)
|
||||
register_context()
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/structure/frame/computer/deconstruct(disassembled = TRUE)
|
||||
if(!(obj_flags & NO_DECONSTRUCTION))
|
||||
var/atom/drop_loc = drop_location()
|
||||
if(state == FRAME_COMPUTER_STATE_GLASSED)
|
||||
if(disassembled)
|
||||
new /obj/item/stack/sheet/glass(drop_loc, 2)
|
||||
else
|
||||
new /obj/item/shard(drop_loc)
|
||||
new /obj/item/shard(drop_loc)
|
||||
if(state >= FRAME_COMPUTER_STATE_WIRED)
|
||||
new /obj/item/stack/cable_coil(drop_loc, 5)
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/computer/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = NONE
|
||||
if(isnull(held_item))
|
||||
return
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_EMPTY)
|
||||
if(held_item.tool_behaviour == TOOL_WRENCH)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(anchored && istype(held_item, /obj/item/circuitboard/computer))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Install board"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_WELDER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Unweld frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
if(held_item.tool_behaviour == TOOL_CROWBAR)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Pry out board"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Secure board"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Unsecure board"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(istype(held_item, /obj/item/stack/cable_coil))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Install cable"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(held_item.tool_behaviour == TOOL_WIRECUTTER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Cut out cable"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(istype(held_item, /obj/item/stack/sheet/glass))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Install panel"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
if(held_item.tool_behaviour == TOOL_CROWBAR)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Pry out glass"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Complete frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/structure/frame/computer/examine(user)
|
||||
. = ..()
|
||||
|
||||
switch(state)
|
||||
if(FRAME_STATE_EMPTY)
|
||||
. += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"].")
|
||||
if(anchored)
|
||||
. += span_warning("It's missing a circuit board.")
|
||||
. += span_notice("It can be [EXAMINE_HINT("welded")] or [EXAMINE_HINT("screwed")] apart.")
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
. += span_warning("An [circuit.name] is installed and should be [EXAMINE_HINT("screwed")] in place.")
|
||||
. += span_notice("The circuit board can be [EXAMINE_HINT("pried")] out.")
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
. += span_warning("Its requires [EXAMINE_HINT("5 cable")] pieces to wire it.")
|
||||
. += span_notice("The circuit board can be [EXAMINE_HINT("screwed")] loose.")
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
. += span_notice("The wires can be cut out with [EXAMINE_HINT("wire cutters")].")
|
||||
. += span_warning("Its requires [EXAMINE_HINT("2 glass")] sheets to complete the screen.")
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
. += span_notice("The screen can be [EXAMINE_HINT("pried")] out.")
|
||||
. += span_notice("The moniter can be [EXAMINE_HINT("screwed")] to complete it")
|
||||
|
||||
/obj/structure/frame/computer/circuit_added(obj/item/circuitboard/added)
|
||||
state = FRAME_COMPUTER_STATE_BOARD_INSTALLED
|
||||
@@ -22,95 +108,15 @@
|
||||
if(state != FRAME_COMPUTER_STATE_EMPTY)
|
||||
balloon_alert(user, "circuit already installed!")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
|
||||
if(!anchored && istype(board))
|
||||
balloon_alert(user, "frame must be anchored!")
|
||||
return FALSE
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_EMPTY)
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
return add_cabling(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(istype(tool, /obj/item/stack/sheet/glass))
|
||||
return add_glass(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(. && !by_hand) // Installing via RPED auto-secures it
|
||||
state = FRAME_COMPUTER_STATE_BOARD_SECURED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return .
|
||||
|
||||
/obj/structure/frame/computer/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
if(. != NONE)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit secured")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_SECURED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit unsecured")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_INSTALLED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(!user.combat_mode)
|
||||
balloon_alert(user, "no glass!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
if(finalize_construction(user, tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
balloon_alert(user, "missing components!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
/obj/structure/frame/computer/crowbar_act(mob/living/user, obj/item/tool)
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit removed")
|
||||
circuit.add_fingerprint(user)
|
||||
circuit.forceMove(drop_location())
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
if(!user.combat_mode)
|
||||
balloon_alert(user, "unsecure the circuit!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(!user.combat_mode)
|
||||
balloon_alert(user, "remove the wiring!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "glass removed")
|
||||
state = FRAME_COMPUTER_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
var/obj/item/stack/sheet/glass/dropped_glass = new (drop_location(), 2)
|
||||
if (!QDELETED(dropped_glass))
|
||||
dropped_glass.add_fingerprint(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/computer/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE)
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
@@ -142,7 +148,120 @@
|
||||
|
||||
return FALSE
|
||||
|
||||
/obj/structure/frame/computer/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_EMPTY)
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
return add_cabling(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(istype(tool, /obj/item/stack/sheet/glass))
|
||||
return add_glass(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
/obj/structure/frame/computer/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit secured")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_SECURED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit unsecured")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_INSTALLED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
if(!user.combat_mode)
|
||||
balloon_alert(user, "no glass!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
if(finalize_construction(user, tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
balloon_alert(user, "missing components!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
/obj/structure/frame/computer/crowbar_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
switch(state)
|
||||
if(FRAME_COMPUTER_STATE_BOARD_INSTALLED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "circuit removed")
|
||||
circuit.add_fingerprint(user)
|
||||
circuit.forceMove(drop_location())
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
balloon_alert(user, "unsecure the circuit!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_WIRED)
|
||||
balloon_alert(user, "remove the wiring!")
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_COMPUTER_STATE_GLASSED)
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "glass removed")
|
||||
state = FRAME_COMPUTER_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
var/obj/item/stack/sheet/glass/dropped_glass = new (drop_location(), 2)
|
||||
if (!QDELETED(dropped_glass))
|
||||
dropped_glass.add_fingerprint(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
|
||||
if(state != FRAME_COMPUTER_STATE_WIRED)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "cables removed")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_SECURED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5)
|
||||
if (!QDELETED(dropped_cables))
|
||||
dropped_cables.add_fingerprint(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/**
|
||||
* Adds cable to the computer to wire it
|
||||
* Arguments
|
||||
*
|
||||
* * mob/living/user - the player who is adding the cable
|
||||
* * obj/item/stack/cable_coil/cable - the cable we are trying to add
|
||||
* * time - time taken to complete the operation
|
||||
*/
|
||||
/obj/structure/frame/computer/proc/add_cabling(mob/living/user, obj/item/stack/cable_coil/cable, time = 2 SECONDS)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
if(state != FRAME_COMPUTER_STATE_BOARD_SECURED)
|
||||
return FALSE
|
||||
if(!cable.tool_start_check(user, amount = 5))
|
||||
@@ -156,7 +275,17 @@
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Adds glass sheets to the computer to complete the screen
|
||||
* Arguments
|
||||
*
|
||||
* * mob/living/user - the player who is adding the glass
|
||||
* * obj/item/stack/sheet/glass/glass - the glass we are trying to add
|
||||
* * time - time taken to complete the operation
|
||||
*/
|
||||
/obj/structure/frame/computer/proc/add_glass(mob/living/user, obj/item/stack/sheet/glass/glass, time = 2 SECONDS)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
if(state != FRAME_COMPUTER_STATE_WIRED)
|
||||
return FALSE
|
||||
if(!glass.tool_start_check(user, amount = 2))
|
||||
@@ -171,22 +300,6 @@
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/frame/computer/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
if(state != FRAME_COMPUTER_STATE_WIRED)
|
||||
return NONE
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
balloon_alert(user, "cables removed")
|
||||
state = FRAME_COMPUTER_STATE_BOARD_SECURED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
var/obj/item/stack/cable_coil/dropped_cables = new (drop_location(), 5)
|
||||
if (!QDELETED(dropped_cables))
|
||||
dropped_cables.add_fingerprint(user)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/computer/AltClick(mob/user)
|
||||
return ..() // This hotkey is BLACKLISTED since it's used by /datum/component/simple_rotation
|
||||
|
||||
/obj/structure/frame/computer/finalize_construction(mob/living/user, obj/item/tool)
|
||||
tool.play_tool_sound(src)
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc)
|
||||
@@ -221,20 +334,6 @@
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/frame/computer/deconstruct(disassembled = TRUE)
|
||||
if(!(obj_flags & NO_DECONSTRUCTION))
|
||||
var/atom/drop_loc = drop_location()
|
||||
if(state == FRAME_COMPUTER_STATE_GLASSED)
|
||||
if(disassembled)
|
||||
new /obj/item/stack/sheet/glass(drop_loc, 2)
|
||||
else
|
||||
new /obj/item/shard(drop_loc)
|
||||
new /obj/item/shard(drop_loc)
|
||||
if(state >= FRAME_COMPUTER_STATE_WIRED)
|
||||
new /obj/item/stack/cable_coil(drop_loc, 5)
|
||||
|
||||
return ..()
|
||||
|
||||
/// Helpers for rcd
|
||||
/obj/structure/frame/computer/rcd
|
||||
icon = 'icons/hud/radial.dmi'
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
new /obj/item/stack/sheet/iron(drop_loc, 5)
|
||||
circuit?.forceMove(drop_loc)
|
||||
|
||||
qdel(src)
|
||||
return ..()
|
||||
|
||||
/// Called when circuit has been set to a new board
|
||||
/obj/structure/frame/proc/circuit_added(obj/item/circuitboard/added)
|
||||
@@ -97,13 +97,13 @@
|
||||
return FALSE
|
||||
|
||||
/obj/structure/frame/wrench_act(mob/living/user, obj/item/tool)
|
||||
. = NONE
|
||||
switch(default_unfasten_wrench(user, tool, 4 SECONDS))
|
||||
if(SUCCESSFUL_UNFASTEN)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
if(FAILED_UNFASTEN)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
return NONE
|
||||
return .
|
||||
|
||||
/obj/structure/frame/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
|
||||
. = ..()
|
||||
@@ -196,421 +196,3 @@
|
||||
*/
|
||||
/obj/structure/frame/proc/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE)
|
||||
return FALSE
|
||||
|
||||
/obj/structure/frame/machine
|
||||
name = "machine frame"
|
||||
desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board."
|
||||
board_type = /obj/item/circuitboard/machine
|
||||
/// List of all compnents inside the frame contributing to its construction
|
||||
var/list/components
|
||||
/// List of all components required to construct the frame
|
||||
var/list/req_components
|
||||
/// User-friendly list of names of required components
|
||||
var/list/req_component_names
|
||||
|
||||
/obj/structure/frame/machine/examine(user)
|
||||
. = ..()
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
return .
|
||||
|
||||
if(!length(req_components))
|
||||
. += span_info("It requires no components.")
|
||||
return .
|
||||
|
||||
if(!req_component_names)
|
||||
stack_trace("[src]'s req_components list has items but its req_component_names list is null!")
|
||||
return .
|
||||
|
||||
var/list/nice_list = list()
|
||||
for(var/component in req_components)
|
||||
if(!ispath(component))
|
||||
stack_trace("An item in [src]'s req_components list is not a path!")
|
||||
continue
|
||||
if(!req_components[component])
|
||||
continue
|
||||
|
||||
nice_list += list("[req_components[component]] [req_component_names[component]]\s")
|
||||
. += span_info("It requires [english_list(nice_list, "no more components")].")
|
||||
return .
|
||||
|
||||
/**
|
||||
* Collates the displayed names of the machine's components
|
||||
*
|
||||
* Arguments:
|
||||
* * specific_parts - If true, the component should not use base name, but a specific tier
|
||||
*/
|
||||
/obj/structure/frame/machine/proc/update_namelist(specific_parts)
|
||||
if(!req_components)
|
||||
return
|
||||
|
||||
req_component_names = list()
|
||||
for(var/component_path in req_components)
|
||||
if(!ispath(component_path))
|
||||
continue
|
||||
|
||||
if(ispath(component_path, /obj/item/stack))
|
||||
var/obj/item/stack/stack_path = component_path
|
||||
if(initial(stack_path.singular_name))
|
||||
req_component_names[component_path] = initial(stack_path.singular_name)
|
||||
else
|
||||
req_component_names[component_path] = initial(stack_path.name)
|
||||
else if(ispath(component_path, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part = component_path
|
||||
var/obj/item/physical_object_type = initial(stock_part.physical_object_type)
|
||||
|
||||
req_component_names[component_path] = initial(physical_object_type.name)
|
||||
else if(ispath(component_path, /obj/item/stock_parts))
|
||||
var/obj/item/stock_parts/stock_part = component_path
|
||||
|
||||
if(!specific_parts && initial(stock_part.base_name))
|
||||
req_component_names[component_path] = initial(stock_part.base_name)
|
||||
else
|
||||
req_component_names[component_path] = initial(stock_part.name)
|
||||
else if(ispath(component_path, /obj/item))
|
||||
var/obj/item/part = component_path
|
||||
|
||||
req_component_names[component_path] = initial(part.name)
|
||||
else
|
||||
stack_trace("Invalid component part [component_path] in [type], couldn't get its name")
|
||||
req_component_names[component_path] = "[component_path] (this is a bug)"
|
||||
|
||||
/obj/structure/frame/machine/proc/get_req_components_amt()
|
||||
var/amt = 0
|
||||
for(var/path in req_components)
|
||||
amt += req_components[path]
|
||||
return amt
|
||||
|
||||
/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time)
|
||||
if(anchored)
|
||||
balloon_alert(user, "must be unsecured first!")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE)
|
||||
if(state == FRAME_STATE_EMPTY)
|
||||
balloon_alert(user, "needs wiring!")
|
||||
return FALSE
|
||||
if(state == FRAME_STATE_BOARD_INSTALLED)
|
||||
balloon_alert(user, "circuit already installed!")
|
||||
return FALSE
|
||||
if(!anchored && istype(board) && board.needs_anchored)
|
||||
balloon_alert(user, "frame must be anchored!")
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added)
|
||||
state = FRAME_STATE_BOARD_INSTALLED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
//add circuit board as the first component to the list of components
|
||||
//required for part_replacer to locate it while exchanging parts
|
||||
//so it does not early return in /obj/machinery/proc/exchange_parts
|
||||
components = list(circuit)
|
||||
req_components = added.req_components.Copy()
|
||||
update_namelist(added.specific_parts)
|
||||
|
||||
/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed)
|
||||
state = FRAME_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE)
|
||||
if(!length(replacer.contents) || !get_req_components_amt())
|
||||
return FALSE
|
||||
|
||||
var/play_sound = FALSE
|
||||
var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier
|
||||
for(var/path in req_components)
|
||||
var/target_path
|
||||
if(ispath(path, /datum/stock_part))
|
||||
var/datum/stock_part/datum_part = path
|
||||
target_path = initial(datum_part.physical_object_base_type)
|
||||
else
|
||||
target_path = path
|
||||
|
||||
var/obj/item/part
|
||||
while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null)))
|
||||
part_list -= part
|
||||
if(istype(part, /obj/item/stack))
|
||||
var/obj/item/stack/S = part
|
||||
var/used_amt = min(round(S.get_amount()), req_components[path])
|
||||
var/stack_name = S.singular_name
|
||||
if(!used_amt || !S.use(used_amt))
|
||||
continue
|
||||
req_components[path] -= used_amt
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [used_amt] [stack_name] to [src]."))
|
||||
play_sound = TRUE
|
||||
else if(replacer.atom_storage.attempt_remove(part, src))
|
||||
var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type]
|
||||
if (!isnull(stock_part_datum))
|
||||
components += stock_part_datum
|
||||
qdel(part)
|
||||
else
|
||||
components += part
|
||||
part.forceMove(src)
|
||||
req_components[path]--
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [part] to [src]."))
|
||||
play_sound = TRUE
|
||||
|
||||
if(play_sound && !no_sound)
|
||||
replacer.play_rped_sound()
|
||||
if(replacer.works_from_distance)
|
||||
user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/**
|
||||
* Attempts to add the passed part to the frame
|
||||
*
|
||||
* Requires no sanity check that the passed part is a stock part
|
||||
*
|
||||
* Arguments
|
||||
* * user - the player
|
||||
* * tool - the part to add
|
||||
*/
|
||||
/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool)
|
||||
for(var/stock_part_base in req_components)
|
||||
if (req_components[stock_part_base] == 0)
|
||||
continue
|
||||
|
||||
var/stock_part_path
|
||||
|
||||
if(ispath(stock_part_base, /obj/item))
|
||||
stock_part_path = stock_part_base
|
||||
else if(ispath(stock_part_base, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part_datum_type = stock_part_base
|
||||
stock_part_path = initial(stock_part_datum_type.physical_object_type)
|
||||
else
|
||||
stack_trace("Bad stock part in req_components: [stock_part_base]")
|
||||
continue
|
||||
|
||||
//if we require an bluespace crystall and we have an full sheet of them we can allow that
|
||||
if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal))
|
||||
//allow it
|
||||
pass()
|
||||
else if(!istype(tool, stock_part_path))
|
||||
continue
|
||||
|
||||
if(isstack(tool))
|
||||
var/obj/item/stack/S = tool
|
||||
var/used_amt = min(round(S.get_amount()), req_components[stock_part_path])
|
||||
if(used_amt && S.use(used_amt))
|
||||
req_components[stock_part_path] -= used_amt
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [tool] to [src]."))
|
||||
return
|
||||
|
||||
// We might end up qdel'ing the part if it's a stock part datum.
|
||||
// In practice, this doesn't have side effects to the name,
|
||||
// but academically we should not be using an object after it's deleted.
|
||||
var/part_name = "[tool]"
|
||||
|
||||
if (ispath(stock_part_base, /datum/stock_part))
|
||||
// We can't just reuse stock_part_path here or its singleton,
|
||||
// or else putting in a tier 2 part will deconstruct to a tier 1 part.
|
||||
var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type]
|
||||
if (isnull(stock_part_datum))
|
||||
stack_trace("tool.type] does not have an associated stock part datum!")
|
||||
continue
|
||||
|
||||
components += stock_part_datum
|
||||
|
||||
// We regenerate the stock parts on deconstruct.
|
||||
// This technically means we lose unique qualities of the stock part, but
|
||||
// it's worth it for how dramatically this simplifies the code.
|
||||
// The only place I can see it affecting anything is like...RPG qualities. :P
|
||||
qdel(tool)
|
||||
else if(user.transferItemToLoc(tool, src))
|
||||
components += tool
|
||||
else
|
||||
break
|
||||
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [part_name] to [src]."))
|
||||
req_components[stock_part_base]--
|
||||
return TRUE
|
||||
|
||||
balloon_alert(user, "can't add that!")
|
||||
return FALSE
|
||||
|
||||
/**
|
||||
* Attempt to finalize the construction of the frame into a machine
|
||||
* as according to our circuit and parts
|
||||
*
|
||||
* If successful, results in qdel'ing the frame and newing of a machine
|
||||
*
|
||||
* Arguments
|
||||
* * user - the player
|
||||
* * tool - the tool used to finalize the construction
|
||||
*/
|
||||
/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool)
|
||||
for(var/component in req_components)
|
||||
if(req_components[component] > 0)
|
||||
user.balloon_alert(user, "missing components!")
|
||||
return FALSE
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc)
|
||||
if(istype(new_machine))
|
||||
new_machine.clear_components()
|
||||
// Set anchor state
|
||||
new_machine.set_anchored(anchored)
|
||||
// Prevent us from dropping stuff thanks to /Exited
|
||||
var/obj/item/circuitboard/machine/leaving_circuit = circuit
|
||||
circuit = null
|
||||
// Assign the circuit & parts & move them all at once into the machine
|
||||
// no need to seperatly move circuit board as its already part of the components list
|
||||
new_machine.circuit = leaving_circuit
|
||||
new_machine.component_parts = components
|
||||
for (var/obj/new_part in components)
|
||||
new_part.forceMove(new_machine)
|
||||
//Inform machine that its finished & cleanup
|
||||
new_machine.RefreshParts()
|
||||
new_machine.on_construction(user)
|
||||
components = null
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_STATE_EMPTY)
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
if(!tool.tool_start_check(user, amount = 5))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
balloon_alert(user, "adding cables...")
|
||||
if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
state = FRAME_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_STATE_WIRED)
|
||||
if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_STATE_BOARD_INSTALLED)
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!user.combat_mode)
|
||||
return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
return .
|
||||
|
||||
/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
return .
|
||||
|
||||
if(finalize_construction(user, tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent)
|
||||
. = ..()
|
||||
if(. != SUCCESSFUL_UNFASTEN)
|
||||
return .
|
||||
|
||||
if(circuit?.needs_anchored)
|
||||
balloon_alert(user, "circuit must be anchored!")
|
||||
return FAILED_UNFASTEN
|
||||
|
||||
return .
|
||||
|
||||
/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
if(state != FRAME_STATE_WIRED)
|
||||
return NONE
|
||||
|
||||
balloon_alert(user, "removing cables...")
|
||||
if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
state = FRAME_STATE_EMPTY
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool)
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
return NONE
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/list/leftover_components = components.Copy() - circuit
|
||||
dump_contents()
|
||||
balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed")
|
||||
// Circuit exited handles updating state
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/machine/Exited(atom/movable/gone, direction)
|
||||
if(gone == circuit)
|
||||
components -= circuit
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/Destroy()
|
||||
QDEL_LIST(components)
|
||||
return ..()
|
||||
|
||||
/**
|
||||
* Returns the instance of path1 in list, else path2 in list
|
||||
*
|
||||
* Arguments
|
||||
* * parts - the list of parts to search
|
||||
* * path1 - the first path to search for
|
||||
* * path2 - the second path to search for, if path1 is not found
|
||||
*/
|
||||
/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2)
|
||||
return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null)
|
||||
|
||||
/obj/structure/frame/machine/deconstruct(disassembled = TRUE)
|
||||
if(!(obj_flags & NO_DECONSTRUCTION))
|
||||
if(state >= FRAME_STATE_WIRED)
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
dump_contents()
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/dump_contents()
|
||||
var/atom/drop_loc = drop_location()
|
||||
|
||||
// We need a snowflake check for stack items since they don't exist anymore
|
||||
for(var/component in circuit?.req_components)
|
||||
if(!ispath(component, /obj/item/stack))
|
||||
continue
|
||||
var/obj/item/stack/stack_path = component
|
||||
var/stack_amount = circuit.req_components[component] - req_components[component]
|
||||
if(stack_amount > 0)
|
||||
new stack_path(drop_loc, stack_amount)
|
||||
|
||||
// Rest of the stuff can just be spat out (this includes the circuitboard0)
|
||||
for(var/component in components)
|
||||
if(ismovable(component))
|
||||
var/atom/movable/atom_component = component
|
||||
atom_component.forceMove(drop_loc)
|
||||
|
||||
else if(istype(component, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part_datum = component
|
||||
var/physical_object_type = initial(stock_part_datum.physical_object_type)
|
||||
new physical_object_type(drop_loc)
|
||||
|
||||
else
|
||||
stack_trace("Invalid component [component] was found in constructable frame")
|
||||
|
||||
components = null
|
||||
req_components = null
|
||||
req_component_names = null
|
||||
|
||||
/obj/structure/frame/machine/secured
|
||||
state = FRAME_STATE_WIRED
|
||||
anchored = TRUE
|
||||
|
||||
/obj/structure/frame/machine/secured/Initialize(mapload)
|
||||
. = ..()
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
@@ -0,0 +1,474 @@
|
||||
/obj/structure/frame/machine
|
||||
name = "machine frame"
|
||||
desc = "The standard frame for most station appliances. Its appearance and function is controlled by the inserted board."
|
||||
board_type = /obj/item/circuitboard/machine
|
||||
/// List of all compnents inside the frame contributing to its construction
|
||||
var/list/components
|
||||
/// List of all components required to construct the frame
|
||||
var/list/req_components
|
||||
/// User-friendly list of names of required components
|
||||
var/list/req_component_names
|
||||
|
||||
/obj/structure/frame/machine/Initialize(mapload)
|
||||
. = ..()
|
||||
register_context()
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/obj/structure/frame/machine/Destroy()
|
||||
QDEL_LIST(components)
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/deconstruct(disassembled = TRUE)
|
||||
if(!(obj_flags & NO_DECONSTRUCTION))
|
||||
if(state >= FRAME_STATE_WIRED)
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
dump_contents()
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/try_dissassemble(mob/living/user, obj/item/tool, disassemble_time)
|
||||
if(anchored)
|
||||
balloon_alert(user, "must be unsecured first!")
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/add_context(atom/source, list/context, obj/item/held_item, mob/user)
|
||||
. = NONE
|
||||
if(isnull(held_item))
|
||||
return
|
||||
|
||||
switch(state)
|
||||
if(FRAME_STATE_EMPTY)
|
||||
if(istype(held_item, /obj/item/stack/cable_coil))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Wire Frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_WRENCH)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_WELDER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Unweld frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Disassemble frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_STATE_WIRED)
|
||||
if(held_item.tool_behaviour == TOOL_WIRECUTTER)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Cut wires"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(istype(held_item, board_type))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Insert board"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
if(FRAME_STATE_BOARD_INSTALLED)
|
||||
if(held_item.tool_behaviour == TOOL_CROWBAR)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Pry out components"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(held_item.tool_behaviour == TOOL_WRENCH)
|
||||
if(!circuit.needs_anchored)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchor"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
return NONE
|
||||
else if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
|
||||
var/needs_components = FALSE
|
||||
for(var/component in req_components)
|
||||
if(!req_components[component])
|
||||
continue
|
||||
needs_components = TRUE
|
||||
break
|
||||
if(!needs_components)
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Complete frame"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
else if(!istype(held_item, /obj/item/storage/part_replacer))
|
||||
for(var/component in req_components)
|
||||
if(!req_components[component])
|
||||
continue
|
||||
var/stock_part_path
|
||||
if(ispath(component, /obj/item))
|
||||
stock_part_path = component
|
||||
else if(ispath(component, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part_datum_type = component
|
||||
stock_part_path = initial(stock_part_datum_type.physical_object_type)
|
||||
if(istype(held_item, stock_part_path))
|
||||
context[SCREENTIP_CONTEXT_LMB] = "Insert part"
|
||||
return CONTEXTUAL_SCREENTIP_SET
|
||||
|
||||
/obj/structure/frame/machine/examine(user)
|
||||
. = ..()
|
||||
if(!circuit?.needs_anchored)
|
||||
. += span_notice("It can be [EXAMINE_HINT("anchored")] [anchored ? "loose" : "in place"]")
|
||||
if(state == FRAME_STATE_EMPTY)
|
||||
. += span_warning("It needs [EXAMINE_HINT("5 cable")] pieces to wire it.")
|
||||
return
|
||||
if(state == FRAME_STATE_WIRED)
|
||||
. += span_info("Its wires can be cut with a [EXAMINE_HINT("wirecutter")].")
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
. += span_warning("Its missing a circuit board..")
|
||||
return
|
||||
if(!length(req_components))
|
||||
. += span_info("It requires no components.")
|
||||
return
|
||||
|
||||
var/list/nice_list = list()
|
||||
for(var/component in req_components)
|
||||
if(!req_components[component])
|
||||
continue
|
||||
nice_list += list("[req_components[component]] [req_component_names[component]]\s")
|
||||
. += span_info("It requires [english_list(nice_list, "no more components")].")
|
||||
|
||||
. += span_info("All the components can be [EXAMINE_HINT("pried")] out.")
|
||||
if(!length(nice_list))
|
||||
. += span_info("The frame can be [EXAMINE_HINT("screwed")] to complete it.")
|
||||
|
||||
/obj/structure/frame/machine/dump_contents()
|
||||
var/atom/drop_loc = drop_location()
|
||||
|
||||
// We need a snowflake check for stack items since they don't exist anymore
|
||||
for(var/component in circuit?.req_components)
|
||||
if(!ispath(component, /obj/item/stack))
|
||||
continue
|
||||
var/obj/item/stack/stack_path = component
|
||||
var/stack_amount = circuit.req_components[component] - req_components[component]
|
||||
if(stack_amount > 0)
|
||||
new stack_path(drop_loc, stack_amount)
|
||||
|
||||
// Rest of the stuff can just be spat out (this includes the circuitboard0)
|
||||
for(var/component in components)
|
||||
if(ismovable(component))
|
||||
var/atom/movable/atom_component = component
|
||||
atom_component.forceMove(drop_loc)
|
||||
|
||||
else if(istype(component, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part_datum = component
|
||||
var/physical_object_type = initial(stock_part_datum.physical_object_type)
|
||||
new physical_object_type(drop_loc)
|
||||
|
||||
else
|
||||
stack_trace("Invalid component [component] was found in constructable frame")
|
||||
|
||||
components = null
|
||||
req_components = null
|
||||
req_component_names = null
|
||||
|
||||
/obj/structure/frame/machine/install_board(mob/living/user, obj/item/circuitboard/machine/board, by_hand = TRUE)
|
||||
if(state == FRAME_STATE_EMPTY)
|
||||
balloon_alert(user, "needs wiring!")
|
||||
return FALSE
|
||||
if(state == FRAME_STATE_BOARD_INSTALLED)
|
||||
balloon_alert(user, "circuit already installed!")
|
||||
return FALSE
|
||||
if(!anchored && istype(board) && board.needs_anchored)
|
||||
balloon_alert(user, "frame must be anchored!")
|
||||
return FALSE
|
||||
|
||||
return ..()
|
||||
|
||||
/obj/structure/frame/machine/circuit_added(obj/item/circuitboard/machine/added)
|
||||
state = FRAME_STATE_BOARD_INSTALLED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
//add circuit board as the first component to the list of components
|
||||
//required for part_replacer to locate it while exchanging parts
|
||||
//so it does not early return in /obj/machinery/proc/exchange_parts
|
||||
components = list(circuit)
|
||||
req_components = added.req_components.Copy()
|
||||
if(!req_components)
|
||||
return
|
||||
|
||||
//creates a list of names from all the required parts
|
||||
req_component_names = list()
|
||||
for(var/component_path in req_components)
|
||||
if(!ispath(component_path))
|
||||
continue
|
||||
|
||||
if(ispath(component_path, /obj/item/stack))
|
||||
var/obj/item/stack/stack_path = component_path
|
||||
if(initial(stack_path.singular_name))
|
||||
req_component_names[component_path] = initial(stack_path.singular_name)
|
||||
else
|
||||
req_component_names[component_path] = initial(stack_path.name)
|
||||
else if(ispath(component_path, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part = component_path
|
||||
var/obj/item/physical_object_type = initial(stock_part.physical_object_type)
|
||||
|
||||
req_component_names[component_path] = initial(physical_object_type.name)
|
||||
else if(ispath(component_path, /obj/item/stock_parts))
|
||||
var/obj/item/stock_parts/stock_part = component_path
|
||||
|
||||
if(!added.specific_parts && initial(stock_part.base_name))
|
||||
req_component_names[component_path] = initial(stock_part.base_name)
|
||||
else
|
||||
req_component_names[component_path] = initial(stock_part.name)
|
||||
else if(ispath(component_path, /obj/item))
|
||||
var/obj/item/part = component_path
|
||||
|
||||
req_component_names[component_path] = initial(part.name)
|
||||
else
|
||||
stack_trace("Invalid component part [component_path] in [type], couldn't get its name")
|
||||
req_component_names[component_path] = "[component_path] (this is a bug)"
|
||||
|
||||
/obj/structure/frame/machine/circuit_removed(obj/item/circuitboard/machine/removed)
|
||||
components -= removed
|
||||
state = FRAME_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
|
||||
/**
|
||||
* Returns the instance of path1 in list, else path2 in list
|
||||
*
|
||||
* Arguments
|
||||
* * parts - the list of parts to search
|
||||
* * path1 - the first path to search for
|
||||
* * path2 - the second path to search for, if path1 is not found
|
||||
*/
|
||||
/obj/structure/frame/machine/proc/look_for(list/parts, path1, path2)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
return (locate(path1) in parts) || (path2 ? (locate(path2) in parts) : null)
|
||||
|
||||
/obj/structure/frame/machine/install_parts_from_part_replacer(mob/living/user, obj/item/storage/part_replacer/replacer, no_sound = FALSE)
|
||||
if(!length(replacer.contents))
|
||||
return FALSE
|
||||
var/amt = 0
|
||||
for(var/path in req_components)
|
||||
amt += req_components[path]
|
||||
if(!amt)
|
||||
return FALSE
|
||||
|
||||
var/play_sound = FALSE
|
||||
var/list/part_list = replacer.get_sorted_parts() //parts sorted in order of tier
|
||||
for(var/path in req_components)
|
||||
var/target_path
|
||||
if(ispath(path, /datum/stock_part))
|
||||
var/datum/stock_part/datum_part = path
|
||||
target_path = initial(datum_part.physical_object_base_type)
|
||||
else
|
||||
target_path = path
|
||||
|
||||
var/obj/item/part
|
||||
while(req_components[path] > 0 && (part = look_for(part_list, target_path, ispath(path, /obj/item/stack/ore/bluespace_crystal) ? /obj/item/stack/sheet/bluespace_crystal : null)))
|
||||
part_list -= part
|
||||
if(istype(part, /obj/item/stack))
|
||||
var/obj/item/stack/S = part
|
||||
var/used_amt = min(round(S.get_amount()), req_components[path])
|
||||
var/stack_name = S.singular_name
|
||||
if(!used_amt || !S.use(used_amt))
|
||||
continue
|
||||
req_components[path] -= used_amt
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [used_amt] [stack_name] to [src]."))
|
||||
play_sound = TRUE
|
||||
else if(replacer.atom_storage.attempt_remove(part, src))
|
||||
var/stock_part_datum = GLOB.stock_part_datums_per_object[part.type]
|
||||
if (!isnull(stock_part_datum))
|
||||
components += stock_part_datum
|
||||
qdel(part)
|
||||
else
|
||||
components += part
|
||||
part.forceMove(src)
|
||||
req_components[path]--
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [part] to [src]."))
|
||||
play_sound = TRUE
|
||||
|
||||
if(play_sound && !no_sound)
|
||||
replacer.play_rped_sound()
|
||||
if(replacer.works_from_distance)
|
||||
user.Beam(src, icon_state = "rped_upgrade", time = 0.5 SECONDS)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/frame/machine/can_be_unfasten_wrench(mob/user, silent)
|
||||
. = ..()
|
||||
if(. != SUCCESSFUL_UNFASTEN)
|
||||
return .
|
||||
|
||||
if(circuit?.needs_anchored)
|
||||
balloon_alert(user, "frame must be anchored!")
|
||||
return FAILED_UNFASTEN
|
||||
|
||||
return .
|
||||
|
||||
/obj/structure/frame/machine/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
return .
|
||||
|
||||
if(finalize_construction(user, tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
/obj/structure/frame/machine/wirecutter_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
if(state != FRAME_STATE_WIRED)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
balloon_alert(user, "removing cables...")
|
||||
if(!tool.use_tool(src, user, 2 SECONDS, volume = 50) || state != FRAME_STATE_WIRED)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
state = FRAME_STATE_EMPTY
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
new /obj/item/stack/cable_coil(drop_location(), 5)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/obj/structure/frame/machine/crowbar_act(mob/living/user, obj/item/tool)
|
||||
if(user.combat_mode)
|
||||
return NONE
|
||||
if(state != FRAME_STATE_BOARD_INSTALLED)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/list/leftover_components = components.Copy() - circuit
|
||||
dump_contents()
|
||||
balloon_alert(user, "circuit board[length(leftover_components) ? " and components" : ""] removed")
|
||||
// Circuit exited handles updating state
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/**
|
||||
* Attempts to add the passed part to the frame
|
||||
*
|
||||
* Requires no sanity check that the passed part is a stock part
|
||||
*
|
||||
* Arguments
|
||||
* * user - the player
|
||||
* * tool - the part to add
|
||||
*/
|
||||
/obj/structure/frame/machine/proc/add_part(mob/living/user, obj/item/tool)
|
||||
PRIVATE_PROC(TRUE)
|
||||
|
||||
for(var/stock_part_base in req_components)
|
||||
if (req_components[stock_part_base] == 0)
|
||||
continue
|
||||
|
||||
var/stock_part_path
|
||||
|
||||
if(ispath(stock_part_base, /obj/item))
|
||||
stock_part_path = stock_part_base
|
||||
else if(ispath(stock_part_base, /datum/stock_part))
|
||||
var/datum/stock_part/stock_part_datum_type = stock_part_base
|
||||
stock_part_path = initial(stock_part_datum_type.physical_object_type)
|
||||
else
|
||||
stack_trace("Bad stock part in req_components: [stock_part_base]")
|
||||
continue
|
||||
|
||||
//if we require an bluespace crystall and we have an full sheet of them we can allow that
|
||||
if(ispath(stock_part_path, /obj/item/stack/ore/bluespace_crystal) && istype(tool, /obj/item/stack/sheet/bluespace_crystal))
|
||||
pass() //allow it
|
||||
else if(!istype(tool, stock_part_path))
|
||||
continue
|
||||
|
||||
if(isstack(tool))
|
||||
var/obj/item/stack/S = tool
|
||||
var/used_amt = min(round(S.get_amount()), req_components[stock_part_path])
|
||||
if(used_amt && S.use(used_amt))
|
||||
req_components[stock_part_path] -= used_amt
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [tool] to [src]."))
|
||||
return
|
||||
|
||||
// We might end up qdel'ing the part if it's a stock part datum.
|
||||
// In practice, this doesn't have side effects to the name,
|
||||
// but academically we should not be using an object after it's deleted.
|
||||
var/part_name = "[tool]"
|
||||
|
||||
if (ispath(stock_part_base, /datum/stock_part))
|
||||
// We can't just reuse stock_part_path here or its singleton,
|
||||
// or else putting in a tier 2 part will deconstruct to a tier 1 part.
|
||||
var/stock_part_datum = GLOB.stock_part_datums_per_object[tool.type]
|
||||
if (isnull(stock_part_datum))
|
||||
stack_trace("tool.type] does not have an associated stock part datum!")
|
||||
continue
|
||||
|
||||
components += stock_part_datum
|
||||
|
||||
// We regenerate the stock parts on deconstruct.
|
||||
// This technically means we lose unique qualities of the stock part, but
|
||||
// it's worth it for how dramatically this simplifies the code.
|
||||
// The only place I can see it affecting anything is like...RPG qualities. :P
|
||||
qdel(tool)
|
||||
else if(user.transferItemToLoc(tool, src))
|
||||
components += tool
|
||||
else
|
||||
break
|
||||
|
||||
// No balloon alert here so they can look back and see what they added
|
||||
to_chat(user, span_notice("You add [part_name] to [src]."))
|
||||
req_components[stock_part_base]--
|
||||
return TRUE
|
||||
|
||||
balloon_alert(user, "can't add that!")
|
||||
return FALSE
|
||||
|
||||
/obj/structure/frame/machine/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
|
||||
. = ..()
|
||||
if(. & ITEM_INTERACT_ANY_BLOCKER)
|
||||
return .
|
||||
|
||||
switch(state)
|
||||
if(FRAME_STATE_EMPTY)
|
||||
if(istype(tool, /obj/item/stack/cable_coil))
|
||||
if(!tool.tool_start_check(user, amount = 5))
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
balloon_alert(user, "adding cables...")
|
||||
if(!tool.use_tool(src, user, 2 SECONDS, volume = 50, amount = 5) || state != FRAME_STATE_EMPTY)
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
|
||||
state = FRAME_STATE_WIRED
|
||||
update_appearance(UPDATE_ICON_STATE)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
if(FRAME_STATE_WIRED)
|
||||
if(isnull(circuit) && istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_circuit_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(FRAME_STATE_BOARD_INSTALLED)
|
||||
if(istype(tool, /obj/item/storage/part_replacer))
|
||||
return install_parts_from_part_replacer(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
if(!user.combat_mode)
|
||||
return add_part(user, tool) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING
|
||||
|
||||
return .
|
||||
|
||||
/**
|
||||
* Attempt to finalize the construction of the frame into a machine
|
||||
* as according to our circuit and parts
|
||||
*
|
||||
* If successful, results in qdel'ing the frame and newing of a machine
|
||||
*
|
||||
* Arguments
|
||||
* * user - the player
|
||||
* * tool - the tool used to finalize the construction
|
||||
*/
|
||||
/obj/structure/frame/machine/finalize_construction(mob/living/user, obj/item/tool)
|
||||
for(var/component in req_components)
|
||||
if(req_components[component] > 0)
|
||||
user.balloon_alert(user, "missing components!")
|
||||
return FALSE
|
||||
|
||||
tool.play_tool_sound(src)
|
||||
var/obj/machinery/new_machine = new circuit.build_path(loc)
|
||||
if(istype(new_machine))
|
||||
new_machine.clear_components()
|
||||
// Set anchor state
|
||||
new_machine.set_anchored(anchored)
|
||||
// Prevent us from dropping stuff thanks to /Exited
|
||||
var/obj/item/circuitboard/machine/leaving_circuit = circuit
|
||||
circuit = null
|
||||
// Assign the circuit & parts & move them all at once into the machine
|
||||
// no need to seperatly move circuit board as its already part of the components list
|
||||
new_machine.circuit = leaving_circuit
|
||||
new_machine.component_parts = components
|
||||
for (var/obj/new_part in components)
|
||||
new_part.forceMove(new_machine)
|
||||
//Inform machine that its finished & cleanup
|
||||
new_machine.RefreshParts()
|
||||
new_machine.on_construction(user)
|
||||
components = null
|
||||
qdel(src)
|
||||
return TRUE
|
||||
|
||||
/obj/structure/frame/machine/secured
|
||||
state = FRAME_STATE_WIRED
|
||||
anchored = TRUE
|
||||
@@ -2048,6 +2048,7 @@
|
||||
#include "code\game\machinery\launch_pad.dm"
|
||||
#include "code\game\machinery\lightswitch.dm"
|
||||
#include "code\game\machinery\limbgrower.dm"
|
||||
#include "code\game\machinery\machine_frame.dm"
|
||||
#include "code\game\machinery\mass_driver.dm"
|
||||
#include "code\game\machinery\mechlaunchpad.dm"
|
||||
#include "code\game\machinery\medical_kiosk.dm"
|
||||
|
||||
Reference in New Issue
Block a user