From eaba74a2ebd2a40b1dad93a1c9a96511917db0c7 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sat, 23 May 2026 00:28:52 +0530 Subject: [PATCH] Fixes for boulder processing machines (#96033) ## About The Pull Request - Opening the panel of a boulder refiner machine or un-wrenching it now turns off its environment light - The boulder refiner machine has reagent holder of type `/datum/reagents/plumbing` which fixes rounding errors & has other plumbing optimized features - The boulder refiner machine now only takes in booster reagents & only outputs waste reagent. This means even if you have a tank with random reagents attached to it, it will only take in booster reagents if present & exclude the rest thus saving you time & space from taking in other reagents - booster reagents is now a static list shared by all machines thus saving memory - Removed `supply_offset` & `demand_offset` vars from core plumbing component. These vars were making the pipes extend outside the tile causing it to overlap with adjacent tile machine pipes making everything ugly. Now the pipes are perpendicular to the conveyer belt sprite and will only take in boulders from the conveyer belt direction https://github.com/user-attachments/assets/5583a790-32b6-40df-a414-1602dd84fefd - Map edited smelters so the conveyer belt is in the direction of the refiner ## Changelog :cl: fix: opening panel of boulder refinery with screwdriver or un-wrenching it turns of its light fix: boulder refinery only takes in booster reagents and excludes others and only outputs waste chemicals as intended fix: boulder refinery machines outputs waste reagents without rounding errors in them qol: removed conveyer sprite from boulder smelter & pixel shifts the refiner so you can see it's plumbing pipes properly sprite: smelters will now only take in boulders in the direction of its conveyer belt. It's plumbing pipes are perpendicular to its conveyer belt /:cl: --- .../map_files/Deltastation/DeltaStation2.dmm | 4 +- .../map_files/IceBoxStation/IceBoxStation.dmm | 2 +- _maps/map_files/MetaStation/MetaStation.dmm | 4 +- .../map_files/NebulaStation/NebulaStation.dmm | 4 +- _maps/map_files/tramstation/tramstation.dmm | 4 +- _maps/map_files/wawastation/wawastation.dmm | 4 +- code/datums/components/plumbing/_plumbing.dm | 25 ------ .../components/plumbing/boulder_reactions.dm | 38 ++++---- .../boulder_processing/_boulder_processing.dm | 15 ++-- .../mining/boulder_processing/refinery.dm | 81 ++++++++++-------- code/modules/plumbing/plumbers/acclimator.dm | 2 +- .../chemistry/reagents/toxin_reagents.dm | 2 +- icons/obj/machines/mining_machines.dmi | Bin 6266 -> 7519 bytes 13 files changed, 90 insertions(+), 95 deletions(-) diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index c703b4f0731..e7f959668cd 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -48810,7 +48810,9 @@ /area/station/security/checkpoint/escape) "lWX" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/bouldertech/refinery/smelter, +/obj/machinery/bouldertech/refinery/smelter{ + dir = 4 + }, /obj/machinery/conveyor{ dir = 8; id = "mining" diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index e2fc8ab5a54..06e0e702a95 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -79390,7 +79390,7 @@ id = "mining_internal" }, /obj/machinery/bouldertech/refinery/smelter{ - dir = 4 + dir = 1 }, /obj/structure/railing/corner/end/flip{ dir = 4 diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 72d1f31fe6a..0afd221b765 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -7408,9 +7408,7 @@ /turf/open/floor/plating, /area/station/science/robotics/mechbay) "cBZ" = ( -/obj/machinery/bouldertech/refinery/smelter{ - dir = 4 - }, +/obj/machinery/bouldertech/refinery/smelter, /obj/machinery/conveyor{ id = "mining" }, diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index c7f091234e9..7e574ce2849 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -142209,9 +142209,7 @@ /obj/machinery/conveyor{ id = "mining" }, -/obj/machinery/bouldertech/refinery/smelter{ - dir = 4 - }, +/obj/machinery/bouldertech/refinery/smelter, /turf/open/floor/iron/dark/textured_large, /area/station/cargo/miningfoundry) "uYZ" = ( diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 02876e5c336..978bfa94cb6 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -38728,7 +38728,9 @@ /area/station/hallway/secondary/entry) "mqT" = ( /obj/effect/decal/cleanable/dirt, -/obj/machinery/bouldertech/refinery/smelter, +/obj/machinery/bouldertech/refinery/smelter{ + dir = 4 + }, /obj/structure/railing, /turf/open/floor/iron, /area/station/cargo/miningfoundry) diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 7bcfc9245e2..6e7f04f5f94 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -23339,7 +23339,9 @@ /turf/open/floor/plating, /area/station/maintenance/department/engine) "iee" = ( -/obj/machinery/bouldertech/refinery/smelter, +/obj/machinery/bouldertech/refinery/smelter{ + dir = 4 + }, /obj/machinery/conveyor{ dir = 6; id = "brm" diff --git a/code/datums/components/plumbing/_plumbing.dm b/code/datums/components/plumbing/_plumbing.dm index 3f3af944f68..f03e1d67866 100644 --- a/code/datums/components/plumbing/_plumbing.dm +++ b/code/datums/components/plumbing/_plumbing.dm @@ -20,11 +20,6 @@ /// 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 - ///Extra offset on supply pipe. - var/supply_offset = 0 - ///Extra offset on demand pipe. - var/demand_offset = 0 - /datum/component/plumbing/Initialize(ducting_layer) if(!ismovable(parent)) return COMPONENT_INCOMPATIBLE @@ -194,28 +189,8 @@ var/duct_y = offset - parent_movable.pixel_y - parent_movable.pixel_z if(direction & initial(demand_connects)) color = demand_color - if(demand_offset) - switch(parent_movable.dir) - if(NORTH) - duct_y -= demand_offset - if(SOUTH) - duct_y += demand_offset - if(EAST) - duct_x -= demand_offset - if(WEST) - duct_x += demand_offset else if(direction & initial(supply_connects)) color = supply_color - if(supply_offset) - switch(parent_movable.dir) - if(NORTH) - duct_y += supply_offset - if(SOUTH) - duct_y -= supply_offset - if(EAST) - duct_x += supply_offset - if(WEST) - duct_x -= supply_offset else continue diff --git a/code/datums/components/plumbing/boulder_reactions.dm b/code/datums/components/plumbing/boulder_reactions.dm index 56496ea803c..982a7839d7a 100644 --- a/code/datums/components/plumbing/boulder_reactions.dm +++ b/code/datums/components/plumbing/boulder_reactions.dm @@ -1,30 +1,32 @@ -/** - * The boulder machines take in many types of chems, but should only ever eject "waste" chems, - */ +/// The boulder machines take in many types of chems, but should only ever eject "waste" chems, /datum/component/plumbing/boulder_reactions - demand_connects = NORTH - supply_connects = SOUTH - supply_offset = 4 - demand_offset = 4 + demand_connects = WEST + supply_connects = EAST /datum/component/plumbing/boulder_reactions/Initialize(ducting_layer) if(!istype(parent, /obj/machinery/bouldertech/refinery)) return COMPONENT_INCOMPATIBLE return ..() +/datum/component/plumbing/boulder_reactions/send_request(dir) + var/obj/machinery/bouldertech/refinery/the_refinery = parent + var/list/datum/reagents/boosters = the_refinery.get_booster_reagents() + + for(var/datum/reagent/booster as anything in boosters) + process_request(MACHINE_REAGENT_TRANSFER, booster, dir, TRUE) + /datum/component/plumbing/boulder_reactions/can_give(amount, reagent, datum/ductnet/net) - if(amount <= 0 || !reagents.total_volume || !reagent) + if(!reagents.total_volume || amount <= 0) return FALSE var/obj/machinery/bouldertech/refinery/the_refinery = parent - var/list/datum/reagents/boosters = the_refinery.booster_list - - if(istype(amount, the_refinery.waste_chemical)) - return TRUE //Always allow waste chemicals to leave. - - if(!length(boosters)) - return ..() - for(var/datum/chem as anything in boosters) - if(chem.type == reagent) // Need to check strict subtype since most acids are subtypes of eachother. + if(reagent) + if(reagent != the_refinery.waste_chemical) //Always allow waste chemicals to enter. return FALSE - return ..() + + return !!reagents.has_reagent(the_refinery.waste_chemical) + +/datum/component/plumbing/boulder_reactions/transfer_to(datum/component/plumbing/target, amount, reagent, datum/ductnet/net, round_robin) + var/obj/machinery/bouldertech/refinery/the_refinery = parent + + reagents.trans_to(target.recipient_reagents_holder(), amount, target_id = the_refinery.waste_chemical, methods = round_robin ? LINEAR : NONE) diff --git a/code/modules/mining/boulder_processing/_boulder_processing.dm b/code/modules/mining/boulder_processing/_boulder_processing.dm index 6d11c876bf3..324c616ae84 100644 --- a/code/modules/mining/boulder_processing/_boulder_processing.dm +++ b/code/modules/mining/boulder_processing/_boulder_processing.dm @@ -22,10 +22,6 @@ var/points_held = 0 ///The action verb to display to players var/action = "processing" - - - /// What list of reagents should we look at when we boost the effectiveness of this machinery? Assign a value to a chem as well, eg: /datum/reagent/water = 1 is a 10% boost - var/list/booster_list = list() /// What reagent should be produced when a boost chemical is replaced by the booster_reagent? var/datum/reagent/waste_chemical = /datum/reagent/water @@ -107,6 +103,7 @@ /obj/machinery/bouldertech/examine_more(mob/user) . = ..() + var/list/datum/reagents/booster_list = get_booster_reagents() if(length(booster_list)) . += span_notice("This machine's output is boosted by chemical intake:
") for(var/datum/reagent/increment as anything in booster_list) @@ -121,7 +118,7 @@ icon_state ="[base_icon_state][suffix]" /obj/machinery/bouldertech/CanAllowThrough(atom/movable/mover, border_dir) - if(!anchored) + if(!anchored || !(dir == border_dir || dir == REVERSE_DIR(border_dir))) return FALSE if(istype(mover, /obj/item/stack/sheet)) return TRUE @@ -254,6 +251,12 @@ refining_efficiency = initial(refining_efficiency) //Reset refining efficiency to 100%. +///Returns a map of reagent -> boost amount to increase this machines efficiency +/obj/machinery/bouldertech/proc/get_booster_reagents() + RETURN_TYPE(/list/datum/reagents) + + return list() + /** * Checks if this machine can process this material * Arguments @@ -380,7 +383,7 @@ if(istype(chosen_boulder, /obj/item/boulder/artifact)) points_held = round((points_held + MINER_POINT_MULTIPLIER)) /// Artifacts give bonus points! chosen_boulder.break_apart() - return//We've processed all the materials in the boulder, so we can just destroy it in break_apart. + return //We've processed all the materials in the boulder, so we can just destroy it in break_apart. chosen_boulder.processed_by = src diff --git a/code/modules/mining/boulder_processing/refinery.dm b/code/modules/mining/boulder_processing/refinery.dm index 52cf7189062..f65669d3b40 100644 --- a/code/modules/mining/boulder_processing/refinery.dm +++ b/code/modules/mining/boulder_processing/refinery.dm @@ -12,14 +12,33 @@ usage_sound = 'sound/machines/mining/refinery.ogg' action = "crushing" waste_chemical = /datum/reagent/toxin/acid/industrial_waste + pixel_y = 1 - /// What list of reagents should we look at when we boost the effectiveness of this machinery? - booster_list = list( - /datum/reagent/toxin/acid = 1, - /datum/reagent/toxin/acid/fluacid = 2, - /datum/reagent/toxin/acid/nitracid = 3, - /datum/reagent/teslium = 5, - ) +/obj/machinery/bouldertech/refinery/Initialize(mapload) + . = ..() + AddComponent(/datum/component/plumbing/boulder_reactions) + AddElement(/datum/element/simple_rotation) + update_appearance(UPDATE_OVERLAYS) + +/obj/machinery/bouldertech/refinery/update_icon_state() + . = ..() + set_light_on(anchored && is_operational && !panel_open) + +/obj/machinery/bouldertech/refinery/create_reagents(max_vol, flags) + QDEL_NULL(reagents) + reagents = new /datum/reagents/plumbing(max_vol, flags) + reagents.my_atom = src + +/obj/machinery/bouldertech/refinery/get_booster_reagents() + var/static/list/booster_reagents + if(!length(booster_reagents)) + booster_reagents = list( + /datum/reagent/toxin/acid = 1, + /datum/reagent/toxin/acid/fluacid = 2, + /datum/reagent/toxin/acid/nitracid = 3, + /datum/reagent/teslium = 5, + ) + return booster_reagents /obj/machinery/bouldertech/refinery/can_process_material(datum/material/possible_mat) var/static/list/processable_materials @@ -54,24 +73,19 @@ reagents.maximum_volume = new_volume -/obj/machinery/bouldertech/refinery/Initialize(mapload) - . = ..() - AddComponent(/datum/component/plumbing/boulder_reactions) - AddElement(/datum/element/simple_rotation) - update_appearance(UPDATE_OVERLAYS) - /obj/machinery/bouldertech/refinery/check_for_boosts() . = ..() //resets to 1.00 efficiency in the parent + var/highest_boost = 0 var/datum/reagent/biggest_booster - for(var/datum/reagent/chem in reagents.reagent_list) - if(!booster_list[chem.type]) + var/list/datum/reagents/booster_list = get_booster_reagents() + for(var/datum/reagent/booster as anything in booster_list) + var/booster_volume = booster_list[booster] + if(!reagents.has_reagent(booster, booster_volume)) //check that we have the associated quantity of the chem in order to perform the boost. continue - if(!reagents.has_reagent(chem.type, booster_list[chem.type])) //check that we have the associated quantity of the chem in order to perform the boost. - continue - if(booster_list[chem.type] > highest_boost) - highest_boost = booster_list[chem.type] - biggest_booster = chem.type + if(booster_list[booster] > highest_boost) + highest_boost = booster_volume + biggest_booster = booster if(!biggest_booster) return @@ -80,14 +94,6 @@ refining_efficiency = 1 + (highest_boost / 10) //Results in a boost from 10-30% reagents.add_reagent(waste_chemical, highest_boost) -/obj/machinery/bouldertech/refinery/default_deconstruction_screwdriver(mob/user, icon_state_open, icon_state_closed, obj/item/screwdriver) - . = ..() - set_light_on(TRUE) - -/obj/machinery/bouldertech/refinery/default_unfasten_wrench(mob/user, obj/item/wrench, time) - . = ..() - set_light_on(TRUE) - /obj/machinery/bouldertech/refinery/plunger_act(obj/item/plunger/attacking_plunger, mob/living/user, reinforced) . = ..() balloon_alert(user, "emptying...") @@ -113,17 +119,24 @@ circuit = /obj/item/circuitboard/machine/smelter usage_sound = 'sound/machines/mining/smelter.ogg' action = "smelting" - booster_list = list( - /datum/reagent/fuel = 1, - /datum/reagent/thermite = 2, - /datum/reagent/gunpowder = 3, - /datum/reagent/liquid_dark_matter = 5, - ) + pixel_x = -1 /obj/machinery/bouldertech/refinery/smelter/Initialize(mapload) . = ..() update_light_value() + +/obj/machinery/bouldertech/refinery/smelter/get_booster_reagents() + var/static/list/booster_reagents + if(!length(booster_reagents)) + booster_reagents = list( + /datum/reagent/fuel = 1, + /datum/reagent/thermite = 2, + /datum/reagent/gunpowder = 3, + /datum/reagent/liquid_dark_matter = 5, + ) + return booster_reagents + /obj/machinery/bouldertech/refinery/smelter/can_process_material(datum/material/possible_mat) var/static/list/processable_materials if(!length(processable_materials)) diff --git a/code/modules/plumbing/plumbers/acclimator.dm b/code/modules/plumbing/plumbers/acclimator.dm index 06639fc99d8..0e9e1443344 100644 --- a/code/modules/plumbing/plumbers/acclimator.dm +++ b/code/modules/plumbing/plumbers/acclimator.dm @@ -1,4 +1,4 @@ -///Same as a tier 1 chem heater +///Same as a tier 3 chem heater #define HEATER_COFFICIENT 0.3 ///Decimal point in rounding temperature #define TEMP_ROUNDING 0.01 diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index 8498456c164..9e73a0be361 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -1640,7 +1640,7 @@ . = ..() var/merged_total = amount + volume if(merged_total >= CRITICAL_CAPACITY) - spew_waste(round(volume / WASTE_REACTION_THRESHOLD*2)) //Sure as HELL can't store it. + spew_waste(round(volume / WASTE_REACTION_THRESHOLD * 2)) //Sure as HELL can't store it. var/atom/container = holder.my_atom var/damage_mult = 1 if(ismachinery(container)) diff --git a/icons/obj/machines/mining_machines.dmi b/icons/obj/machines/mining_machines.dmi index c1a4076e3a2f5130ca3acc772da738479b4dcad7..a895f18da0035f780723db4e2fd35f68a9d434c0 100644 GIT binary patch literal 7519 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 A4*&oF delta 6146 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

+_W?fBJnxEk6q1LD}k z)jO@8^=t@#U{e}Ec=3p|Kqi;+p>c9Ag!9TSbFy#xhBh4PvAH*Wl`#v>tYIrzkH}b4 zwVSq=$b;$)CiQWG!bmc-XQWRz0jpGNXTTJl@ zRMsn41%u%dxwp3_LUP5C3j-IXKaa@9GVIf-R+sITT>c+)r`dD*o@1oEF42wV`*Sx; zJ#3s%A8Z<@|ImO<1Vu)1+;@ZH9$_mcXj->_vLT^NGV`qYpv z*ZgTS@CDOii`N6U@;{|C6F%GUBg}I}!>v;|&=y9;>;=<`w#N&Hg{1z1Ti*(Y8>U)W zFBT%VnYjhz;H~M@9;;~mQI(uKwjQx_tBe0bq$G6CcW|`*J4S4{P-9@^4K1o1CJ3g2qcg%0y5~W=(Dxd1U7qFpPmw;CZgmm$t}38e zMi-;>Y*usO@EuXp0uE5y`g^=^3j}mlqcEowDqLT-`hng9;pr={c%&jb&SGbl8Ut3;wVNAv460i^NeheW9 zVuyL4{heT~yp+Mat~>G0F_X{N-b+G%xFlu~aZ%(Lzn*=sDJ3Y9E#}Es} z_{!~gxvNGUHJfe=|E^ZVO}7brrhnoIKk$5>=E0(gVuvs=;xv$nDz&;;bD|MAyo})| ztmrkaqSY-l6*oi+o_)JfD)R$bI_$9}5{l`N2v3?0`hsMe3)oYiil>vKWSK>Jn%1PH z05sIpo75QGhlF~AGLTVo_g= zj##1%)TE8eK7|~$4n}vQ*D@l80Fb{1Vir2oQ4|1_ z*o`bNx=vklX**c-C1$}X24;O}x{pH4!3svD03kPLN!C*LX%%nN01Bg&;x;&RuOxn zY?&zVTyul`%6>(^TW#2k=~_*Y_xL4u8ue7ic%=zmN6#$qDV`p`b(@y{ZPkeRAKlqt zbd=oF?J3Kt4T*P+T;B>>79c++Ic_ym3SjTvDrj>Z)(KYeU8`)7c3P4?1}SA|l|W)^ zfT5j<>DPBA(X>1%E^RoI4LkD)ws;l-3RrelS9CEy#AW;liV<6;VXVNf(;4Z%Wri&* zK-_B?17~awtl7dAPzJ))mXQO>?j1vO@cVUk|R>ykRd7NmvZ?xzwfz zZ@b0?@@=9a)*jRM30b7m9tWn*vLHSDMm#I#tlj-zYrx9P*0jplGw%NY D^RB{0