mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-25 14:08:31 +01:00
General maintenance for chem master (#82002)
## About The Pull Request **1. Qol** - Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, removal & replacing actions - Analyzing reagents is now a client side feature & not a back end mode, meaning one person can see details of a reagent while the other can print stuff and do other operations so it's a non blocking operation. This also means 2 players can see information of 2 different reagents in their own screens, With that the overlay for analysis mode has been removed - You cannot do any tool acts on machines while printing. Balloon alerts will be displayed warning you of that. - The preferred container for the master reagent in the beaker is now showed in both condiment & chem master. It can be enabled/disabled via a CheckBox **2. Code Improvements** - Removed defines like `TARGET_BEAKER` , `TARGET_BEAKER` etc. ther functionality is implemented as params in the `transfer_reagent()` proc directly - Removed all variables relating to analyzing reagents like `reagent_analysis_mode`, `has_container_suggestion` etc. all memory savings - `printable_containers` now stores static values that can be shared across many chem masters - Updates only overlays and not the whole icon during operations for efficiency **3. Fixes** - You can hit the chem master with the screwdriver, wrench, crowbar & beaker when in combat mode - You cannot insert hologram items into the chem master - Deconstructing a condiment master will give you the circuit board already pre-programmed with that option selected so you don't need to use a screwdriver to re program it - `printing_amount` is now the maximum number of containers that can be printed at a time. Presently this number with upgraded parts would print out empty containers especially for patches. This is because `volume_per_item` does not take into consideration this var. Also this var would not give control to the player on exactly how many containers to print as whatever amount the player entered would be multiplied with this value producing a lot of waste & worse empty containers. Now this var determines exactly how many containers you can print and is imposed on the client side UI as well **4. Refactors (UI performance)** - Beaker data is compressed into a single entity & sent to the UI. This is set to null if no beaker is loaded thus saving data sent - Reuses Beaker props from chem synthesizer to reduce code - reagent REF replaced with direct type converted to text and later converted with `text2path()` cause its much faster ## Changelog 🆑 qol: Adds screen tips & examines for screwdriver, wrench, crowbar & beaker insertion, removal & replacing actions qol: Analyzing reagents no longer blocks other players from doing other operations. Multiple players can analyze different reagents on the same machine qol: You cannot do any tool acts on the machine while printing to prevent any side effects. qol: The preferred container for the master reagent in the beaker is now showed in both condiment & chem master. The feature can be enabled/disabled via a check box code: removed defines for reagent transfer, vars for reagent analyzis to save memory. Autodoc for other vars & procs fix: You can hit the chem master with tools like screwdriver, crowbar, wrench & beaker in combat mode fix: You cannot insert hologram items into the chem master fix: Deconstructing a condiment master will give you the circuit board already pre-programmed with that option fix: You now print the exact amount of containers requested even with upgraded parts without creating empty containers. Max printable containers is 13 with tier 4 parts able to print 50 containers. refactor: Optimized client side UI code & chem master as a whole. /🆑 --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
This commit is contained in:
@@ -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(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/examine(mob/user)
|
||||
. = ..()
|
||||
if(gone == beaker)
|
||||
beaker = null
|
||||
update_appearance(UPDATE_ICON)
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += span_notice("The status display reads:<br>Reagent buffer capacity: <b>[reagents.maximum_volume]</b> units.<br>Number of containers printed per cycle <b>[printing_amount]</b>.")
|
||||
if(!QDELETED(beaker))
|
||||
. += span_notice("[beaker] of <b>[beaker.reagents.maximum_volume]u</b> capacity inserted")
|
||||
. += span_notice("Right click with empty hand to remove beaker")
|
||||
else
|
||||
. += span_warning("Missing input beaker")
|
||||
|
||||
/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
|
||||
. += 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=ALL)
|
||||
/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,45 +122,124 @@
|
||||
// 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/wrench_act(mob/living/user, obj/item/tool)
|
||||
if(default_unfasten_wrench(user, tool) == SUCCESSFUL_UNFASTEN)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
/obj/machinery/chem_master/Exited(atom/movable/gone, direction)
|
||||
. = ..()
|
||||
if(gone == beaker)
|
||||
beaker = null
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/obj/machinery/chem_master/screwdriver_act(mob/living/user, obj/item/tool)
|
||||
if(default_deconstruction_screwdriver(user, icon_state, icon_state, tool))
|
||||
update_appearance(UPDATE_ICON)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
/obj/machinery/chem_master/on_set_is_operational(old_value)
|
||||
if(!is_operational)
|
||||
is_printing = FALSE
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
|
||||
/obj/machinery/chem_master/crowbar_act(mob/living/user, obj/item/tool)
|
||||
if(default_deconstruction_crowbar(tool))
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
return ITEM_INTERACT_BLOCKING
|
||||
/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],
|
||||
)
|
||||
return containers
|
||||
|
||||
/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())
|
||||
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
|
||||
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
|
||||
|
||||
/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_OVERLAYS)
|
||||
return ITEM_INTERACT_SUCCESS
|
||||
|
||||
/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
|
||||
|
||||
/**
|
||||
* 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)
|
||||
|
||||
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
|
||||
@@ -163,25 +250,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],
|
||||
)
|
||||
|
||||
/obj/machinery/chem_master/ui_assets(mob/user)
|
||||
return list(
|
||||
get_asset_datum(/datum/asset/spritesheet/chemmaster)
|
||||
@@ -195,269 +263,282 @@
|
||||
|
||||
/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()
|
||||
|
||||
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
|
||||
//printing statictics
|
||||
.["isPrinting"] = is_printing
|
||||
.["printingProgress"] = printing_progress
|
||||
.["printingTotal"] = printing_total
|
||||
.["maxPrintable"] = printing_amount
|
||||
|
||||
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
|
||||
//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
|
||||
|
||||
data["transferMode"] = transfer_mode
|
||||
//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
|
||||
|
||||
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
|
||||
//is transfering or destroying reagents. applied only for buffer
|
||||
.["isTransfering"] = is_transfering
|
||||
|
||||
data["selectedContainerRef"] = selected_container
|
||||
var/obj/item/reagent_containers/container = locate(selected_container)
|
||||
data["selectedContainerVolume"] = initial(container.volume)
|
||||
//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
|
||||
|
||||
return data
|
||||
//selected container
|
||||
.["selectedContainerRef"] = REF(selected_container)
|
||||
.["selectedContainerVolume"] = initial(selected_container.volume)
|
||||
|
||||
/obj/machinery/chem_master/ui_act(action, params)
|
||||
/**
|
||||
* 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
|
||||
|
||||
//sanity checks for reagent path
|
||||
var/datum/reagent/reagent = text2path(path)
|
||||
if (!reagent)
|
||||
return FALSE
|
||||
|
||||
//use energy
|
||||
if(!use_energy(active_power_usage))
|
||||
return FALSE
|
||||
|
||||
//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")
|
||||
var/reagent_ref = params["reagentRef"]
|
||||
var/amount = params["amount"]
|
||||
var/target = params["target"]
|
||||
|
||||
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("toggleTransferMode")
|
||||
is_transfering = !is_transfering
|
||||
return TRUE
|
||||
|
||||
if("stopPrinting")
|
||||
is_printing = FALSE
|
||||
update_appearance(UPDATE_OVERLAYS)
|
||||
return TRUE
|
||||
|
||||
if("selectContainer")
|
||||
var/obj/item/reagent_containers/target = locate(params["ref"])
|
||||
if(!ispath(target))
|
||||
return FALSE
|
||||
|
||||
selected_container = target
|
||||
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)"
|
||||
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
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
//use power
|
||||
if(!use_energy(active_power_usage))
|
||||
return
|
||||
|
||||
//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
|
||||
return TRUE
|
||||
|
||||
if(action == "toggleContainerSuggestion")
|
||||
do_suggest_container = !do_suggest_container
|
||||
return TRUE
|
||||
|
||||
if(action == "selectContainer")
|
||||
selected_container = params["ref"]
|
||||
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)"
|
||||
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
|
||||
|
||||
// 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
|
||||
|
||||
use_energy(active_power_usage)
|
||||
|
||||
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
|
||||
|
||||
return FALSE
|
||||
|
||||
/// 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
|
||||
|
||||
/obj/machinery/chem_master/examine(mob/user)
|
||||
. = ..()
|
||||
if(in_range(user, src) || isobserver(user))
|
||||
. += span_notice("The status display reads:<br>Reagent buffer capacity: <b>[reagents.maximum_volume]</b> units.<br>Number of containers printed at once increased by <b>[100 * (printing_amount / initial(printing_amount)) - 100]%</b>.")
|
||||
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
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
@@ -18,32 +18,22 @@ import {
|
||||
Tooltip,
|
||||
} from '../components';
|
||||
import { Window } from '../layouts';
|
||||
import { Beaker, BeakerReagent } from './common/BeakerDisplay';
|
||||
|
||||
type Data = {
|
||||
reagentAnalysisMode: BooleanLike;
|
||||
analysisData: Analysis;
|
||||
isPrinting: BooleanLike;
|
||||
printingProgress: number;
|
||||
printingTotal: number;
|
||||
transferMode: BooleanLike;
|
||||
hasBeaker: BooleanLike;
|
||||
beakerCurrentVolume: number;
|
||||
beakerMaxVolume: number;
|
||||
beakerContents: Reagent[];
|
||||
bufferContents: Reagent[];
|
||||
bufferCurrentVolume: number;
|
||||
bufferMaxVolume: number;
|
||||
categories: Category[];
|
||||
selectedContainerRef: string;
|
||||
selectedContainerVolume: number;
|
||||
hasContainerSuggestion: BooleanLike;
|
||||
doSuggestContainer: BooleanLike;
|
||||
suggestedContainer: string;
|
||||
type Container = {
|
||||
icon: string;
|
||||
ref: string;
|
||||
name: string;
|
||||
volume: number;
|
||||
};
|
||||
|
||||
type Analysis = {
|
||||
type Category = {
|
||||
name: string;
|
||||
state: string;
|
||||
containers: Container[];
|
||||
};
|
||||
|
||||
type AnalyzableReagent = BeakerReagent & {
|
||||
ref: string;
|
||||
pH: number;
|
||||
color: string;
|
||||
description: string;
|
||||
@@ -53,144 +43,162 @@ type Analysis = {
|
||||
addictionTypes: string[];
|
||||
};
|
||||
|
||||
type Category = {
|
||||
name: string;
|
||||
containers: Container[];
|
||||
};
|
||||
type AnalyzableBeaker = {
|
||||
contents: AnalyzableReagent[];
|
||||
} & Beaker;
|
||||
|
||||
type Reagent = {
|
||||
ref: string;
|
||||
name: string;
|
||||
volume: number;
|
||||
};
|
||||
|
||||
type Container = {
|
||||
icon: string;
|
||||
ref: string;
|
||||
name: string;
|
||||
volume: number;
|
||||
type Data = {
|
||||
categories: Category[];
|
||||
isPrinting: BooleanLike;
|
||||
printingProgress: number;
|
||||
printingTotal: number;
|
||||
maxPrintable: number;
|
||||
beaker: AnalyzableBeaker;
|
||||
buffer: AnalyzableBeaker;
|
||||
isTransfering: BooleanLike;
|
||||
suggestedContainerRef: string;
|
||||
selectedContainerRef: string;
|
||||
selectedContainerVolume: number;
|
||||
};
|
||||
|
||||
export const ChemMaster = (props) => {
|
||||
const { data } = useBackend<Data>();
|
||||
const { reagentAnalysisMode } = data;
|
||||
const [analyzedReagent, setAnalyzedReagent] = useState<AnalyzableReagent>();
|
||||
|
||||
return (
|
||||
<Window width={400} height={620}>
|
||||
<Window width={450} height={620}>
|
||||
<Window.Content scrollable>
|
||||
{reagentAnalysisMode ? <AnalysisResults /> : <ChemMasterContent />}
|
||||
{analyzedReagent ? (
|
||||
<AnalysisResults
|
||||
analysisData={analyzedReagent}
|
||||
onExit={() => setAnalyzedReagent(undefined)}
|
||||
/>
|
||||
) : (
|
||||
<ChemMasterContent
|
||||
analyze={(chemical: AnalyzableReagent) =>
|
||||
setAnalyzedReagent(chemical)
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const ChemMasterContent = (props) => {
|
||||
const ChemMasterContent = (props: {
|
||||
analyze: (chemical: AnalyzableReagent) => void;
|
||||
}) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
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<number>(1);
|
||||
const [showPreferredContainer, setShowPreferredContainer] =
|
||||
useState<BooleanLike>(false);
|
||||
const buffer_contents = buffer.contents;
|
||||
|
||||
return (
|
||||
<Box>
|
||||
<Section
|
||||
title="Beaker"
|
||||
buttons={
|
||||
!!hasBeaker && (
|
||||
beaker && (
|
||||
<Box>
|
||||
<Box inline color="label" mr={2}>
|
||||
<AnimatedNumber value={beakerCurrentVolume} initial={0} />
|
||||
{` / ${beakerMaxVolume} units`}
|
||||
<AnimatedNumber value={beaker.currentVolume} initial={0} />
|
||||
{` / ${beaker.maxVolume} units`}
|
||||
</Box>
|
||||
<Button
|
||||
icon="eject"
|
||||
content="Eject"
|
||||
onClick={() => act('eject')}
|
||||
/>
|
||||
<Button icon="eject" onClick={() => act('eject')}>
|
||||
Eject
|
||||
</Button>
|
||||
</Box>
|
||||
)
|
||||
}
|
||||
>
|
||||
{!hasBeaker && (
|
||||
{!beaker ? (
|
||||
<Box color="label" my={'4px'}>
|
||||
No beaker loaded.
|
||||
</Box>
|
||||
)}
|
||||
{!!hasBeaker && beakerCurrentVolume === 0 && (
|
||||
) : beaker.currentVolume === 0 ? (
|
||||
<Box color="label" my={'4px'}>
|
||||
Beaker is empty.
|
||||
</Box>
|
||||
) : (
|
||||
<Table>
|
||||
{beaker.contents.map((chemical) => (
|
||||
<ReagentEntry
|
||||
key={chemical.ref}
|
||||
chemical={chemical}
|
||||
transferTo="buffer"
|
||||
analyze={props.analyze}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
)}
|
||||
<Table>
|
||||
{beakerContents.map((chemical) => (
|
||||
<ReagentEntry
|
||||
key={chemical.ref}
|
||||
chemical={chemical}
|
||||
transferTo="buffer"
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
<Section
|
||||
title="Buffer"
|
||||
buttons={
|
||||
<>
|
||||
<Box inline color="label" mr={1}>
|
||||
<AnimatedNumber value={bufferCurrentVolume} initial={0} />
|
||||
{` / ${bufferMaxVolume} units`}
|
||||
<AnimatedNumber value={buffer.currentVolume} initial={0} />
|
||||
{` / ${buffer.maxVolume} units`}
|
||||
</Box>
|
||||
<Button
|
||||
color={transferMode ? 'good' : 'bad'}
|
||||
icon={transferMode ? 'exchange-alt' : 'trash'}
|
||||
content={transferMode ? 'Moving reagents' : 'Destroying reagents'}
|
||||
color={isTransfering ? 'good' : 'bad'}
|
||||
icon={isTransfering ? 'exchange-alt' : 'trash'}
|
||||
onClick={() => act('toggleTransferMode')}
|
||||
/>
|
||||
>
|
||||
{isTransfering ? 'Moving reagents' : 'Destroying reagents'}
|
||||
</Button>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{bufferContents.length === 0 && (
|
||||
{buffer_contents.length === 0 ? (
|
||||
<Box color="label" my={'4px'}>
|
||||
Buffer is empty.
|
||||
</Box>
|
||||
) : (
|
||||
<Table>
|
||||
{buffer_contents.map((chemical) => (
|
||||
<ReagentEntry
|
||||
key={chemical.ref}
|
||||
chemical={chemical}
|
||||
transferTo="beaker"
|
||||
analyze={props.analyze}
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
)}
|
||||
<Table>
|
||||
{bufferContents.map((chemical) => (
|
||||
<ReagentEntry
|
||||
key={chemical.ref}
|
||||
chemical={chemical}
|
||||
transferTo="beaker"
|
||||
/>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
{!isPrinting && (
|
||||
<Section
|
||||
title="Packaging"
|
||||
buttons={
|
||||
bufferContents.length !== 0 &&
|
||||
(!isPrinting ? (
|
||||
buffer_contents.length !== 0 && (
|
||||
<Box>
|
||||
<Button.Checkbox
|
||||
checked={showPreferredContainer}
|
||||
onClick={() =>
|
||||
setShowPreferredContainer((currentValue) => !currentValue)
|
||||
}
|
||||
>
|
||||
Suggest
|
||||
</Button.Checkbox>
|
||||
<NumberInput
|
||||
unit={'items'}
|
||||
step={1}
|
||||
value={itemCount}
|
||||
minValue={1}
|
||||
maxValue={50}
|
||||
maxValue={maxPrintable}
|
||||
onChange={(value) => {
|
||||
setItemCount(value);
|
||||
}}
|
||||
@@ -200,51 +208,36 @@ const ChemMasterContent = (props) => {
|
||||
Math.round(
|
||||
Math.min(
|
||||
selectedContainerVolume,
|
||||
bufferCurrentVolume / itemCount,
|
||||
buffer.currentVolume / itemCount,
|
||||
) * 100,
|
||||
) / 100
|
||||
} u. each`}
|
||||
</Box>
|
||||
<Button
|
||||
content="Print"
|
||||
icon="flask"
|
||||
onClick={() =>
|
||||
act('create', {
|
||||
itemCount: itemCount,
|
||||
})
|
||||
}
|
||||
/>
|
||||
>
|
||||
Print
|
||||
</Button>
|
||||
</Box>
|
||||
) : (
|
||||
<Button content="Printing..." icon="gear" iconSpin disabled />
|
||||
))
|
||||
)
|
||||
}
|
||||
>
|
||||
{!!hasContainerSuggestion && (
|
||||
<Button.Checkbox
|
||||
onClick={() => act('toggleContainerSuggestion')}
|
||||
checked={doSuggestContainer}
|
||||
mb={1}
|
||||
>
|
||||
Guess container by main reagent in the buffer
|
||||
</Button.Checkbox>
|
||||
)}
|
||||
{categories.map((category) => (
|
||||
<Box key={category.name}>
|
||||
<GroupTitle title={category.name} />
|
||||
{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
|
||||
<ContainerButton
|
||||
key={container.ref}
|
||||
category={category}
|
||||
container={container}
|
||||
/>
|
||||
),
|
||||
)}
|
||||
{category.containers.map((container) => (
|
||||
<ContainerButton
|
||||
key={container.ref}
|
||||
category={category}
|
||||
container={container}
|
||||
showPreferredContainer={showPreferredContainer}
|
||||
/>
|
||||
))}
|
||||
</Box>
|
||||
))}
|
||||
</Section>
|
||||
@@ -256,9 +249,10 @@ const ChemMasterContent = (props) => {
|
||||
<Button
|
||||
color="bad"
|
||||
icon="times"
|
||||
content="Stop"
|
||||
onClick={() => act('stopPrinting')}
|
||||
/>
|
||||
>
|
||||
Stop
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<ProgressBar
|
||||
@@ -282,9 +276,15 @@ const ChemMasterContent = (props) => {
|
||||
);
|
||||
};
|
||||
|
||||
const ReagentEntry = (props) => {
|
||||
type ReagentProps = {
|
||||
chemical: AnalyzableReagent;
|
||||
transferTo: string;
|
||||
analyze: (chemical: AnalyzableReagent) => void;
|
||||
};
|
||||
|
||||
const ReagentEntry = (props: ReagentProps) => {
|
||||
const { data, act } = useBackend<Data>();
|
||||
const { chemical, transferTo } = props;
|
||||
const { chemical, transferTo, analyze } = props;
|
||||
const { isPrinting } = data;
|
||||
return (
|
||||
<Table.Row key={chemical.ref}>
|
||||
@@ -295,7 +295,6 @@ const ReagentEntry = (props) => {
|
||||
</Table.Cell>
|
||||
<Table.Cell collapsing>
|
||||
<Button
|
||||
content="1"
|
||||
disabled={isPrinting}
|
||||
onClick={() => {
|
||||
act('transfer', {
|
||||
@@ -304,9 +303,10 @@ const ReagentEntry = (props) => {
|
||||
target: transferTo,
|
||||
});
|
||||
}}
|
||||
/>
|
||||
>
|
||||
1
|
||||
</Button>
|
||||
<Button
|
||||
content="5"
|
||||
disabled={isPrinting}
|
||||
onClick={() =>
|
||||
act('transfer', {
|
||||
@@ -315,9 +315,10 @@ const ReagentEntry = (props) => {
|
||||
target: transferTo,
|
||||
})
|
||||
}
|
||||
/>
|
||||
>
|
||||
5
|
||||
</Button>
|
||||
<Button
|
||||
content="10"
|
||||
disabled={isPrinting}
|
||||
onClick={() =>
|
||||
act('transfer', {
|
||||
@@ -326,9 +327,10 @@ const ReagentEntry = (props) => {
|
||||
target: transferTo,
|
||||
})
|
||||
}
|
||||
/>
|
||||
>
|
||||
10
|
||||
</Button>
|
||||
<Button
|
||||
content="All"
|
||||
disabled={isPrinting}
|
||||
onClick={() =>
|
||||
act('transfer', {
|
||||
@@ -337,7 +339,9 @@ const ReagentEntry = (props) => {
|
||||
target: transferTo,
|
||||
})
|
||||
}
|
||||
/>
|
||||
>
|
||||
All
|
||||
</Button>
|
||||
<Button
|
||||
icon="ellipsis-h"
|
||||
tooltip="Custom amount"
|
||||
@@ -353,21 +357,25 @@ const ReagentEntry = (props) => {
|
||||
<Button
|
||||
icon="question"
|
||||
tooltip="Analyze"
|
||||
onClick={() =>
|
||||
act('analyze', {
|
||||
reagentRef: chemical.ref,
|
||||
})
|
||||
}
|
||||
onClick={() => analyze(chemical)}
|
||||
/>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
);
|
||||
};
|
||||
|
||||
const ContainerButton = ({ container, category }) => {
|
||||
type CategoryButtonProps = {
|
||||
category: Category;
|
||||
container: Container;
|
||||
showPreferredContainer: BooleanLike;
|
||||
};
|
||||
|
||||
const ContainerButton = (props: CategoryButtonProps) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
const { isPrinting, selectedContainerRef } = data;
|
||||
const { isPrinting, selectedContainerRef, suggestedContainerRef } = data;
|
||||
const { category, container, showPreferredContainer } = props;
|
||||
const isPillPatch = ['pills', 'patches'].includes(category.name);
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
key={container.ref}
|
||||
@@ -375,7 +383,14 @@ const ContainerButton = ({ container, category }) => {
|
||||
>
|
||||
<Button
|
||||
overflow="hidden"
|
||||
color="transparent"
|
||||
color={'transparent'}
|
||||
backgroundColor={
|
||||
showPreferredContainer &&
|
||||
selectedContainerRef !== suggestedContainerRef && // if we selected the same container as the suggested then don't override color
|
||||
container.ref === suggestedContainerRef
|
||||
? 'blue'
|
||||
: 'transparent'
|
||||
}
|
||||
width={isPillPatch ? '32px' : '48px'}
|
||||
height={isPillPatch ? '32px' : '48px'}
|
||||
selected={container.ref === selectedContainerRef}
|
||||
@@ -399,11 +414,12 @@ const ContainerButton = ({ container, category }) => {
|
||||
) as any;
|
||||
};
|
||||
|
||||
const AnalysisResults = (props) => {
|
||||
const { act, data } = useBackend<Data>();
|
||||
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 (
|
||||
<Section
|
||||
title="Analysis Results"
|
||||
buttons={
|
||||
<Button
|
||||
icon="arrow-left"
|
||||
content="Back"
|
||||
onClick={() => act('stopAnalysis')}
|
||||
/>
|
||||
<Button icon="arrow-left" onClick={() => props.onExit()}>
|
||||
Back
|
||||
</Button>
|
||||
}
|
||||
>
|
||||
<LabeledList>
|
||||
@@ -438,7 +454,6 @@ const AnalysisResults = (props) => {
|
||||
</Box>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="pH">{pH}</LabeledList.Item>
|
||||
<LabeledList.Item label="State">{state}</LabeledList.Item>
|
||||
<LabeledList.Item label="Color">
|
||||
<ColorBox color={color} mr={1} />
|
||||
{color}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
Section,
|
||||
} from '../../components';
|
||||
|
||||
type BeakerReagent = {
|
||||
export type BeakerReagent = {
|
||||
name: string;
|
||||
volume: number;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user