diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index f08ef74269c..75a4792c7cb 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -531,6 +531,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied when the MMI component is added to an [/obj/item/integrated_circuit] #define TRAIT_COMPONENT_PRINTER "component_printer" +/// Trait applied when an integrated circuit/module becomes undupable +#define TRAIT_CIRCUIT_UNDUPABLE "circuit_undupable" + /// If present on a [/mob/living/carbon], will make them appear to have a medium level disease on health HUDs. #define TRAIT_DISEASELIKE_SEVERITY_MEDIUM "diseaselike_severity_medium" diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index c93e263cbcc..124d9f4da47 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -107,16 +107,14 @@ #define CIRCUIT_FLAG_INPUT_SIGNAL (1<<0) /// Creates an output trigger that sends a pulse whenever the component is successfully triggered #define CIRCUIT_FLAG_OUTPUT_SIGNAL (1<<1) -/// Prohibits the component from being duplicated via the module duplicator -#define CIRCUIT_FLAG_UNDUPEABLE (1<<2) /// Marks a circuit component as admin only. Admins will only be able to link/unlink with these circuit components. -#define CIRCUIT_FLAG_ADMIN (1<<3) +#define CIRCUIT_FLAG_ADMIN (1<<2) /// This circuit component does not show in the menu. -#define CIRCUIT_FLAG_HIDDEN (1<<4) +#define CIRCUIT_FLAG_HIDDEN (1<<3) /// This circuit component has been marked as a component that has instant execution and will show up in the UI as so. This will only cause a visual change. -#define CIRCUIT_FLAG_INSTANT (1<<5) +#define CIRCUIT_FLAG_INSTANT (1<<4) /// This circuit component can't be loaded in module component. Saves us some headaches. -#define CIRCUIT_FLAG_REFUSE_MODULE (1<<6) +#define CIRCUIT_FLAG_REFUSE_MODULE (1<<5) // Datatype flags /// The datatype supports manual inputs diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 76d8e75936c..390c85e50f7 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -285,10 +285,13 @@ /// Called when this component is about to be added to an integrated_circuit. /obj/item/circuit_component/proc/add_to(obj/item/integrated_circuit/added_to) + if(circuit_flags & CIRCUIT_FLAG_ADMIN) + ADD_TRAIT(added_to, TRAIT_CIRCUIT_UNDUPABLE, src) return TRUE /// Called when this component is removed from an integrated_circuit. /obj/item/circuit_component/proc/removed_from(obj/item/integrated_circuit/removed_from) + REMOVE_TRAIT(removed_from, TRAIT_CIRCUIT_UNDUPABLE, src) return /** diff --git a/code/modules/wiremod/core/component_printer.dm b/code/modules/wiremod/core/component_printer.dm index 0369dc309a5..3a537d5bb3c 100644 --- a/code/modules/wiremod/core/component_printer.dm +++ b/code/modules/wiremod/core/component_printer.dm @@ -343,46 +343,66 @@ addtimer(CALLBACK(src, .proc/finish_module_print, design), 1.6 SECONDS) /obj/machinery/module_duplicator/proc/finish_module_print(list/design) - var/obj/item/circuit_component/module/module = new(drop_location()) - module.load_data_from_list(design["dupe_data"]) - module.pixel_x = module.base_pixel_x + rand(-5, 5) - module.pixel_y = module.base_pixel_y + rand(-5, 5) + var/atom/movable/created_atom + if(design["integrated_circuit"]) + var/obj/item/integrated_circuit/circuit = new(drop_location()) + var/list/errors = list() + circuit.load_circuit_data(design["dupe_data"], errors) + if(length(errors)) + stack_trace("Error loading user saved circuit [errors.Join(", ")].") + created_atom = circuit + else + var/obj/item/circuit_component/module/module = new(drop_location()) + module.load_data_from_list(design["dupe_data"]) + created_atom = module + created_atom.pixel_x = created_atom.base_pixel_x + rand(-5, 5) + created_atom.pixel_y = created_atom.base_pixel_y + rand(-5, 5) /obj/machinery/module_duplicator/attackby(obj/item/weapon, mob/user, params) - if(!istype(weapon, /obj/item/circuit_component/module)) + var/list/data = list() + + if(istype(weapon, /obj/item/circuit_component/module)) + var/obj/item/circuit_component/module/module = weapon + if(HAS_TRAIT(module, TRAIT_CIRCUIT_UNDUPABLE)) + balloon_alert(user, "integrated circuit cannot be saved!") + return ..() + + data["dupe_data"] = list() + module.save_data_to_list(data["dupe_data"]) + + data["name"] = module.display_name + data["desc"] = "A module that has been loaded in by [user]." + data["materials"] = list(GET_MATERIAL_REF(/datum/material/glass) = module.circuit_size * cost_per_component) + else if(istype(weapon, /obj/item/integrated_circuit)) + var/obj/item/integrated_circuit/integrated_circuit = weapon + if(HAS_TRAIT(integrated_circuit, TRAIT_CIRCUIT_UNDUPABLE)) + balloon_alert(user, "integrated circuit cannot be saved!") + return ..() + data["dupe_data"] = integrated_circuit.convert_to_json() + + data["name"] = integrated_circuit.display_name + data["desc"] = "An integrated circuit that has been loaded in by [user]." + + var/datum/design/integrated_circuit/circuit_design = SSresearch.techweb_design_by_id("integrated_circuit") + var/materials = list(GET_MATERIAL_REF(/datum/material/glass) = integrated_circuit.current_size * cost_per_component) + for(var/material_type in circuit_design.materials) + materials[material_type] += circuit_design.materials[material_type] + + data["materials"] = materials + data["integrated_circuit"] = TRUE + + if(!length(data)) return ..() - var/obj/item/circuit_component/module/module = weapon - if(module.circuit_flags & CIRCUIT_FLAG_UNDUPEABLE) - balloon_alert(user, "module cannot be saved!") - return ..() - - if(module.display_name == initial(module.display_name)) - balloon_alert(user, "module needs a name!") + if(!data["name"]) + balloon_alert(user, "it needs a name!") return ..() for(var/list/component_data as anything in scanned_designs) - if(component_data["name"] == module.display_name) - balloon_alert(user, "module name already exists!") + if(component_data["name"] == data["name"]) + balloon_alert(user, "name already exists!") return ..() - var/total_cost = 0 - for(var/obj/item/circuit_component/component as anything in module.internal_circuit.attached_components) - if(component.circuit_flags & CIRCUIT_FLAG_UNDUPEABLE) - balloon_alert(user, "module contains prohibited components!") - return ..() - - total_cost += cost_per_component - - var/list/data = list() - - data["dupe_data"] = list() - module.save_data_to_list(data["dupe_data"]) - - data["name"] = module.display_name - data["desc"] = "A module that has been loaded in by [user]." - data["materials"] = list(/datum/material/glass = total_cost) - flick("module-fab-scan", src) addtimer(CALLBACK(src, .proc/finish_module_scan, user, data), 1.4 SECONDS)