From dc357ab2f726f384c694b461fe559466d3913846 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sun, 21 Dec 2025 07:19:22 -0600 Subject: [PATCH] Limits the amount of distinct chems that can be held in chemistry factory outputs (#93991) --- code/__DEFINES/plumbing.dm | 5 ++ code/datums/components/plumbing/_plumbing.dm | 68 +++++++++++++++---- .../components/plumbing/automated_iv.dm | 11 ++- .../components/plumbing/reaction_chamber.dm | 2 - .../components/plumbing/simple_components.dm | 4 ++ code/game/machinery/iv_drip.dm | 7 -- code/modules/plumbing/plumbers/bottler.dm | 2 +- code/modules/plumbing/plumbers/iv_drip.dm | 2 +- code/modules/plumbing/plumbers/pill_press.dm | 2 +- .../plumbing/plumbers/simple_machines.dm | 2 +- .../chemistry/machinery/smoke_machine.dm | 2 +- 11 files changed, 71 insertions(+), 36 deletions(-) diff --git a/code/__DEFINES/plumbing.dm b/code/__DEFINES/plumbing.dm index 432f8ca4357..2168a0a0cfd 100644 --- a/code/__DEFINES/plumbing.dm +++ b/code/__DEFINES/plumbing.dm @@ -10,3 +10,8 @@ /// Name of omni color #define DUCT_COLOR_OMNI "omni" + +///IV drip operation mode when it sucks blood from the object +#define IV_TAKING 0 +///IV drip operation mode when it injects reagents into the object +#define IV_INJECTING 1 diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index b6319116b6c..cc454d4327c 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -26,6 +26,9 @@ var/supply_color = COLOR_BLUE ///Extend the pipe to the edge for wall-mounted plumbed devices, like sinks and showers var/extend_pipe_to_edge = FALSE + /// How many distinct reagents can we accept at once + /// Ex - if this was set to "3", our component would only request the first 3 reagents found, even if more are available + var/distinct_reagent_cap = INFINITY ///turn_connects is for wheter or not we spin with the object to change our pipes /datum/component/plumbing/Initialize(start=TRUE, ducting_layer, turn_connects=TRUE, datum/reagents/custom_receiver, extend_pipe_to_edge = FALSE) @@ -55,10 +58,19 @@ RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(create_overlays)) //called by lateinit on startup RegisterSignal(parent, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_parent_dir_change)) //called when placed on a shuttle and it moves, and other edge cases RegisterSignal(parent, COMSIG_MOVABLE_CHANGE_DUCT_LAYER, PROC_REF(change_ducting_layer)) + RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) /datum/component/plumbing/UnregisterFromParent() - UnregisterSignal(parent, list(COMSIG_MOVABLE_MOVED, COMSIG_QDELETING, COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, COMSIG_OBJ_HIDE, \ - COMSIG_ATOM_UPDATE_OVERLAYS, COMSIG_ATOM_DIR_CHANGE, COMSIG_MOVABLE_CHANGE_DUCT_LAYER)) + UnregisterSignal(parent, list( + COMSIG_MOVABLE_MOVED, + COMSIG_QDELETING, + COMSIG_OBJ_DEFAULT_UNFASTEN_WRENCH, + COMSIG_OBJ_HIDE, + COMSIG_ATOM_UPDATE_OVERLAYS, + COMSIG_ATOM_DIR_CHANGE, + COMSIG_MOVABLE_CHANGE_DUCT_LAYER, + COMSIG_ATOM_EXAMINE, + )) REMOVE_TRAIT(parent, TRAIT_UNDERFLOOR, REF(src)) /datum/component/plumbing/Destroy() @@ -76,6 +88,12 @@ if(D & demand_connects) send_request(D) +/datum/component/plumbing/proc/on_examine(atom/movable/source, mob/user, list/examine_list) + SIGNAL_HANDLER + + if(distinct_reagent_cap != INFINITY) + examine_list += span_notice("This plumbing component will only accept up to [distinct_reagent_cap] distinct reagents at once.") + ///Can we be added to the ductnet? /datum/component/plumbing/proc/can_add(datum/ductnet/ductnet, dir) if(!active) @@ -89,22 +107,44 @@ ///called from in process(). only calls process_request(), but can be overwritten for children with special behaviour /datum/component/plumbing/proc/send_request(dir) - process_request(dir = dir) + var/amount_to_give = MACHINE_REAGENT_TRANSFER + // infinite cap means we need to special handling, process_request will just grab as much as it wants. + if(distinct_reagent_cap == INFINITY) + process_request(amount_to_give, null, dir) // null for no specific reagent, we're not picky. + return + + // we have a cap, so we need to figure out what reagents we want + var/list/all_allowed_reagents = get_all_network_reagents(ducts["[dir]"]) + if(length(all_allowed_reagents) > distinct_reagent_cap) + all_allowed_reagents.Cut(distinct_reagent_cap + 1) + else if(!length(all_allowed_reagents)) + return + + // request an even amount of each allowed reagent + var/amount_per_reagent = round(amount_to_give / length(all_allowed_reagents), CHEMICAL_VOLUME_ROUNDING) + for(var/allowed_reagent in all_allowed_reagents) + process_request(amount_per_reagent, allowed_reagent, dir) + +/// Returns a list of all distinct reagent types available in the passed duct network. +/// The passed net can be null, it is handled. +/datum/component/plumbing/proc/get_all_network_reagents(datum/ductnet/net) + var/list/distinct_reagents = list() + for(var/datum/reagent/existing_regent as anything in reagents.reagent_list) + distinct_reagents |= existing_regent.type + for(var/datum/component/plumbing/supplier as anything in net?.suppliers) + for(var/datum/reagent/chemical as anything in supplier.reagents.reagent_list) + distinct_reagents |= chemical.type + return distinct_reagents ///check who can give us what we want, and how many each of them will give us /datum/component/plumbing/proc/process_request(amount = MACHINE_REAGENT_TRANSFER, reagent, dir, round_robin = TRUE) - //find the duct to take from - var/datum/ductnet/net - if(!ducts.Find(num2text(dir))) - return FALSE - net = ducts[num2text(dir)] - + var/datum/ductnet/net = ducts["[dir]"] //find all valid suppliers in the duct var/list/valid_suppliers = list() - for(var/datum/component/plumbing/supplier as anything in net.suppliers) + for(var/datum/component/plumbing/supplier as anything in net?.suppliers) if(supplier.can_give(amount, reagent, net)) valid_suppliers += supplier - var/suppliersLeft = valid_suppliers.len + var/suppliersLeft = length(valid_suppliers) if(!suppliersLeft) return FALSE @@ -122,12 +162,10 @@ SHOULD_BE_PURE(TRUE) if(amount <= 0) - return + return FALSE if(reagent) //only asked for one type of reagent - for(var/datum/reagent/contained_reagent as anything in reagents.reagent_list) - if(contained_reagent.type == reagent) - return TRUE + return reagents.has_reagent(reagent) else if(reagents.total_volume) //take whatever return TRUE diff --git a/code/datums/components/plumbing/automated_iv.dm b/code/datums/components/plumbing/automated_iv.dm index 15639d85251..1f067a7b1e8 100644 --- a/code/datums/components/plumbing/automated_iv.dm +++ b/code/datums/components/plumbing/automated_iv.dm @@ -4,7 +4,7 @@ ///Temporary holder to store all the reagents from the iv drip before transferring it to the ducts var/datum/reagents/plumbing/holder -/datum/component/plumbing/automated_iv/Initialize(start=TRUE, _ducting_layer, _turn_connects=TRUE, datum/reagents/custom_receiver) +/datum/component/plumbing/automated_iv/Initialize(start = TRUE, _ducting_layer, _turn_connects = TRUE, datum/reagents/custom_receiver, distinct_reagent_cap = 3) . = ..() if(!istype(parent, /obj/machinery/iv_drip/plumbing)) return COMPONENT_INCOMPATIBLE @@ -17,16 +17,13 @@ return ..() /datum/component/plumbing/automated_iv/can_give(amount, reagent) - . = ..() - if(!.) - return var/obj/machinery/iv_drip/plumbing/drip = parent - return drip.mode == 0 + return ..() && drip.mode == IV_TAKING /datum/component/plumbing/automated_iv/send_request(dir) var/obj/machinery/iv_drip/plumbing/drip = parent - if(drip.mode == 1) - process_request(dir = dir) + if(drip.mode == IV_INJECTING) + return ..() /datum/component/plumbing/automated_iv/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net, round_robin = TRUE) reagents.trans_to(holder, reagents.total_volume) diff --git a/code/datums/components/plumbing/reaction_chamber.dm b/code/datums/components/plumbing/reaction_chamber.dm index 07ea18e13da..3332d94b094 100644 --- a/code/datums/components/plumbing/reaction_chamber.dm +++ b/code/datums/components/plumbing/reaction_chamber.dm @@ -83,5 +83,3 @@ /datum/component/plumbing/alkaline_input/send_request(dir) process_request(reagent = /datum/reagent/reaction_agent/basic_buffer, dir = dir) - - diff --git a/code/datums/components/plumbing/simple_components.dm b/code/datums/components/plumbing/simple_components.dm index 1378780353a..98fa64f885a 100644 --- a/code/datums/components/plumbing/simple_components.dm +++ b/code/datums/components/plumbing/simple_components.dm @@ -3,6 +3,10 @@ /datum/component/plumbing/simple_demand demand_connects = SOUTH +/datum/component/plumbing/simple_demand/Initialize(start, ducting_layer, turn_connects, datum/reagents/custom_receiver, extend_pipe_to_edge, distinct_reagent_cap = INFINITY) + src.distinct_reagent_cap = distinct_reagent_cap + return ..() + ///has one pipe output that only supplies. example is liquid pump and manual input pipe /datum/component/plumbing/simple_supply supply_connects = SOUTH diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm index e48d342b12a..8e400fc964a 100644 --- a/code/game/machinery/iv_drip.dm +++ b/code/game/machinery/iv_drip.dm @@ -1,7 +1,3 @@ -///IV drip operation mode when it sucks blood from the object -#define IV_TAKING 0 -///IV drip operation mode when it injects reagents into the object -#define IV_INJECTING 1 ///What the transfer rate value is rounded to #define IV_TRANSFER_RATE_STEP 0.01 ///Minimum possible IV drip transfer rate in units per second @@ -462,9 +458,6 @@ use_user_hud_icon = TRUE overlay_state = "iv_connected" -#undef IV_TAKING -#undef IV_INJECTING - #undef MIN_IV_TRANSFER_RATE #undef MAX_IV_TRANSFER_RATE diff --git a/code/modules/plumbing/plumbers/bottler.dm b/code/modules/plumbing/plumbers/bottler.dm index b3421e9ffc3..f181427c654 100644 --- a/code/modules/plumbing/plumbers/bottler.dm +++ b/code/modules/plumbing/plumbers/bottler.dm @@ -21,7 +21,7 @@ /obj/machinery/plumbing/bottler/Initialize(mapload, bolt, layer) . = ..() - AddComponent(/datum/component/plumbing/simple_demand, bolt, layer) + AddComponent(/datum/component/plumbing/simple_demand, bolt, layer, distinct_reagent_cap = 3) setDir(dir) /obj/machinery/plumbing/bottler/examine(mob/user) diff --git a/code/modules/plumbing/plumbers/iv_drip.dm b/code/modules/plumbing/plumbers/iv_drip.dm index cef9d1752d1..a12d78cb4e9 100644 --- a/code/modules/plumbing/plumbers/iv_drip.dm +++ b/code/modules/plumbing/plumbers/iv_drip.dm @@ -10,7 +10,7 @@ /obj/machinery/iv_drip/plumbing/Initialize(mapload, bolt, layer) . = ..() - AddComponent(/datum/component/plumbing/automated_iv, bolt, layer) + AddComponent(/datum/component/plumbing/automated_iv, bolt, layer, distinct_reagent_cap = 3) AddComponent(/datum/component/simple_rotation) /obj/machinery/iv_drip/plumbing/quick_toggle(mob/living/user) diff --git a/code/modules/plumbing/plumbers/pill_press.dm b/code/modules/plumbing/plumbers/pill_press.dm index 4bd9321d2a8..8e10239511e 100644 --- a/code/modules/plumbing/plumbers/pill_press.dm +++ b/code/modules/plumbing/plumbers/pill_press.dm @@ -57,7 +57,7 @@ max_volume = initial(packaging_type.volume) current_volume = clamp(current_volume, MIN_VOLUME, max_volume) - AddComponent(/datum/component/plumbing/simple_demand, bolt, layer) + AddComponent(/datum/component/plumbing/simple_demand, bolt, layer, distinct_reagent_cap = 3) /obj/machinery/plumbing/pill_press/Destroy(force) QDEL_LAZYLIST(stored_products) diff --git a/code/modules/plumbing/plumbers/simple_machines.dm b/code/modules/plumbing/plumbers/simple_machines.dm index c2ef3082973..ded80bf88f1 100644 --- a/code/modules/plumbing/plumbers/simple_machines.dm +++ b/code/modules/plumbing/plumbers/simple_machines.dm @@ -21,7 +21,7 @@ /obj/machinery/plumbing/output/Initialize(mapload, bolt, layer) . = ..() - AddComponent(/datum/component/plumbing/simple_demand, bolt, layer) + AddComponent(/datum/component/plumbing/simple_demand, bolt, layer, distinct_reagent_cap = 5) ///For pouring reagents from ducts directly into cups /obj/machinery/plumbing/output/tap diff --git a/code/modules/reagents/chemistry/machinery/smoke_machine.dm b/code/modules/reagents/chemistry/machinery/smoke_machine.dm index 54358350d5c..c1775221e24 100644 --- a/code/modules/reagents/chemistry/machinery/smoke_machine.dm +++ b/code/modules/reagents/chemistry/machinery/smoke_machine.dm @@ -43,7 +43,7 @@ . = ..() - AddComponent(/datum/component/plumbing/simple_demand) + AddComponent(/datum/component/plumbing/simple_demand, distinct_reagent_cap = 5) AddComponent(/datum/component/simple_rotation) register_context()