From a6d0e503cbed54662afd4d90cff1ff98732371b8 Mon Sep 17 00:00:00 2001
From: NovaBot <154629622+NovaBot13@users.noreply.github.com>
Date: Wed, 10 Apr 2024 23:26:47 -0400
Subject: [PATCH] [MIRROR] General maintenance for chem master (#1904)
* General maintenance for chem master
* Update chem_master.dm
* Update chem_master.dm
* Update chem_master.dm
* Update chem_master.dm
---------
Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com>
Co-authored-by: Mal <13398309+vinylspiders@users.noreply.github.com>
---
.../chemistry/machinery/chem_master.dm | 725 ++++++++++--------
icons/obj/medical/chemical.dmi | Bin 71028 -> 70968 bytes
tgui/packages/tgui/interfaces/ChemMaster.tsx | 317 ++++----
.../tgui/interfaces/common/BeakerDisplay.tsx | 2 +-
4 files changed, 569 insertions(+), 475 deletions(-)
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index dfad101c273..cc6b09c72aa 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -1,84 +1,94 @@
-#define TRANSFER_MODE_DESTROY 0
-#define TRANSFER_MODE_MOVE 1
-#define TARGET_BEAKER "beaker"
-#define TARGET_BUFFER "buffer"
-
/obj/machinery/chem_master
name = "ChemMaster 3000"
desc = "Used to separate chemicals and distribute them in a variety of forms."
- density = TRUE
- layer = BELOW_OBJ_LAYER
icon = 'icons/obj/medical/chemical.dmi'
icon_state = "chemmaster"
base_icon_state = "chemmaster"
+ density = TRUE
idle_power_usage = BASE_MACHINE_IDLE_CONSUMPTION * 0.2
+ active_power_usage = BASE_MACHINE_ACTIVE_CONSUMPTION * 0.2
resistance_flags = FIRE_PROOF | ACID_PROOF
circuit = /obj/item/circuitboard/machine/chem_master
- /// Icons for different percentages of buffer reagents
- var/fill_icon = 'icons/obj/medical/reagent_fillings.dmi'
- var/fill_icon_state = "chemmaster"
- var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
+
/// Inserted reagent container
var/obj/item/reagent_containers/beaker
/// Whether separated reagents should be moved back to container or destroyed.
- var/transfer_mode = TRANSFER_MODE_MOVE
- /// Whether reagent analysis screen is active
- var/reagent_analysis_mode = FALSE
- /// Reagent being analyzed
- var/datum/reagent/analyzed_reagent
+ var/is_transfering = TRUE
/// List of printable container types
- var/list/printable_containers = list()
- /// Container used by default to reset to (REF)
- var/default_container
- /// Selected printable container type (REF)
- var/selected_container
- /// Whether the machine has an option to suggest container
- var/has_container_suggestion = FALSE
- /// Whether to suggest container or not
- var/do_suggest_container = FALSE
- /// The container suggested by main reagent in the buffer
- var/suggested_container
+ var/list/printable_containers
+ /// Container used by default to reset to
+ var/obj/item/reagent_containers/default_container
+ /// Selected printable container type
+ var/obj/item/reagent_containers/selected_container
/// Whether the machine is busy with printing containers
var/is_printing = FALSE
- /// Number of printed containers in the current printing cycle for UI progress bar
+ /// Number of containers printed so far
var/printing_progress
+ /// Number of containers to be printed
var/printing_total
- /// Default duration of printing cycle
- var/printing_speed = 0.75 SECONDS // Duration of animation
- /// The amount of containers printed in one cycle
+ /// The amount of containers that can be printed in 1 cycle
var/printing_amount = 1
/obj/machinery/chem_master/Initialize(mapload)
create_reagents(100)
- load_printable_containers()
- default_container = REF(printable_containers[printable_containers[1]][1])
+
+ printable_containers = load_printable_containers()
+ default_container = printable_containers[printable_containers[1]][1]
selected_container = default_container
- return ..()
+
+ register_context()
+
+ . = ..()
+
+ var/obj/item/circuitboard/machine/chem_master/board = circuit
+ board.build_path = type
+ board.name = name
/obj/machinery/chem_master/Destroy()
QDEL_NULL(beaker)
return ..()
-/obj/machinery/chem_master/on_deconstruction(disassembled)
- replace_beaker()
- return ..()
+/obj/machinery/chem_master/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = NONE
+ if(isnull(held_item) || (held_item.item_flags & ABSTRACT) || (held_item.flags_1 & HOLOGRAM_1))
+ if(isnull(held_item))
+ context[SCREENTIP_CONTEXT_RMB] = "Remove beaker"
+ . = CONTEXTUAL_SCREENTIP_SET
+ return .
-/obj/machinery/chem_master/Exited(atom/movable/gone, direction)
- . = ..()
- if(gone == beaker)
- beaker = null
- update_appearance(UPDATE_ICON)
+ if(is_reagent_container(held_item) && held_item.is_open_container())
+ if(!QDELETED(beaker))
+ context[SCREENTIP_CONTEXT_LMB] = "Replace beaker"
+ else
+ context[SCREENTIP_CONTEXT_LMB] = "Insert beaker"
+ return CONTEXTUAL_SCREENTIP_SET
+
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] panel"
+ return CONTEXTUAL_SCREENTIP_SET
+ else if(held_item.tool_behaviour == TOOL_WRENCH)
+ context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""] anchor"
+ return CONTEXTUAL_SCREENTIP_SET
+ else if(panel_open && held_item.tool_behaviour == TOOL_CROWBAR)
+ context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
+ return CONTEXTUAL_SCREENTIP_SET
-/obj/machinery/chem_master/RefreshParts()
+/obj/machinery/chem_master/examine(mob/user)
. = ..()
- reagents.maximum_volume = 0
- for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts)
- reagents.maximum_volume += beaker.reagents.maximum_volume
- printing_amount = 0
- for(var/datum/stock_part/servo/servo in component_parts)
- printing_amount += servo.tier
-
-/obj/machinery/chem_master/update_appearance(updates=ALL)
+ if(in_range(user, src) || isobserver(user))
+ . += span_notice("The status display reads:
Reagent buffer capacity: [reagents.maximum_volume] units.
Number of containers printed per cycle [printing_amount].")
+ if(!QDELETED(beaker))
+ . += span_notice("[beaker] of [beaker.reagents.maximum_volume]u capacity inserted")
+ . += span_notice("Right click with empty hand to remove beaker")
+ else
+ . += span_warning("Missing input beaker")
+
+ . += span_notice("It can be [EXAMINE_HINT("wrenched")] [anchored ? "loose" : "in place"]")
+ . += span_notice("Its maintainence panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"]")
+ if(panel_open)
+ . += span_notice("The machine can be [EXAMINE_HINT("pried")] apart.")
+
+/obj/machinery/chem_master/update_appearance(updates)
. = ..()
if(panel_open || (machine_stat & (NOPOWER|BROKEN)))
set_light(0)
@@ -102,9 +112,7 @@
// Screen overlay
if(!panel_open && !(machine_stat & (NOPOWER | BROKEN)))
var/screen_overlay = base_icon_state + "_overlay_screen"
- if(reagent_analysis_mode)
- screen_overlay += "_analysis"
- else if(is_printing)
+ if(is_printing)
screen_overlay += "_active"
else if(reagents.total_volume > 0)
screen_overlay += "_main"
@@ -114,46 +122,126 @@
// Buffer reagents overlay
if(reagents.total_volume)
var/threshold = null
+ var/static/list/fill_icon_thresholds = list(10, 20, 30, 40, 50, 60, 70, 80, 90, 100)
for(var/i in 1 to fill_icon_thresholds.len)
- if(ROUND_UP(100 * reagents.total_volume / reagents.maximum_volume) >= fill_icon_thresholds[i])
+ if(ROUND_UP(100 * (reagents.total_volume / reagents.maximum_volume)) >= fill_icon_thresholds[i])
threshold = i
if(threshold)
- var/fill_name = "[fill_icon_state][fill_icon_thresholds[threshold]]"
- var/mutable_appearance/filling = mutable_appearance(fill_icon, fill_name)
+ var/fill_name = "chemmaster[fill_icon_thresholds[threshold]]"
+ var/mutable_appearance/filling = mutable_appearance('icons/obj/medical/reagent_fillings.dmi', fill_name)
filling.color = mix_color_from_reagents(reagents.reagent_list)
. += filling
+/obj/machinery/chem_master/Exited(atom/movable/gone, direction)
+ . = ..()
+ if(gone == beaker)
+ beaker = null
+ update_appearance(UPDATE_OVERLAYS)
+
+/obj/machinery/chem_master/on_set_is_operational(old_value)
+ if(!is_operational)
+ is_printing = FALSE
+ update_appearance(UPDATE_OVERLAYS)
+
+/obj/machinery/chem_master/RefreshParts()
+ . = ..()
+ reagents.maximum_volume = 0
+ for(var/obj/item/reagent_containers/cup/beaker/beaker in component_parts)
+ reagents.maximum_volume += beaker.reagents.maximum_volume
+
+ printing_amount = 0
+ for(var/datum/stock_part/servo/servo in component_parts)
+ printing_amount += servo.tier * 12.5
+ printing_amount = min(50, ROUND_UP(printing_amount))
+
+///Return a map of category->list of containers this machine can print
+/obj/machinery/chem_master/proc/load_printable_containers()
+ PROTECTED_PROC(TRUE)
+ SHOULD_BE_PURE(TRUE)
+
+ var/static/list/containers
+ if(!length(containers))
+ containers = list(
+ CAT_TUBES = GLOB.reagent_containers[CAT_TUBES],
+ CAT_PILLS = GLOB.reagent_containers[CAT_PILLS],
+ CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES],
+ CAT_HYPOS = GLOB.reagent_containers[CAT_HYPOS], // NOVA EDIT ADDITION
+ CAT_DARTS = GLOB.reagent_containers[CAT_DARTS], // NOVA EDIT ADDITION
+ )
+ return containers
+
+/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
+ if(user.combat_mode || (tool.item_flags & ABSTRACT) || (tool.flags_1 & HOLOGRAM_1) || !can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH))
+ return ..()
+
+ if(is_reagent_container(tool) && tool.is_open_container())
+ replace_beaker(user, tool)
+ if(!panel_open)
+ ui_interact(user)
+ return ITEM_INTERACT_SUCCESS
+ else
+ return ITEM_INTERACT_BLOCKING
+
+ return ..()
/obj/machinery/chem_master/wrench_act(mob/living/user, obj/item/tool)
+ if(user.combat_mode)
+ return NONE
+
+ . = ITEM_INTERACT_BLOCKING
+ if(is_printing)
+ balloon_alert(user, "still printing!")
+ return .
+
if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN)
return ITEM_INTERACT_SUCCESS
- return ITEM_INTERACT_BLOCKING
/obj/machinery/chem_master/screwdriver_act(mob/living/user, obj/item/tool)
+ if(user.combat_mode)
+ return NONE
+
+ . = ITEM_INTERACT_BLOCKING
+ if(is_printing)
+ balloon_alert(user, "still printing!")
+ return .
+
if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool))
- update_appearance(UPDATE_ICON)
+ update_appearance(UPDATE_OVERLAYS)
return ITEM_INTERACT_SUCCESS
- return ITEM_INTERACT_BLOCKING
/obj/machinery/chem_master/crowbar_act(mob/living/user, obj/item/tool)
+ if(user.combat_mode)
+ return NONE
+
+ . = ITEM_INTERACT_BLOCKING
+ if(is_printing)
+ balloon_alert(user, "still printing!")
+ return .
+
if(default_deconstruction_crowbar(tool))
return ITEM_INTERACT_SUCCESS
- return ITEM_INTERACT_BLOCKING
-/obj/machinery/chem_master/item_interaction(mob/living/user, obj/item/tool, list/modifiers, is_right_clicking)
- if(is_reagent_container(tool) && !(tool.item_flags & ABSTRACT) && tool.is_open_container())
- replace_beaker(user, tool)
- if(!panel_open)
- ui_interact(user)
- return ITEM_INTERACT_SUCCESS
+/**
+ * Insert, remove, replace the existig beaker
+ * Arguments
+ *
+ * * mob/living/user - the player trying to replace the beaker
+ * * obj/item/reagent_containers/new_beaker - the beaker we are trying to insert, swap with existing or remove if null
+ */
+/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
+ PRIVATE_PROC(TRUE)
- return ..()
+ if(!QDELETED(beaker))
+ try_put_in_hand(beaker, user)
+ if(!QDELETED(new_beaker) && user.transferItemToLoc(new_beaker, src))
+ beaker = new_beaker
+ update_appearance(UPDATE_OVERLAYS)
/obj/machinery/chem_master/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
if(. == SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN)
return .
- if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH|FORBID_TELEKINESIS_REACH))
+ if(!can_interact(user) || !user.can_perform_action(src, ALLOW_SILICON_REACH | FORBID_TELEKINESIS_REACH))
return .
replace_beaker(user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
@@ -164,27 +252,6 @@
/obj/machinery/chem_master/attack_ai_secondary(mob/user, list/modifiers)
return attack_hand_secondary(user, modifiers)
-/// Insert new beaker and/or eject the inserted one
-/obj/machinery/chem_master/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
- if(new_beaker && user && !user.transferItemToLoc(new_beaker, src))
- return FALSE
- if(beaker)
- try_put_in_hand(beaker, user)
- beaker = null
- if(new_beaker)
- beaker = new_beaker
- update_appearance(UPDATE_ICON)
- return TRUE
-
-/obj/machinery/chem_master/proc/load_printable_containers()
- printable_containers = list(
- CAT_TUBES = GLOB.reagent_containers[CAT_TUBES],
- CAT_PILLS = GLOB.reagent_containers[CAT_PILLS],
- CAT_PATCHES = GLOB.reagent_containers[CAT_PATCHES],
- CAT_HYPOS = GLOB.reagent_containers[CAT_HYPOS], // NOVA EDIT ADDITION
- CAT_DARTS = GLOB.reagent_containers[CAT_DARTS], // NOVA EDIT ADDITION
- )
-
/obj/machinery/chem_master/ui_assets(mob/user)
return list(
get_asset_datum(/datum/asset/spritesheet/chemmaster)
@@ -198,274 +265,286 @@
/obj/machinery/chem_master/ui_static_data(mob/user)
var/list/data = list()
+
data["categories"] = list()
for(var/category in printable_containers)
- var/container_data = list()
+ //make the category
+ var/list/category_list = list(
+ "name" = category,
+ "containers" = list(),
+ )
+
+ //add containers to this category
for(var/obj/item/reagent_containers/container as anything in printable_containers[category])
- container_data += list(list(
+ category_list["containers"] += list(list(
"icon" = sanitize_css_class_name("[container]"),
"ref" = REF(container),
"name" = initial(container.name),
"volume" = initial(container.volume),
))
- data["categories"]+= list(list(
- "name" = category,
- "containers" = container_data,
- ))
+
+ //add the category
+ data["categories"] += list(category_list)
return data
/obj/machinery/chem_master/ui_data(mob/user)
- var/list/data = list()
+ . = list()
+
+ //printing statictics
+ .["isPrinting"] = is_printing
+ .["printingProgress"] = printing_progress
+ .["printingTotal"] = printing_total
+ .["maxPrintable"] = printing_amount
+
+ //contents of source beaker
+ var/list/beaker_data = null
+ if(!QDELETED(beaker))
+ beaker_data = list()
+ beaker_data["maxVolume"] = beaker.volume
+ beaker_data["currentVolume"] = round(beaker.reagents.total_volume, CHEMICAL_VOLUME_ROUNDING)
+ var/list/beakerContents = list()
+ if(length(beaker.reagents.reagent_list))
+ for(var/datum/reagent/reagent as anything in beaker.reagents.reagent_list)
+ beakerContents += list(list(
+ "ref" = "[reagent.type]",
+ "name" = reagent.name,
+ "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING),
+ "pH" = reagent.ph,
+ "color" = reagent.color,
+ "description" = reagent.description,
+ "purity" = reagent.purity,
+ "metaRate" = reagent.metabolization_rate,
+ "overdose" = reagent.overdose_threshold,
+ "addictionTypes" = reagents.parse_addictions(reagent),
+ ))
+ beaker_data["contents"] = beakerContents
+ .["beaker"] = beaker_data
+
+ //contents of buffer
+ beaker_data = list()
+ beaker_data["maxVolume"] = reagents.maximum_volume
+ beaker_data["currentVolume"] = round(reagents.total_volume, CHEMICAL_VOLUME_ROUNDING)
+ var/list/beakerContents = list()
+ if(length(reagents.reagent_list))
+ for(var/datum/reagent/reagent as anything in reagents.reagent_list)
+ beakerContents += list(list(
+ "ref" = "[reagent.type]",
+ "name" = reagent.name,
+ "volume" = round(reagent.volume, CHEMICAL_VOLUME_ROUNDING),
+ "pH" = reagent.ph,
+ "color" = reagent.color,
+ "description" = reagent.description,
+ "purity" = reagent.purity,
+ "metaRate" = reagent.metabolization_rate,
+ "overdose" = reagent.overdose_threshold,
+ "addictionTypes" = reagents.parse_addictions(reagent),
+ ))
+ beaker_data["contents"] = beakerContents
+ .["buffer"] = beaker_data
+
+ //is transfering or destroying reagents. applied only for buffer
+ .["isTransfering"] = is_transfering
+
+ //container along with the suggested type
+ var/obj/item/reagent_containers/suggested_container = default_container
+ if(reagents.total_volume > 0)
+ var/datum/reagent/master_reagent = reagents.get_master_reagent()
+ var/container_found = FALSE
+ suggested_container = master_reagent.default_container
+ for(var/category in printable_containers)
+ for(var/obj/item/reagent_containers/container as anything in printable_containers[category])
+ if(container == suggested_container)
+ suggested_container = REF(container)
+ container_found = TRUE
+ break
+ if(!container_found)
+ suggested_container = REF(default_container)
+ .["suggestedContainerRef"] = suggested_container
+
+ //selected container
+ .["selectedContainerRef"] = REF(selected_container)
+ .["selectedContainerVolume"] = initial(selected_container.volume)
+
+/**
+ * Transfers a single reagent between buffer & beaker
+ * Arguments
+ *
+ * * mob/user - the player who is attempting the transfer
+ * * datum/reagents/source - the holder we are transferring from
+ * * datum/reagents/target - the holder we are transferring to
+ * * datum/reagent/path - the reagent typepath we are transfering
+ * * amount - volume to transfer -1 means custom amount
+ * * do_transfer - transfer the reagents else destroy them
+ */
+/obj/machinery/chem_master/proc/transfer_reagent(mob/user, datum/reagents/source, datum/reagents/target, datum/reagent/path, amount, do_transfer)
+ PRIVATE_PROC(TRUE)
+
+ //sanity checks for transfer amount
+ if(isnull(amount))
+ return FALSE
+ amount = text2num(amount)
+ if(isnull(amount))
+ return FALSE
+ if(amount == -1)
+ var/target_amount = tgui_input_number(user, "Enter amount to transfer", "Transfer amount")
+ if(!target_amount)
+ return FALSE
+ amount = text2num(target_amount)
+ if(isnull(amount))
+ return FALSE
+ if(amount <= 0)
+ return FALSE
- data["reagentAnalysisMode"] = reagent_analysis_mode
- if(reagent_analysis_mode && analyzed_reagent)
- var/state
- switch(analyzed_reagent.reagent_state)
- if(SOLID)
- state = "Solid"
- if(LIQUID)
- state = "Liquid"
- if(GAS)
- state = "Gas"
- else
- state = "Unknown"
- data["analysisData"] = list(
- "name" = analyzed_reagent.name,
- "state" = state,
- "pH" = analyzed_reagent.ph,
- "color" = analyzed_reagent.color,
- "description" = analyzed_reagent.description,
- "purity" = analyzed_reagent.purity,
- "metaRate" = analyzed_reagent.metabolization_rate,
- "overdose" = analyzed_reagent.overdose_threshold,
- "addictionTypes" = reagents.parse_addictions(analyzed_reagent),
- )
- else
- data["isPrinting"] = is_printing
- data["printingProgress"] = printing_progress
- data["printingTotal"] = printing_total
- data["hasBeaker"] = beaker ? TRUE : FALSE
- data["beakerCurrentVolume"] = beaker ? round(beaker.reagents.total_volume, 0.01) : null
- data["beakerMaxVolume"] = beaker ? beaker.volume : null
- var/list/beaker_contents = list()
- if(beaker)
- for(var/datum/reagent/reagent in beaker.reagents.reagent_list)
- beaker_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01))))
- data["beakerContents"] = beaker_contents
-
- var/list/buffer_contents = list()
- if(reagents.total_volume)
- for(var/datum/reagent/reagent in reagents.reagent_list)
- buffer_contents.Add(list(list("name" = reagent.name, "ref" = REF(reagent), "volume" = round(reagent.volume, 0.01))))
- data["bufferContents"] = buffer_contents
- data["bufferCurrentVolume"] = round(reagents.total_volume, 0.01)
- data["bufferMaxVolume"] = reagents.maximum_volume
-
- data["transferMode"] = transfer_mode
-
- data["hasContainerSuggestion"] = !!has_container_suggestion
- if(has_container_suggestion)
- data["doSuggestContainer"] = !!do_suggest_container
- if(do_suggest_container)
- if(reagents.total_volume > 0)
- var/master_reagent = reagents.get_master_reagent()
- suggested_container = get_suggested_container(master_reagent)
- else
- suggested_container = default_container
- data["suggestedContainer"] = suggested_container
- selected_container = suggested_container
- else if (isnull(selected_container))
- selected_container = default_container
-
- data["selectedContainerRef"] = selected_container
- var/obj/item/reagent_containers/container = locate(selected_container)
- data["selectedContainerVolume"] = initial(container.volume)
+ //sanity checks for reagent path
+ var/datum/reagent/reagent = text2path(path)
+ if (!reagent)
+ return FALSE
- return data
+ //use energy
+ if(!use_energy(active_power_usage))
+ return FALSE
-/obj/machinery/chem_master/ui_act(action, params)
+ //do the operation
+ . = FALSE
+ if(do_transfer)
+ if(target.is_reacting)
+ return FALSE
+ if(source.trans_to(target, amount, target_id = reagent))
+ . = TRUE
+ else if(source.remove_reagent(reagent, amount))
+ . = TRUE
+ if(. && !QDELETED(src)) //transferring volatile reagents can cause a explosion & destory us
+ update_appearance(UPDATE_OVERLAYS)
+ return .
+
+/obj/machinery/chem_master/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
- if(action == "eject")
- replace_beaker(usr)
- return TRUE
-
- if(action == "transfer")
- var/reagent_ref = params["reagentRef"]
- var/amount = text2num(params["amount"])
- var/target = params["target"]
- return transfer_reagent(reagent_ref, amount, target)
-
- if(action == "toggleTransferMode")
- transfer_mode = !transfer_mode
- return TRUE
-
- if(action == "analyze")
- analyzed_reagent = locate(params["reagentRef"])
- if(analyzed_reagent)
- reagent_analysis_mode = TRUE
- update_appearance(UPDATE_ICON)
+ switch(action)
+ if("eject")
+ replace_beaker(ui.user)
return TRUE
- if(action == "stopAnalysis")
- reagent_analysis_mode = FALSE
- analyzed_reagent = null
- update_appearance(UPDATE_ICON)
- return TRUE
+ if("transfer")
+ if(is_printing)
+ say("buffer locked while printing!")
+ return
- if(action == "stopPrinting")
- is_printing = FALSE
- return TRUE
+ var/reagent_ref = params["reagentRef"]
+ var/amount = params["amount"]
+ var/target = params["target"]
- if(action == "toggleContainerSuggestion")
- do_suggest_container = !do_suggest_container
- return TRUE
+ if(target == "buffer")
+ return transfer_reagent(ui.user, beaker.reagents, reagents, reagent_ref, amount, TRUE)
+ else if(target == "beaker")
+ return transfer_reagent(ui.user, reagents, beaker.reagents, reagent_ref, amount, is_transfering)
+ return FALSE
- if(action == "selectContainer")
- selected_container = params["ref"]
- return TRUE
+ if("toggleTransferMode")
+ is_transfering = !is_transfering
+ return TRUE
- if(action == "create")
- if(reagents.total_volume == 0)
- return FALSE
- var/item_count = text2num(params["itemCount"])
- if(item_count <= 0)
- return FALSE
- create_containers(item_count)
- return TRUE
-
-/// Create N selected containers with reagents from buffer split between them
-/obj/machinery/chem_master/proc/create_containers(item_count = 1)
- var/obj/item/reagent_containers/container_style = locate(selected_container)
- var/is_pill_subtype = ispath(container_style, /obj/item/reagent_containers/pill)
- var/volume_in_each = reagents.total_volume / item_count
- var/printing_amount_current = is_pill_subtype ? printing_amount * 2 : printing_amount
-
- // Generate item name
- var/item_name_default = initial(container_style.name)
- var/datum/reagent/master_reagent = reagents.get_master_reagent()
- if(selected_container == default_container) // Tubes and bottles gain reagent name
- item_name_default = "[master_reagent.name] [item_name_default]"
- if(!(initial(container_style.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name
- item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)"
- // NOVA EDIT ADDITION START - Autonamed hyposprays/smartdarts
- if(ispath(container_style, /obj/item/reagent_containers/cup/vial) || ispath(container_style, /obj/item/reagent_containers/syringe/smartdart))
- item_name_default = "[master_reagent.name] [item_name_default]"
- // NOVA EDIT ADDITION END
-
- var/item_name = tgui_input_text(usr,
- "Container name",
- "Name",
- item_name_default,
- MAX_NAME_LEN)
-
- if(!item_name || !reagents.total_volume || QDELETED(src) || !usr.can_perform_action(src, ALLOW_SILICON_REACH))
- return FALSE
+ if("stopPrinting")
+ is_printing = FALSE
+ update_appearance(UPDATE_OVERLAYS)
+ return TRUE
- // Print and fill containers
- is_printing = TRUE
- update_appearance(UPDATE_ICON)
- printing_progress = 0
- printing_total = item_count
- while(item_count > 0)
- if(!is_printing)
- break
- use_energy(active_power_usage)
- stoplag(printing_speed)
- for(var/i in 1 to printing_amount_current)
- if(!item_count)
- continue
- var/obj/item/reagent_containers/item = new container_style(drop_location())
- adjust_item_drop_location(item)
- item.name = item_name
- item.reagents.clear_reagents()
- reagents.trans_to(item, volume_in_each, transferred_by = src)
- printing_progress++
- item_count--
- update_appearance(UPDATE_ICON)
- is_printing = FALSE
- update_appearance(UPDATE_ICON)
- return TRUE
-
-/// Transfer reagents to specified target from the opposite source
-/obj/machinery/chem_master/proc/transfer_reagent(reagent_ref, amount, target)
- if (amount == -1)
- amount = text2num(input("Enter the amount you want to transfer:", name, ""))
- if (amount == null || amount <= 0)
- return FALSE
- if (!beaker && target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE)
- return FALSE
- var/datum/reagent/reagent = locate(reagent_ref)
- if (!reagent)
- return FALSE
+ if("selectContainer")
+ var/obj/item/reagent_containers/target = locate(params["ref"])
+ if(!ispath(target))
+ return FALSE
- use_energy(active_power_usage)
+ selected_container = target
+ return TRUE
- if (target == TARGET_BUFFER)
- if(!check_reactions(reagent, beaker.reagents))
- return FALSE
- beaker.reagents.trans_to(src, amount, target_id = reagent.type)
- update_appearance(UPDATE_ICON)
- return TRUE
-
- if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_DESTROY)
- reagents.remove_reagent(reagent.type, amount)
- update_appearance(UPDATE_ICON)
- return TRUE
- if (target == TARGET_BEAKER && transfer_mode == TRANSFER_MODE_MOVE)
- if(!check_reactions(reagent, reagents))
- return FALSE
- reagents.trans_to(beaker, amount, target_id = reagent.type)
- update_appearance(UPDATE_ICON)
- return TRUE
+ if("create")
+ if(!reagents.total_volume || is_printing)
+ return FALSE
+
+ //validate print count
+ var/item_count = params["itemCount"]
+ if(isnull(item_count))
+ return FALSE
+ item_count = text2num(item_count)
+ if(isnull(item_count) || item_count <= 0)
+ return FALSE
+ item_count = min(item_count, printing_amount)
+ var/volume_in_each = round(reagents.total_volume / item_count, CHEMICAL_VOLUME_ROUNDING)
+
+ // Generate item name
+ var/item_name_default = initial(selected_container.name)
+ var/datum/reagent/master_reagent = reagents.get_master_reagent()
+ if(selected_container == default_container) // Tubes and bottles gain reagent name
+ item_name_default = "[master_reagent.name] [item_name_default]"
+ if(!(initial(selected_container.reagent_flags) & OPENCONTAINER)) // Closed containers get both reagent name and units in the name
+ item_name_default = "[master_reagent.name] [item_name_default] ([volume_in_each]u)"
+ // NOVA EDIT ADDITION START - Autonamed hyposprays/smartdarts
+ if(ispath(selected_container, /obj/item/reagent_containers/cup/vial) || ispath(selected_container, /obj/item/reagent_containers/syringe/smartdart))
+ item_name_default = "[master_reagent.name] [item_name_default]"
+ // NOVA EDIT ADDITION END
+ var/item_name = tgui_input_text(usr,
+ "Container name",
+ "Name",
+ item_name_default,
+ MAX_NAME_LEN)
+ if(!item_name)
+ return FALSE
+
+ //start printing
+ is_printing = TRUE
+ printing_progress = 0
+ printing_total = item_count
+ update_appearance(UPDATE_OVERLAYS)
+ create_containers(ui.user, item_count, item_name, volume_in_each)
+ return TRUE
- return FALSE
+/**
+ * Create N selected containers with reagents from buffer split between them
+ * Arguments
+ *
+ * * mob/user - the player printing these containers
+ * * item_count - number of containers to print
+ * * item_name - the name for each container printed
+ * * volume_in_each - volume in each container created
+ */
+/obj/machinery/chem_master/proc/create_containers(mob/user, item_count, item_name, volume_in_each)
+ PRIVATE_PROC(TRUE)
+
+ //lost power or manually stopped
+ if(!is_printing)
+ return
-/// Checks to see if the target reagent is being created (reacting) and if so prevents transfer
-/// Only prevents reactant from being moved so that people can still manlipulate input reagents
-/obj/machinery/chem_master/proc/check_reactions(datum/reagent/reagent, datum/reagents/holder)
- if(!reagent)
- return FALSE
- var/canMove = TRUE
- for(var/datum/equilibrium/equilibrium as anything in holder.reaction_list)
- if(equilibrium.reaction.reaction_flags & REACTION_COMPETITIVE)
- continue
- for(var/datum/reagent/result as anything in equilibrium.reaction.required_reagents)
- if(result == reagent.type)
- canMove = FALSE
- if(!canMove)
- say("Cannot move reagent during reaction!")
- return canMove
-
-/// Retrieve REF to the best container for provided reagent
-/obj/machinery/chem_master/proc/get_suggested_container(datum/reagent/reagent)
- var/preferred_container = reagent.default_container
- for(var/category in printable_containers)
- for(var/container in printable_containers[category])
- if(container == preferred_container)
- return REF(container)
- return default_container
+ //use power
+ if(!use_energy(active_power_usage))
+ return
-/obj/machinery/chem_master/examine(mob/user)
- . = ..()
- if(in_range(user, src) || isobserver(user))
- . += span_notice("The status display reads:
Reagent buffer capacity: [reagents.maximum_volume] units.
Number of containers printed at once increased by [100 * (printing_amount / initial(printing_amount)) - 100]%.")
+ //print the stuff
+ var/obj/item/reagent_containers/item = new selected_container(drop_location())
+ adjust_item_drop_location(item)
+ item.name = item_name
+ item.reagents.clear_reagents()
+ reagents.trans_to(item, volume_in_each, transferred_by = user)
+ printing_progress++
+ update_appearance(UPDATE_OVERLAYS)
+
+ //print more items
+ item_count --
+ if(item_count > 0)
+ addtimer(CALLBACK(src, PROC_REF(create_containers), user, item_count, item_name, volume_in_each), 0.75 SECONDS)
+ else
+ is_printing = FALSE
+ update_appearance(UPDATE_OVERLAYS)
/obj/machinery/chem_master/condimaster
name = "CondiMaster 3000"
desc = "Used to create condiments and other cooking supplies."
icon_state = "condimaster"
- has_container_suggestion = TRUE
/obj/machinery/chem_master/condimaster/load_printable_containers()
- printable_containers = list(
- CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS],
- )
-
-#undef TRANSFER_MODE_DESTROY
-#undef TRANSFER_MODE_MOVE
-#undef TARGET_BEAKER
-#undef TARGET_BUFFER
+ var/static/list/containers
+ if(!length(containers))
+ containers = list(CAT_CONDIMENTS = GLOB.reagent_containers[CAT_CONDIMENTS])
+ return containers
diff --git a/icons/obj/medical/chemical.dmi b/icons/obj/medical/chemical.dmi
index b4b26e4f848c62158486744538a343f2397e17ba..84dfd01d2d455103f75a8026227d79c70922cc64 100644
GIT binary patch
delta 10637
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%0D69XdT;l}qL4}jgU
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 {
- const { data } = useBackend();
- const { reagentAnalysisMode } = data;
+ const [analyzedReagent, setAnalyzedReagent] = useState();
+
return (
-
+
- {reagentAnalysisMode ? : }
+ {analyzedReagent ? (
+ setAnalyzedReagent(undefined)}
+ />
+ ) : (
+
+ setAnalyzedReagent(chemical)
+ }
+ />
+ )}
);
};
-const ChemMasterContent = (props) => {
+const ChemMasterContent = (props: {
+ analyze: (chemical: AnalyzableReagent) => void;
+}) => {
const { act, data } = useBackend();
const {
isPrinting,
printingProgress,
printingTotal,
- transferMode,
- hasBeaker,
- beakerCurrentVolume,
- beakerMaxVolume,
- beakerContents,
- bufferContents,
- bufferCurrentVolume,
- bufferMaxVolume,
+ maxPrintable,
+ isTransfering,
+ beaker,
+ buffer,
categories,
selectedContainerVolume,
- hasContainerSuggestion,
- doSuggestContainer,
- suggestedContainer,
} = data;
- const [itemCount, setItemCount] = useState(1);
+ const [itemCount, setItemCount] = useState(1);
+ const [showPreferredContainer, setShowPreferredContainer] =
+ useState(false);
+ const buffer_contents = buffer.contents;
return (
-
- {` / ${beakerMaxVolume} units`}
+
+ {` / ${beaker.maxVolume} units`}
-
)
}
>
- {!hasBeaker && (
+ {!beaker ? (
No beaker loaded.
- )}
- {!!hasBeaker && beakerCurrentVolume === 0 && (
+ ) : beaker.currentVolume === 0 ? (
Beaker is empty.
+ ) : (
+
+ {beaker.contents.map((chemical) => (
+
+ ))}
+
)}
-
- {beakerContents.map((chemical) => (
-
- ))}
-
-
- {` / ${bufferMaxVolume} units`}
+
+ {` / ${buffer.maxVolume} units`}
act('toggleTransferMode')}
- />
+ >
+ {isTransfering ? 'Moving reagents' : 'Destroying reagents'}
+
>
}
>
- {bufferContents.length === 0 && (
+ {buffer_contents.length === 0 ? (
Buffer is empty.
+ ) : (
+
+ {buffer_contents.map((chemical) => (
+
+ ))}
+
)}
-
- {bufferContents.map((chemical) => (
-
- ))}
-
{!isPrinting && (
+
+ setShowPreferredContainer((currentValue) => !currentValue)
+ }
+ >
+ Suggest
+
{
setItemCount(value);
}}
@@ -200,51 +208,36 @@ const ChemMasterContent = (props) => {
Math.round(
Math.min(
selectedContainerVolume,
- bufferCurrentVolume / itemCount,
+ buffer.currentVolume / itemCount,
) * 100,
) / 100
} u. each`}
act('create', {
itemCount: itemCount,
})
}
- />
+ >
+ Print
+
- ) : (
-
- ))
+ )
}
>
- {!!hasContainerSuggestion && (
- act('toggleContainerSuggestion')}
- checked={doSuggestContainer}
- mb={1}
- >
- Guess container by main reagent in the buffer
-
- )}
{categories.map((category) => (
- {category.containers.map(
- (container) =>
- (!hasContainerSuggestion || // Doesn't have suggestion
- (!!hasContainerSuggestion && !doSuggestContainer) || // Has sugestion and it's disabled
- (!!doSuggestContainer &&
- container.ref === suggestedContainer)) && ( // Suggestion enabled and container matches
-
- ),
- )}
+ {category.containers.map((container) => (
+
+ ))}
))}
@@ -256,9 +249,10 @@ const ChemMasterContent = (props) => {
act('stopPrinting')}
- />
+ >
+ Stop
+
}
>
{
);
};
-const ReagentEntry = (props) => {
+type ReagentProps = {
+ chemical: AnalyzableReagent;
+ transferTo: string;
+ analyze: (chemical: AnalyzableReagent) => void;
+};
+
+const ReagentEntry = (props: ReagentProps) => {
const { data, act } = useBackend();
- const { chemical, transferTo } = props;
+ const { chemical, transferTo, analyze } = props;
const { isPrinting } = data;
return (
@@ -295,7 +295,6 @@ const ReagentEntry = (props) => {
{
act('transfer', {
@@ -304,9 +303,10 @@ const ReagentEntry = (props) => {
target: transferTo,
});
}}
- />
+ >
+ 1
+
act('transfer', {
@@ -315,9 +315,10 @@ const ReagentEntry = (props) => {
target: transferTo,
})
}
- />
+ >
+ 5
+
act('transfer', {
@@ -326,9 +327,10 @@ const ReagentEntry = (props) => {
target: transferTo,
})
}
- />
+ >
+ 10
+
act('transfer', {
@@ -337,7 +339,9 @@ const ReagentEntry = (props) => {
target: transferTo,
})
}
- />
+ >
+ All
+
{
- act('analyze', {
- reagentRef: chemical.ref,
- })
- }
+ onClick={() => analyze(chemical)}
/>
);
};
-const ContainerButton = ({ container, category }) => {
+type CategoryButtonProps = {
+ category: Category;
+ container: Container;
+ showPreferredContainer: BooleanLike;
+};
+
+const ContainerButton = (props: CategoryButtonProps) => {
const { act, data } = useBackend();
- const { isPrinting, selectedContainerRef } = data;
+ const { isPrinting, selectedContainerRef, suggestedContainerRef } = data;
+ const { category, container, showPreferredContainer } = props;
const isPillPatch = ['pills', 'patches'].includes(category.name);
+
return (
{
>
{
) as any;
};
-const AnalysisResults = (props) => {
- const { act, data } = useBackend();
+const AnalysisResults = (props: {
+ analysisData: AnalyzableReagent;
+ onExit: () => void;
+}) => {
const {
name,
- state,
pH,
color,
description,
@@ -411,18 +427,18 @@ const AnalysisResults = (props) => {
metaRate,
overdose,
addictionTypes,
- } = data.analysisData;
+ } = props.analysisData;
+
const purityLevel =
purity <= 0.5 ? 'bad' : purity <= 0.75 ? 'average' : 'good'; // Color names
+
return (
act('stopAnalysis')}
- />
+ props.onExit()}>
+ Back
+
}
>
@@ -438,7 +454,6 @@ const AnalysisResults = (props) => {
{pH}
- {state}
{color}
diff --git a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx
index 6c2d3649325..3483c3ceede 100644
--- a/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx
+++ b/tgui/packages/tgui/interfaces/common/BeakerDisplay.tsx
@@ -8,7 +8,7 @@ import {
Section,
} from '../../components';
-type BeakerReagent = {
+export type BeakerReagent = {
name: string;
volume: number;
};