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/datum/design/D in files.known_designs)
- if(!(D.build_type & PROTOLATHE) || D.category != name_set)
+ for(var/datum/design/D in design_list)
+ if(D.category != name_set)
continue
- var/temp_dat = "[D.name] ([linked_lathe.output_part_cost(D)])"
+ var/temp_dat = "[D.name]"
+ var/color_modifier = ""//Determines what color the material cost indicator will have in the menu
+ var/material_cost = "" //Each material cost is split up so that it can be colored and added individually
+
var/upTo=20 //How many we can print
-// //Associative list that keeps track of each resource cost.
-// var/list/available_resources = list()
+ var/count = 0 //Tracks when to add "|" between each material cost
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)
+ var/available_prints = linked_lathe.material_print_amount(D, M)
+ if(available_prints < 1)
+ color_modifier = "#ff0000"
+ if(bluespace_available) //See if the bluespace materials can make up for the insufficiency, not compatible with chems
+ var/total_resources = bluespace_materials.getAmount(M) + linked_lathe.materials.getAmount(M)
+ available_prints = total_resources / linked_lathe.get_resource_cost_w_coeff(D, M)
+ if(available_prints >= 1)
+ color_modifier = "#00ffff"
+ material_cost += "[linked_lathe.output_part_cost_individual(D, M)]"
+ count++
+ if(count < D.materials.len)
+ material_cost += " | "
+ upTo = min(upTo, available_prints)
+ color_modifier = "" //Reset the color modifier for the next material cost
+ temp_dat = "[temp_dat] ([material_cost])"
+
if (upTo >= 1) //If we can print at least one item
dat += {"-
[temp_dat] Queue: "}
@@ -991,8 +1013,11 @@ 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]
"
+ design_list -= D //It's now in the printing menu, don't parse this for other part_sets
dat += "
"
+ 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/datum/design/D in files.known_designs)
- if(!(D.build_type & IMPRINTER) || D.category != name_set)
+ for(var/datum/design/D in design_list)
+ if(D.category != name_set)
continue
- var/temp_dat = "[D.name] ([linked_imprinter.output_part_cost(D)])"
- var/upTo=10
+ var/temp_dat = "[D.name]"
+ var/color_modifier = ""
+ var/material_cost = ""
+
+ var/upTo=20
+ var/count = 0
for(var/M in D.materials)
- var/num_units_avail=linked_imprinter.check_mat(D,M)
- if(num_units_avail)
- upTo = min(upTo, num_units_avail)
- else
- upTo = 0
- break
- if (upTo >= 1)
- dat += {"- [temp_dat] Queue: "}
+ var/available_prints = linked_imprinter.material_print_amount(D, M)
+ if(available_prints < 1)
+ color_modifier = "#ff0000"
+ if(copytext(M,1,2) == "$") //Boards require chems but this feature only works with materials
+ if(bluespace_available)
+ var/total_resources = bluespace_materials.getAmount(M) + linked_imprinter.materials.getAmount(M)
+ available_prints = total_resources / linked_imprinter.get_resource_cost_w_coeff(D, M)
+ if(available_prints >= 1)
+ color_modifier = "#00ffff"
+ material_cost += "[linked_imprinter.output_part_cost_individual(D, M)]"
+ count++
+ if(count < D.materials.len)
+ material_cost += " | "
+ upTo = min(upTo, available_prints)
+ color_modifier = ""
+ temp_dat = "[temp_dat] ([material_cost])"
+
+ if (upTo >= 1) //If we can print at least one item
+ dat += {"
-
+ [temp_dat] Queue: "}
if(upTo>=5)
dat += "×5"
if(upTo>=10)
@@ -1082,8 +1136,11 @@ 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]
"
+ design_list -= D
dat += "
"
+ 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."