[MIRROR] Lab-like Chemistry Dispensors (#12889)

Co-authored-by: Poojawa <Poojawa@users.noreply.github.com>
Co-authored-by: Cameron Lennox <killer65311@gmail.com>
Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2026-07-11 01:14:32 +02:00
committed by GitHub
co-authored by Poojawa Cameron Lennox Kashargul
parent 712656b6f6
commit 0ed557bec8
8 changed files with 103 additions and 46 deletions
@@ -12,12 +12,13 @@
var/ui_title = "Chemical Dispenser"
var/accept_drinking = 0
///If the dispenser is a drink dispenser. Used for update_icon() to prevent beakers from being displayed.
var/accept_drinking = FALSE
var/amount = 30
var/max_catriges = 30
var/max_cartridges = 30
use_power = USE_POWER_IDLE
idle_power_usage = 100
idle_power_usage = 0.1 KILOWATTS
anchored = TRUE
unacidable = TRUE
@@ -31,20 +32,63 @@
. = ..()
if(spawn_cartridges)
for(var/type in spawn_cartridges)
add_cartridge(new type(src))
add_cartridge(new type(src), forced = TRUE)
AddElement(/datum/element/rotatable)
/obj/machinery/chemical_dispenser/examine(mob/user)
. = ..()
. += "It has [cartridges.len] cartridges installed, and has space for [max_catriges - cartridges.len] more."
. += "It has [cartridges.len] cartridges installed, and has space for [max_cartridges - cartridges.len] more."
. += "It'll take a prying tool to retrieve installed cartridges."
/obj/machinery/chemical_dispenser/update_icon()
if(accept_drinking) //drink dispensors don't have fancy sprites, so this is a very handy checker
icon_state = initial(icon_state) //just in case some weirdness happens I guess.
return
cut_overlays()
icon_state = initial(icon_state)
if(panel_open)
add_overlay("[initial(icon_state)]_panel-o")
if(container)
icon_state = "[initial(icon_state)]_working"
if(istype(container, /obj/item/reagent_containers/glass/beaker/bluespace))
add_overlay("[initial(icon_state)]_bsbeaker")
if(istype(container, /obj/item/reagent_containers/glass/beaker/noreact))
add_overlay("[initial(icon_state)]_nrbeaker")
else //the only see-through one gets filling updates, and we can only do glass and subtypes of glass anyway.
var/obj/item/reagent_containers/glass/C = container
if(C.reagents && C.reagents.total_volume)
var/mutable_appearance/filling = mutable_appearance('icons/obj/reagentfillings.dmi', "[initial(icon_state)]_1")
var/percent = round((C.reagents.total_volume / C.volume) * 100)
switch(percent)
if(0 to 1) filling.icon_state = "nofill"
if(2 to 35) filling.icon_state = "[initial(icon_state)]_1"
if(36 to 74) filling.icon_state = "[initial(icon_state)]_5"
if(75 to INFINITY) filling.icon_state = "[initial(icon_state)]_10"
filling.color = C.reagents.get_color()
//Add our filling, if any.
add_overlay(filling)
//Then overlay the beaker atop of the filling, so it appears behind it.
add_overlay("[initial(icon_state)]_beaker")
if(stat & NOPOWER)
icon_state = "[initial(icon_state)]_nopower"
if(stat & BROKEN)
icon_state = "[initial(icon_state)]_broken"
return
/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/reagent_containers/chem_disp_cartridge/C, mob/user, forced = FALSE)
if(!panel_open && !forced)
to_chat(user, span_warning("You need to open the access hatch first!"))
return
/obj/machinery/chemical_dispenser/proc/add_cartridge(obj/item/reagent_containers/chem_disp_cartridge/C, mob/user)
if(!istype(C))
if(user)
to_chat(user, span_warning("\The [C] will not fit in \the [src]!"))
return
if(cartridges.len >= max_catriges)
if(cartridges.len >= max_cartridges)
if(user)
to_chat(user, span_warning("\The [src] does not have any slots open for \the [C] to fit into!"))
return
@@ -63,7 +107,7 @@
user.drop_from_inventory(C)
to_chat(user, span_notice("You add \the [C] to \the [src]."))
C.loc = src
C.forceMove(src)
cartridges[C.label] = C
cartridges = sortAssoc(cartridges)
SStgui.update_uis(src)
@@ -74,31 +118,27 @@
SStgui.update_uis(src)
/obj/machinery/chemical_dispenser/attackby(obj/item/W, mob/user)
if(W.has_tool_quality(TOOL_WRENCH))
playsound(src, W.usesound, 50, 1)
to_chat(user, span_notice("You begin to [anchored ? "un" : ""]fasten \the [src]."))
if (do_after(user, 2 SECONDS * W.toolspeed, target = src))
user.visible_message(
span_notice("\The [user] [anchored ? "un" : ""]fastens \the [src]."),
span_notice("You have [anchored ? "un" : ""]fastened \the [src]."),
"You hear a ratchet.")
anchored = !anchored
else
to_chat(user, span_notice("You decide not to [anchored ? "un" : ""]fasten \the [src]."))
if(default_unfasten_wrench(user, W, 5 SECONDS))
return
else if(istype(W, /obj/item/reagent_containers/chem_disp_cartridge))
if(istype(W, /obj/item/reagent_containers/chem_disp_cartridge))
add_cartridge(W, user)
else if(W.has_tool_quality(TOOL_SCREWDRIVER))
var/label = tgui_input_list(user, "Which cartridge would you like to remove?", "Chemical Dispenser", cartridges)
if(!label) return
var/obj/item/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label)
if(C)
to_chat(user, span_notice("You remove \the [C] from \the [src]."))
C.loc = loc
playsound(src, W.usesound, 50, 1)
if(default_deconstruction_screwdriver(user, W))
update_icon() //open the hatch!
return
else if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food))
if(panel_open)
if(W.has_tool_quality(TOOL_CROWBAR)) //I would make the deconstructable, but the cartridge system makes this... unwise.
var/label = tgui_input_list(user, "Which cartridge would you like to remove?", "Chemical Dispenser", cartridges)
if(!label || !Adjacent(user)) return
var/obj/item/reagent_containers/chem_disp_cartridge/C = remove_cartridge(label)
if(C)
to_chat(user, span_notice("You remove [C] from [src]."))
C.forceMove(get_turf(src))
playsound(src, W.usesound, 50, 1)
if(istype(W, /obj/item/reagent_containers/glass) || istype(W, /obj/item/reagent_containers/food))
if(container)
to_chat(user, span_warning("There is already \a [container] on \the [src]!"))
return
@@ -117,13 +157,30 @@
to_chat(user, span_warning("You don't see how \the [RC] could fit into \the [src]."))
return
container = RC
user.drop_from_inventory(RC)
RC.loc = src
replace_container(user, RC)
to_chat(user, span_notice("You set \the [RC] on \the [src]."))
update_icon()
else
return ..()
/obj/machinery/chemical_dispenser/click_alt(mob/user)
if(container)
replace_container(user, null)
/obj/machinery/chemical_dispenser/proc/replace_container(mob/living/user, obj/item/reagent_containers/new_container)
if(container)
container.forceMove(drop_location())
if(user && Adjacent(user))
user.put_in_hands(container)
if(new_container)
if(user && Adjacent(user))
user.drop_from_inventory(new_container, src)
container = new_container
else
container = null
update_icon()
return TRUE
/obj/machinery/chemical_dispenser/tgui_interact(mob/user, datum/tgui/ui = null)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
@@ -181,6 +238,7 @@
var/obj/item/reagent_containers/chem_disp_cartridge/C = cartridges[label]
playsound(src, 'sound/machines/reagent_dispense.ogg', 25, 1)
C.reagents.trans_to(container, amount)
update_icon()
. = TRUE
if("remove")
@@ -193,15 +251,12 @@
R.remove_reagent(id, amount)
else if(amount == -1) // Isolate
R.isolate_reagent(id)
update_icon()
. = TRUE
if("ejectBeaker")
if(container)
container.forceMove(get_turf(src))
if(Adjacent(ui.user)) // So the AI doesn't get a beaker somehow.
ui.user.put_in_hands(container)
container = null
. = TRUE
replace_container(ui.user)
. = TRUE //no afterattack
if("import_config")
/* CHOMPRemve Start, skip the import_job check
@@ -63,7 +63,7 @@
desc = "A soda machine."
icon_state = "soda_dispenser"
ui_title = "Soda Dispenser"
accept_drinking = 1
accept_drinking = TRUE
import_job = JOB_BARTENDER
/obj/machinery/chemical_dispenser/bar_soft/full
@@ -95,7 +95,7 @@
desc = "A beer machine. Like a soda machine, but more fun!"
icon_state = "booze_dispenser"
ui_title = "Booze Dispenser"
accept_drinking = 1
accept_drinking = TRUE
import_job = JOB_BARTENDER
/obj/machinery/chemical_dispenser/bar_alc/full
@@ -128,7 +128,7 @@
desc = "Driving crack dealers out of employment since 2280."
icon_state = "coffee_dispenser"
ui_title = "Coffee Dispenser"
accept_drinking = 1
accept_drinking = TRUE
import_job = JOB_BARTENDER
/obj/machinery/chemical_dispenser/bar_coffee/full
@@ -161,7 +161,7 @@
desc = "Allow your customers to test your patience to the extremes."
icon_state = "syrup_dispenser"
ui_title = "Syrup Dispenser"
accept_drinking = 1
accept_drinking = TRUE
/obj/machinery/chemical_dispenser/bar_syrup/full
spawn_cartridges = list(
@@ -1,5 +1,6 @@
/obj/machinery/chemical_dispenser/xenoflora
name = "xenoflora chem dispenser"
icon_state = "minidispenser"
ui_title = "Xenoflora Chemical Dispenser"
dispense_reagents = list(
REAGENT_ID_WATER, REAGENT_ID_SUGAR, REAGENT_ID_ETHANOL, REAGENT_ID_RADIUM, REAGENT_ID_AMMONIA, REAGENT_ID_DIETHYLAMINE, REAGENT_ID_PLANTBGONE, REAGENT_ID_MUTAGEN, REAGENT_ID_CALCIUM
@@ -21,6 +22,7 @@
/obj/machinery/chemical_dispenser/biochemistry
name = "bioproduct dispenser"
icon_state = "minidispenser"
ui_title = "Bioproduct Dispenser"
dispense_reagents = list(
REAGENT_ID_NUTRIMENT, REAGENT_ID_PROTEIN, REAGENT_ID_MILK