From a35160b7cd69914e0707fd79e65448dd46e82ad0 Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Mon, 1 Jun 2026 12:24:15 +0300 Subject: [PATCH 1/6] stuff --- code/modules/research/rdconsole.dm | 69 +++++++++++++++--------------- code/modules/research/research.dm | 4 +- 2 files changed, 37 insertions(+), 36 deletions(-) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 24617227630b..b38a65a5c321 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -35,38 +35,38 @@ won't update every console in existence) but it's more of a hassle to do. Also, // Defines for what used to be magic numbers. // The code partially relies on numbers to tell what device is supposed to show up (2.x = Protolathe for example). // The (machine)_UPPER_LIMIT defines are used due to the aforementioned. -#define DATABASE_UPDATE 0.0 -#define DATABASE_PROCESS 0.1 -#define CONSOLE_LOCKED 0.2 -#define PROTOLATHE_BUILD 0.3 -#define CIRCUIT_BUILD 0.4 - -#define CONSOLE_MENU 1.0 -#define CONSOLE_RESEARCH_MENU 1.1 -#define CONSOLE_DISK_TECH_MENU 1.2 -#define CONSOLE_DISK_TECH_DOWNLOAD_MENU 1.3 -#define CONSOLE_DISK_DESIGN_MENU 1.4 -#define CONSOLE_DISK_DESIGN_DOWNLOAD_MENU 1.5 -#define CONSOLE_SETTINGS_MENU 1.6 -#define CONSOLE_LINKAGE_MENU 1.7 - -#define DA_UNLINKED 2.0 -#define DA_NO_ITEM_LOADED 2.1 -#define DA_ITEM_LOADED 2.2 -#define DA_UPPER_LIMIT 2.9 - -#define PROTOLATHE_UNLINKED 3.0 -#define PROTOLATHE_MENU 3.1 -#define PROTOLATHE_RESOURCE_MENU 3.2 -#define PROTOLATHE_QUEUE_MENU 3.4 -#define PROTOLATHE_UPPER_LIMIT 3.9 - -#define CIRCUIT_UNLINKED 4.0 -#define CIRCUIT_MENU 4.1 -#define CIRCUIT_CHEMICAL_MENU 4.2 -#define CIRCUIT_RESOURCE_MENU 4.3 -#define CIRCUIT_QUEUE_MENU 4.4 -#define CIRCUIT_UPPER_LIMIT 4.9 +#define DATABASE_UPDATE 0 +#define DATABASE_PROCESS 1 +#define CONSOLE_LOCKED 2 +#define PROTOLATHE_BUILD 3 +#define CIRCUIT_BUILD 4 + +#define CONSOLE_MENU 10 +#define CONSOLE_RESEARCH_MENU 11 +#define CONSOLE_DISK_TECH_MENU 12 +#define CONSOLE_DISK_TECH_DOWNLOAD_MENU 13 +#define CONSOLE_DISK_DESIGN_MENU 14 +#define CONSOLE_DISK_DESIGN_DOWNLOAD_MENU 15 +#define CONSOLE_SETTINGS_MENU 16 +#define CONSOLE_LINKAGE_MENU 17 + +#define DA_UNLINKED 20 +#define DA_NO_ITEM_LOADED 21 +#define DA_ITEM_LOADED 22 +#define DA_UPPER_LIMIT 29 + +#define PROTOLATHE_UNLINKED 30 +#define PROTOLATHE_MENU 31 +#define PROTOLATHE_RESOURCE_MENU 32 +#define PROTOLATHE_QUEUE_MENU 34 +#define PROTOLATHE_UPPER_LIMIT 39 + +#define CIRCUIT_UNLINKED 40 +#define CIRCUIT_MENU 41 +#define CIRCUIT_CHEMICAL_MENU 42 +#define CIRCUIT_RESOURCE_MENU 43 +#define CIRCUIT_QUEUE_MENU 44 +#define CIRCUIT_UPPER_LIMIT 49 /obj/machinery/computer/rdconsole name = "R&D Console" @@ -739,7 +739,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, return user.set_machine(src) - var/dat = list() + var/dat = "" files.RefreshResearch() switch(screen) //A quick check to make sure you get the right screen when a device is disconnected. if(DA_UNLINKED to DA_UPPER_LIMIT) @@ -969,6 +969,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(num_units_avail) upTo = min(upTo, num_units_avail) else + upTo = 0 break if (upTo) dat += {"
  • @@ -1062,6 +1063,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(num_units_avail) upTo = min(upTo, num_units_avail) else + upTo = 0 break if (upTo) dat += {"
  • [temp_dat] Queue: "} @@ -1149,7 +1151,6 @@ won't update every console in existence) but it's more of a hassle to do. Also, else dat += "Stop Production" - dat = jointext(dat,"") var/datum/browser/popup = new(user, "\ref[src]", name, 575, 400) popup.set_content(dat) popup.open() diff --git a/code/modules/research/research.dm b/code/modules/research/research.dm index 03f3dc800630..3bc957484316 100644 --- a/code/modules/research/research.dm +++ b/code/modules/research/research.dm @@ -62,7 +62,7 @@ var/global/list/all_tech = list() tech_list[T.id] = T all_tech[T.id] = T if(!design_list.len) - for(var/D in typesof(/datum/design) - /datum/design) + for(var/D in typesof(/datum/design) - /datum/design - /datum/design/medal) design_list += new D() RefreshResearch() @@ -268,7 +268,7 @@ var/global/list/all_tech = list() goal_level=0 // Doesn't count towards maxed research, since it's bonus. max_level=8 new_category = "Nanotrasen" - + /datum/tech/alien name = "Alien Technology" desc = "Resarch found in distant systems operated by grays." From 46d6e3927280d82425f73c7f8a8db242d3ddc558 Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Mon, 1 Jun 2026 17:15:50 +0300 Subject: [PATCH 2/6] Update rdconsole.dm --- code/modules/research/rdconsole.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index b38a65a5c321..9ae6e91069cb 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -971,7 +971,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, else upTo = 0 break - if (upTo) + if (upTo >= 1) //If we can print at least one item dat += {"
  • [temp_dat] Queue: "} if(upTo>=5) From 7915404c4c560d489d4434c84fb9cd90f798bf74 Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Wed, 3 Jun 2026 06:49:18 +0300 Subject: [PATCH 3/6] 1 --- code/modules/research/fabricators.dm | 3 +++ code/modules/research/rdconsole.dm | 14 +++++++++++--- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/code/modules/research/fabricators.dm b/code/modules/research/fabricators.dm index 72067f05c019..93099a65c54b 100644 --- a/code/modules/research/fabricators.dm +++ b/code/modules/research/fabricators.dm @@ -307,6 +307,9 @@ return INFINITY return round(reagent_total / cost) +//Copypasted proc that checks for bluespace resources specifically +/obj/machinery/r_n_d/fabricator/proc/check_mat_with_bluespace(var/datum/design/being_built, var/M) + //The build_part_loop fires independently and will build stuff until the queue is over or when it is stopped. /obj/machinery/r_n_d/fabricator/proc/build_part_loop() if(busy || stopped || being_built || stat&(NOPOWER|BROKEN|FORCEDISABLE) || queue.len == 0) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 9ae6e91069cb..72ded842c005 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -963,14 +963,22 @@ won't update every console in existence) but it's more of a hassle to do. Also, if(!(D.build_type & PROTOLATHE) || D.category != name_set) continue var/temp_dat = "[D.name] ([linked_lathe.output_part_cost(D)])" - var/upTo=20 + var/upTo=20 //How many we can print +// //Associative list that keeps track of each resource cost. +// var/list/available_resources = list() for(var/M in D.materials) var/num_units_avail=linked_lathe.check_mat(D,M) +// available_resources += M if(num_units_avail) upTo = min(upTo, num_units_avail) else + num_units_avail = linked_lathe.check_mats_bluespace(M) upTo = 0 break + //if(!upTo) //Check if it can be printed with bluespace items instead + // for(var/M in D.materials) + // var/bluespace_resources = linked_lathe.check_mats_bluespace(M) + // if(bluespace_resources) if (upTo >= 1) //If we can print at least one item dat += {"
  • [temp_dat] Queue: "} @@ -983,7 +991,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, dat += "Custom" dat += "
  • " else - dat += "
  • [temp_dat]
  • " + dat += "
  • [temp_dat]
  • " dat += "" if(PROTOLATHE_RESOURCE_MENU) //Protolathe Material Storage Sub-menu @@ -1065,7 +1073,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, else upTo = 0 break - if (upTo) + if (upTo >= 1) dat += {"
  • [temp_dat] Queue: "} if(upTo>=5) dat += "×5" From 0369774c8cfb11d5d28d0234f5d8c701899671db Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Thu, 4 Jun 2026 17:55:05 +0300 Subject: [PATCH 4/6] more stuff --- code/modules/research/fabricators.dm | 150 +++++++++++++++++++++------ code/modules/research/rdconsole.dm | 119 +++++++++++++++------ 2 files changed, 206 insertions(+), 63 deletions(-) diff --git a/code/modules/research/fabricators.dm b/code/modules/research/fabricators.dm index 93099a65c54b..3268ad751373 100644 --- a/code/modules/research/fabricators.dm +++ b/code/modules/research/fabricators.dm @@ -6,6 +6,10 @@ #define FAB_MAT_BASEMOD 100 +//Keeps track of fabricators with bluespace materials in them +//Improved alternative over checking every single machine in the game to see if it has bluespace bins in it. +var/global/list/bluespace_fabricators = list() +var/datum/materials/bluespace_materials = new /obj/machinery/r_n_d/fabricator desc = "A fabricator. What kind, you don't know." @@ -63,6 +67,14 @@ T += M.rating - 1 max_material_storage = (initial(max_material_storage)+(T * 187500)) update_coeff() + if(has_bluespace_bin()) + bluespace_fabricators |= src + else + bluespace_fabricators -= src + +/obj/machinery/r_n_d/fabricator/Destroy() + ..() + bluespace_fabricators -= src //A separate proc for updating the machine's coefficiency ratings /obj/machinery/r_n_d/fabricator/update_coeff() @@ -225,9 +237,23 @@ output += "[output ? " | " : null][get_resource_cost_w_coeff(part,M)] [chemical_reagents_list[M]]" return output +//Same as output_part_cost but only for a specific resource +/obj/machinery/r_n_d/fabricator/proc/output_part_cost_individual(var/datum/design/part, var/specific_material) + var/output = "" + for(var/M in part.materials) + if(M == specific_material) + if(copytext(M, 1, 2) == "$") + if(!(research_flags & IGNORE_MATS)) + var/datum/material/material = materials.getMaterial(M) + output = "[get_resource_cost_w_coeff(part,M)] [material.processed_name]" + else //It's a chem, not a material + if(!(research_flags & IGNORE_CHEMS)) + output = "[get_resource_cost_w_coeff(part,M)] [chemical_reagents_list[M]]" + return output + /obj/machinery/r_n_d/fabricator/proc/remove_materials(var/datum/design/part) for(var/M in part.materials) - if(!check_mat(part, M)) + if(!material_print_amount(part, M)) return 0 for(var/M in part.materials) @@ -256,16 +282,76 @@ if(!has_bluespace_bin()) return 0 - for (var/obj/machinery/r_n_d/fabricator/gibmats in machines) - if(gibmats.has_bluespace_bin()) - for(var/gib in part.materials) - if (gibmats.check_mat(part,gib) && !check_mat(part,gib))//they have what we need && we don't need more - if(copytext(gib,1,2) == "$" && !(research_flags & IGNORE_MATS)) - var/bluespaceamount = get_resource_cost_w_coeff(part, gib) - gibmats.materials.removeAmount(gib,bluespaceamount) - materials.addAmount(gib,bluespaceamount) + for (var/obj/machinery/r_n_d/fabricator/gibmats in bluespace_fabricators) + for(var/gib in part.materials) + if (gibmats.material_print_amount(part,gib) && !material_print_amount(part,gib))//they have what we need && we don't need more + if(copytext(gib,1,2) == "$" && !(research_flags & IGNORE_MATS)) + var/bluespaceamount = get_resource_cost_w_coeff(part, gib) + gibmats.materials.removeAmount(gib,bluespaceamount) + materials.addAmount(gib,bluespaceamount) return remove_materials(part) +//Proc for checking whether there's enough materials +/obj/machinery/r_n_d/fabricator/proc/enough_materials(var/datum/design/part) + var/resource_amount + for(var/M in part.materials) + var/is_material = copytext(M,1,2) == "$" + var/material_cost = get_resource_cost_w_coeff(part, M) //Don't call this proc multiple times + resource_amount = check_mats(M) + if(resource_amount >= material_cost) //Do we have enough materials? + continue + if((research_flags & IGNORE_MATS) && is_material) + continue + else if((research_flags & IGNORE_CHEMS) && !is_material) + continue + //Has access to bluespace and are there other machines? + if(has_bluespace_bin() && is_material) //Materials only, no chems + var/total_bluespace_amount //Keep track of how many resources there are + var/list/other_fabricators = bluespace_fabricators - src + for(var/obj/machinery/r_n_d/fabricator/F in other_fabricators) + total_bluespace_amount += F.check_mats(M) + if((total_bluespace_amount + resource_amount) >= material_cost) //Are there enough materials in the bluespace network to cover the cost? + continue + return 0 //Not enough materials + return 1 + +//Does the actual material taking, and should be called after enough_materials() +//A lot of redundancy with the enough_materials() proc but this prevents an odd case where some materials would be swapped between +//fabricators due to there not being sufficient materials midway through the material transfer +/obj/machinery/r_n_d/fabricator/proc/take_materials(var/datum/design/part) + var/resource_amount + for(var/M in part.materials) + var/is_material = copytext(M,1,2) == "$" + var/material_cost = get_resource_cost_w_coeff(part, M) + resource_amount = check_mats(M) + if((research_flags & IGNORE_MATS) && is_material) + continue + else if((research_flags & IGNORE_CHEMS) && !is_material) + continue + if(resource_amount >= material_cost) + if(is_material) + materials.removeAmount(M, material_cost) + else //It's a chemical + for(var/obj/item/weapon/reagent_containers/RC in component_parts) + var/remove_amount = min(RC.reagents.get_reagent_amount(M), material_cost) + RC.reagents.remove_reagent(M, remove_amount) + material_cost -= remove_amount + if(material_cost <= 0) + break + update_buffer_size() + else if(has_bluespace_bin() && is_material) //Now extract per fabricator + var/list/other_fabricators = bluespace_fabricators - src + if(other_fabricators.len) + for(var/obj/machinery/r_n_d/fabricator/F in other_fabricators) + var/remove_amount = min(F.check_mats(M), material_cost) + F.materials.removeAmount(M, remove_amount) + material_cost -= remove_amount + if(material_cost <= 0) + break + if(material_cost > 0) + warning("Bluespace matter bins did not consume a 1:1 amount of material, please yell at a coder.") + return 1 + //Returns however much of that material we have /obj/machinery/r_n_d/fabricator/proc/check_mats(var/material) if(copytext(material,1,2) == "$")//It's iron/gold/glass @@ -282,45 +368,44 @@ return 0 var/amount - for(var/obj/machinery/r_n_d/fabricator/gibmats in machines) - if(gibmats.has_bluespace_bin()) - amount += gibmats.materials.getAmount(material) + for(var/obj/machinery/r_n_d/fabricator/gibmats in bluespace_fabricators) + amount += gibmats.materials.getAmount(material) return amount - -/obj/machinery/r_n_d/fabricator/proc/check_mat(var/datum/design/being_built, var/M) +//How many times a resource cost is covered +/obj/machinery/r_n_d/fabricator/proc/material_print_amount(var/datum/design/being_built, var/M) if(copytext(M,1,2) == "$") if(research_flags & IGNORE_MATS) - return 1 + return 100 //Arbitrary value meaning that you can print the material 100 times var/cost = get_resource_cost_w_coeff(being_built, M) if(cost <= 0) - return INFINITY - return round(materials.storage[M] / cost) + return 100 + return floor(materials.storage[M] / cost) else if(research_flags & IGNORE_CHEMS) - return 1 + return 100 var/reagent_total = 0 for(var/obj/item/weapon/reagent_containers/RC in component_parts) reagent_total += RC.reagents.get_reagent_amount(M) var/cost = get_resource_cost_w_coeff(being_built, M) if(cost <= 0) - return INFINITY - return round(reagent_total / cost) - -//Copypasted proc that checks for bluespace resources specifically -/obj/machinery/r_n_d/fabricator/proc/check_mat_with_bluespace(var/datum/design/being_built, var/M) + return 100 + return floor(reagent_total / cost) //The build_part_loop fires independently and will build stuff until the queue is over or when it is stopped. /obj/machinery/r_n_d/fabricator/proc/build_part_loop() + while(build_part_loop_check()) + var/datum/design/D = queue_pop() + if(!build_part(D)) + if(D) + queue.Add(D) + stop_processing_queue() + sleep(fabricator_cooldown) + +/obj/machinery/r_n_d/fabricator/proc/build_part_loop_check() if(busy || stopped || being_built || stat&(NOPOWER|BROKEN|FORCEDISABLE) || queue.len == 0) - return - var/datum/design/D = queue_pop() - if(!build_part(D)) - if(D) - queue.Add(D) - stop_processing_queue() - sleep(fabricator_cooldown) - build_part_loop() + return 0 + return 1 /obj/machinery/r_n_d/fabricator/proc/build_part(var/datum/design/part) if(!part || being_built) //we're in the middle of something here! @@ -334,10 +419,11 @@ visible_message("The [name] buzzes, \"Safety procedures prevent current queued item from being built.\"") return - if(!remove_materials(part) && !bluespace_materials(part)) + if(!enough_materials(part)) stopped = 1 visible_message("The [name] beeps, \"Not enough materials to complete item.\"") return + take_materials(part) being_built = new part.build_path(src) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 72ded842c005..67e4fee97786 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -122,6 +122,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, "Armor" = list(), "Misc" = list(), ) + var/datum/materials/bluespace_materials = new //A dummy list that keeps track of bluespace resources for printing purposes. /obj/machinery/computer/rdconsole/Destroy() . = ..() @@ -144,6 +145,8 @@ won't update every console in existence) but it's more of a hassle to do. Also, linked_lathe.linked_console = null linked_lathe.update_icon() linked_lathe = null + if(bluespace_materials) + QDEL_NULL(bluespace_materials) /obj/machinery/computer/rdconsole/proc/Maximize() for(var/ID in files.known_tech) @@ -955,30 +958,49 @@ won't update every console in existence) but it's more of a hassle to do. Also, dat += "[name_set] " dat += "Filter All" + var/list/design_list = files.known_designs.Copy() + for(var/datum/design/D in design_list) + if(!(D.build_type & PROTOLATHE)) //Remove incompatible designs from the list + design_list -= D + + var/bluespace_available = FALSE // A toggle variable to avoid doing unnecessary checking of whether the list has any materials at all + if(linked_lathe.has_bluespace_bin()) + for(var/obj/machinery/r_n_d/fabricator/F in bluespace_fabricators - linked_lathe) //Don't include the machine itself + for(var/mat_id in F.materials.storage) + bluespace_materials.storage[mat_id] += F.materials.getAmount(mat_id) + if(bluespace_materials.getVolume()) //We have materials + bluespace_available = TRUE //So we don't have to call getVolume() for every single design + for(var/name_set in linked_lathe.part_sets) if(name_set in filtered["protolathe"]) continue dat += "

    [name_set]

    " + for(var/mat_id in bluespace_materials.storage) //Clean up the dummy list + bluespace_materials.storage[mat_id] = 0 if(PROTOLATHE_RESOURCE_MENU) //Protolathe Material Storage Sub-menu @@ -1057,24 +1082,53 @@ won't update every console in existence) but it's more of a hassle to do. Also, dat += "[name_set] " dat += "Filter All
    " + var/list/design_list = files.known_designs.Copy() + for(var/datum/design/D in design_list) + if(!(D.build_type & IMPRINTER)) + design_list -= D + + var/bluespace_available = FALSE + if(linked_imprinter.has_bluespace_bin()) + for(var/obj/machinery/r_n_d/fabricator/F in bluespace_fabricators - linked_imprinter) + for(var/mat_id in F.materials.storage) + bluespace_materials.storage[mat_id] += F.materials.getAmount(mat_id) + if(bluespace_materials.getVolume()) //We have materials + bluespace_available = TRUE //So we don't have to call getVolume() for every single design + for(var/name_set in linked_imprinter.part_sets) if(name_set in filtered["imprinter"]) continue dat += "

    [name_set]

    " + for(var/mat_id in bluespace_materials.storage) //Clean up the dummy list + bluespace_materials.storage[mat_id] = 0 if(CIRCUIT_CHEMICAL_MENU) From 3306b01ca5a3fe6151622d9061d82410341de26a Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Thu, 4 Jun 2026 18:07:37 +0300 Subject: [PATCH 5/6] Update rdconsole.dm --- code/modules/research/rdconsole.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/research/rdconsole.dm b/code/modules/research/rdconsole.dm index 67e4fee97786..42ebcb642a6d 100644 --- a/code/modules/research/rdconsole.dm +++ b/code/modules/research/rdconsole.dm @@ -1106,7 +1106,7 @@ won't update every console in existence) but it's more of a hassle to do. Also, var/color_modifier = "" var/material_cost = "" - var/upTo=20 + var/upTo=10 var/count = 0 for(var/M in D.materials) var/available_prints = linked_imprinter.material_print_amount(D, M) From 77d452f78f9aa70cf4bc16ce77fbc5f9c7b8a174 Mon Sep 17 00:00:00 2001 From: boy2mantwicethefam <41342767+boy2mantwicethefam@users.noreply.github.com> Date: Tue, 9 Jun 2026 20:46:57 +0300 Subject: [PATCH 6/6] Update fabricators.dm --- code/modules/research/fabricators.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/research/fabricators.dm b/code/modules/research/fabricators.dm index 3268ad751373..3157ef5980e3 100644 --- a/code/modules/research/fabricators.dm +++ b/code/modules/research/fabricators.dm @@ -9,7 +9,6 @@ //Keeps track of fabricators with bluespace materials in them //Improved alternative over checking every single machine in the game to see if it has bluespace bins in it. var/global/list/bluespace_fabricators = list() -var/datum/materials/bluespace_materials = new /obj/machinery/r_n_d/fabricator desc = "A fabricator. What kind, you don't know."