diff --git a/code/game/machinery/_machinery.dm b/code/game/machinery/_machinery.dm index 2836c8c5da7..a471391ba0e 100644 --- a/code/game/machinery/_machinery.dm +++ b/code/game/machinery/_machinery.dm @@ -119,6 +119,8 @@ var/is_operational = TRUE var/wire_compatible = FALSE + /// stack components inside this machine. Will be initialized and cached only when displaying the parts + var/list/cached_stack_parts = null var/list/component_parts = null //list of all the parts used to build it, if made from certain kinds of frames. var/panel_open = FALSE var/state_open = FALSE @@ -205,6 +207,8 @@ component_parts.Cut() + LAZYCLEARLIST(cached_stack_parts) + QDEL_NULL(circuit) unset_static_power() return ..() @@ -805,13 +809,28 @@ return ..() //we don't have any parts. spawn_frame(disassembled) - for(var/datum/part in component_parts) + for(var/part in component_parts) if(istype(part, /datum/stock_part)) var/datum/stock_part/datum_part = part new datum_part.physical_object_type(loc) else var/obj/item/obj_part = part obj_part.forceMove(loc) + if(istype(obj_part, /obj/item/circuitboard/machine)) + // if the stack parts were initialized in display_parts() then just move them outside + if(cached_stack_parts) + for(var/stack_component in cached_stack_parts) + var/obj/item/stack/stack_ref = cached_stack_parts[stack_component] + stack_ref.forceMove(loc) + cached_stack_parts.Cut() + // else create the stack parts by infering them from the circuit board requested components + else + var/obj/item/circuitboard/machine/board = obj_part + for(var/component in board.req_components) + if(!ispath(component, /obj/item/stack)) + continue + var/obj/item/stack/stack_path = component + new stack_path(loc, board.req_components[component]) LAZYCLEARLIST(component_parts) return ..() @@ -972,29 +991,33 @@ * if the rped first picked up a tier 3 part AND THEN a tier 4 part * tier 3 would be installed and the loop would break and check for the next required component thus * completly ignoring the tier 4 component inside + * we also ignore stack components inside the RPED cause we dont exchange that */ - var/list/part_list = replacer_tool.get_sorted_parts() - for(var/datum/primary_part_base as anything in component_parts) + var/list/part_list = replacer_tool.get_sorted_parts(ignore_stacks = TRUE) + if(!part_list.len) + return FALSE + for(var/primary_part_base as anything in component_parts) + //we exchanged all we could time to bail + if(!part_list.len) + break + var/current_rating var/required_type - if (istype(primary_part_base, /datum/stock_part)) + //we dont exchange circuitboards cause thats dumb + if(istype(primary_part_base, /obj/item/circuitboard)) + continue + else if(istype(primary_part_base, /datum/stock_part)) var/datum/stock_part/primary_stock_part = primary_part_base current_rating = primary_stock_part.tier required_type = primary_stock_part.physical_object_base_type else var/obj/item/primary_stock_part_item = primary_part_base current_rating = primary_stock_part_item.get_part_rating() - for(var/design_type in machine_board.req_components) - if(!ispath(primary_stock_part_item.type, design_type)) - continue - - required_type = design_type - - if (isnull(required_type)) - // Not an error, happens with circuitboards. - continue + if(ispath(primary_stock_part_item.type, design_type)) + required_type = design_type + break for(var/obj/item/secondary_part in part_list) if(!istype(secondary_part, required_type)) @@ -1006,28 +1029,22 @@ if(checked_cell.rigged || checked_cell.corrupted) checked_cell.charge = checked_cell.maxcharge checked_cell.explode() + break if(secondary_part.get_part_rating() > current_rating) - if(istype(secondary_part,/obj/item/stack)) //conveniently this will mean primary_part is also a stack and I will kill the first person to prove me wrong - var/obj/item/stack/primary_stack = primary_part_base - var/obj/item/stack/secondary_stack = secondary_part - var/used_amt = primary_stack.get_amount() - if(!secondary_stack.use(used_amt)) - continue //if we don't have the exact amount to replace we don't - var/obj/item/stack/secondary_inserted = new secondary_stack.merge_type(null,used_amt) - component_parts += secondary_inserted - else - if(replacer_tool.atom_storage.attempt_remove(secondary_part, src)) - if (istype(primary_part_base, /datum/stock_part)) - var/stock_part_datum = GLOB.stock_part_datums_per_object[secondary_part.type] - if (isnull(stock_part_datum)) - CRASH("[secondary_part] ([secondary_part.type]) did not have a stock part datum (was trying to find [primary_part_base])") - component_parts += stock_part_datum - part_list -= secondary_part //have to manually remove cause we are no longer refering replacer_tool.contents - qdel(secondary_part) - else - component_parts += secondary_part - secondary_part.forceMove(src) - part_list -= secondary_part //have to manually remove cause we are no longer refering replacer_tool.contents + //store name of part incase we qdel it below + var/secondary_part_name = secondary_part.name + if(replacer_tool.atom_storage.attempt_remove(secondary_part, src)) + if (istype(primary_part_base, /datum/stock_part)) + var/stock_part_datum = GLOB.stock_part_datums_per_object[secondary_part.type] + if (isnull(stock_part_datum)) + CRASH("[secondary_part] ([secondary_part.type]) did not have a stock part datum (was trying to find [primary_part_base])") + component_parts += stock_part_datum + part_list -= secondary_part //have to manually remove cause we are no longer refering replacer_tool.contents + qdel(secondary_part) + else + component_parts += secondary_part + secondary_part.forceMove(src) + part_list -= secondary_part //have to manually remove cause we are no longer refering replacer_tool.contents component_parts -= primary_part_base @@ -1040,7 +1057,7 @@ physical_part = primary_part_base replacer_tool.atom_storage.attempt_insert(physical_part, user, TRUE) - to_chat(user, span_notice("[capitalize(physical_part.name)] replaced with [secondary_part.name].")) + to_chat(user, span_notice("[capitalize(physical_part.name)] replaced with [secondary_part_name].")) shouldplaysound = TRUE //Only play the sound when parts are actually replaced! break @@ -1050,59 +1067,64 @@ replacer_tool.play_rped_sound() return TRUE +/// get the physical ref of the stack component used in displaying the machine parts +/obj/machinery/proc/get_stack(obj/item/stack/component, amount) + if(!cached_stack_parts) + cached_stack_parts = list() + + if(cached_stack_parts[component]) + return cached_stack_parts[component] + + cached_stack_parts[component] = new component(src, amount) + return cached_stack_parts[component] + /obj/machinery/proc/display_parts(mob/user) var/list/part_count = list() for(var/component_part in component_parts) - var/component_name + var/obj/item/component_ref if (istype(component_part, /datum/stock_part)) var/datum/stock_part/stock_part = component_part - component_name = initial(stock_part.physical_object_type.name) + component_ref = stock_part.physical_object_reference else - var/atom/stock_part = component_part - component_name = stock_part.name + component_ref = component_part + for(var/obj/item/counted_part in part_count) + //e.g. 2 beakers though they have the same type are still 2 different objects so component_ref wont keep them unique so we look for that type ourselves and increment it + if(istype(counted_part, component_ref.type)) + part_count[counted_part]++ + component_ref = null + break + //looks like we already counted an type of this obj reference, time to bail + if(!component_ref) + continue - if(part_count[component_name]) - part_count[component_name]++ + if(part_count[component_ref]) + part_count[component_ref]++ continue + part_count[component_ref] = 1 - if(isstack(component_part)) - var/obj/item/stack/stack_part = component_part - part_count[component_name] = stack_part.amount - else - part_count[component_name] = 1 + // we infer the required stack stuff inside the machine from the circuitboards requested components + if(istype(component_ref, /obj/item/circuitboard/machine)) + var/obj/item/circuitboard/machine/board = component_ref + for(var/component as anything in board.req_components) + if(!ispath(component, /obj/item/stack)) + continue + var/obj/item/stack/stack_path = component + var/obj/item/stack/stack_ref = get_stack(stack_path, board.req_components[component]) + part_count[stack_ref] = stack_ref.amount - var/list/printed_components = list() var/text = span_notice("It contains the following parts:") - for(var/component_part_base in component_parts) - var/atom/component_part - var/component_name - - if (istype(component_part_base, /datum/stock_part)) - var/datum/stock_part/stock_part = component_part_base - component_part = stock_part.physical_object_reference - component_name = initial(stock_part.physical_object_type.name) + for(var/component_part in part_count) + var/part_name + if(isstack(component_part)) + var/obj/item/stack/stack_ref = component_part + part_name = stack_ref.singular_name else - component_part = component_part_base - component_name = component_part.name - - if (!istype(component_part)) - stack_trace("[component_part_base] is not an /atom or a /datum/stock_part (or did not make one)") - continue - - if(printed_components[component_name]) - continue //already printed so skip - - var/part_name = component_name - if (isstack(component_part)) - var/obj/item/stack/stack_part = component_part - part_name = stack_part.singular_name - - text += span_notice("[icon2html(component_part, user)] [part_count[component_name]] [part_name]\s.") - printed_components[component_name] = TRUE - + var/obj/item/part = component_part + part_name = part.name + text += span_notice("[icon2html(component_part, user)] [part_count[component_part]] [part_name]\s.") return text /obj/machinery/examine(mob/user) diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index bb757d99012..565690d5fee 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -297,9 +297,8 @@ return var/obj/item/storage/part_replacer/replacer = P - var/list/added_components = list() + 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)) @@ -314,34 +313,25 @@ 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 - var/NS = new S.merge_type(src, used_amt) - added_components[NS] = path req_components[path] -= used_amt - else - added_components[part] = path - if(replacer.atom_storage.attempt_remove(part, src)) - req_components[path]-- + 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]-- + to_chat(user, span_notice("You add [part] to [src].")) + play_sound = TRUE - for(var/obj/item/part in added_components) - if(istype(part,/obj/item/stack)) - var/obj/item/stack/incoming_stack = part - for(var/obj/item/stack/merge_stack in components) - if(incoming_stack.can_merge(merge_stack)) - incoming_stack.merge(merge_stack) - if(QDELETED(incoming_stack)) - break - if(!QDELETED(part)) //If we're a stack and we merged we might not exist anymore - 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) - to_chat(user, span_notice("You add [part] to [src].")) - if(added_components.len) + if(play_sound) replacer.play_rped_sound() return @@ -366,16 +356,7 @@ if(isstack(P)) var/obj/item/stack/S = P var/used_amt = min(round(S.get_amount()), req_components[stock_part_path]) - if(used_amt && S.use(used_amt)) - var/obj/item/stack/NS = locate(S.merge_type) in components - - if(!NS) - NS = new S.merge_type(src, used_amt) - components += NS - else - NS.add(used_amt) - req_components[stock_part_path] -= used_amt to_chat(user, span_notice("You add [P] to [src].")) return diff --git a/code/game/objects/items/circuitboards/circuitboard.dm b/code/game/objects/items/circuitboards/circuitboard.dm index a71720cc207..7bff3b664d3 100644 --- a/code/game/objects/items/circuitboards/circuitboard.dm +++ b/code/game/objects/items/circuitboards/circuitboard.dm @@ -92,12 +92,12 @@ micro-manipulator, console screen, beaker, Microlaser, matter bin, power cells. comp_path = def_components[comp_path] if(ispath(comp_path, /obj/item/stack)) - machine.component_parts += new comp_path(machine, comp_amt) + continue else if (ispath(comp_path, /datum/stock_part)) + var/stock_part_datum = GLOB.stock_part_datums[comp_path] + if (isnull(stock_part_datum)) + CRASH("[comp_path] didn't have a matching stock part datum") for (var/_ in 1 to comp_amt) - var/stock_part_datum = GLOB.stock_part_datums[comp_path] - if (isnull(stock_part_datum)) - CRASH("[comp_path] didn't have a matching stock part datum") machine.component_parts += stock_part_datum else for(var/component in 1 to comp_amt) diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm index 9642cf3a103..d62674692b5 100644 --- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm +++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm @@ -365,6 +365,23 @@ /obj/item/stack/sheet/plasteel = 5) //Generic +/obj/item/circuitboard/machine/component_printer + name = "\improper Component Printer (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/component_printer + req_components = list( + /datum/stock_part/matter_bin = 2, + /datum/stock_part/manipulator = 2, + ) + +/obj/item/circuitboard/machine/module_duplicator + name = "\improper Module Duplicator (Machine Board)" + greyscale_colors = CIRCUIT_COLOR_SCIENCE + build_path = /obj/machinery/module_duplicator + req_components = list( + /datum/stock_part/matter_bin = 2, + /datum/stock_part/manipulator = 2, + ) /obj/item/circuitboard/machine/circuit_imprinter name = "Circuit Imprinter" diff --git a/code/modules/research/stock_parts.dm b/code/modules/research/stock_parts.dm index 83c492f9356..211bd04d963 100644 --- a/code/modules/research/stock_parts.dm +++ b/code/modules/research/stock_parts.dm @@ -219,12 +219,12 @@ If you create T5+ please take a pass at mech_fabricator.dm. The parts being good lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' -/obj/item/storage/part_replacer/proc/get_sorted_parts() +/obj/item/storage/part_replacer/proc/get_sorted_parts(ignore_stacks = FALSE) var/list/part_list = list() //Assemble a list of current parts, then sort them by their rating! for(var/obj/item/component_part in contents) - //No need to put circuit boards in this list - if(istype(component_part, /obj/item/circuitboard)) + //No need to put circuit boards in this list or stacks when exchanging parts + if(istype(component_part, /obj/item/circuitboard) || (ignore_stacks && istype(component_part, /obj/item/stack))) continue part_list += component_part //Sort the parts. This ensures that higher tier items are applied first. diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 11d888527ff..aad610adf43 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -218,15 +218,6 @@ return data -/obj/item/circuitboard/machine/component_printer - name = "\improper Component Printer (Machine Board)" - greyscale_colors = CIRCUIT_COLOR_SCIENCE - build_path = /obj/machinery/component_printer - req_components = list( - /datum/stock_part/matter_bin = 2, - /datum/stock_part/manipulator = 2, - ) - /obj/machinery/debug_component_printer name = "debug component printer" desc = "Produces components for the creation of integrated circuits." @@ -529,12 +520,3 @@ data[initial(material_type.name)] = materials[material_type] * efficiency_coeff return data - -/obj/item/circuitboard/machine/module_duplicator - name = "\improper Module Duplicator (Machine Board)" - greyscale_colors = CIRCUIT_COLOR_SCIENCE - build_path = /obj/machinery/module_duplicator - req_components = list( - /datum/stock_part/matter_bin = 2, - /datum/stock_part/manipulator = 2, - )