From 37c3bbbd9c2a38b873de9c4b76d2ac7d25c07fb6 Mon Sep 17 00:00:00 2001
From: Fermi <33956696+Thalpy@users.noreply.github.com>
Date: Mon, 4 Jan 2021 01:48:35 +0000
Subject: [PATCH] Fixing things and gui
---
code/modules/reagents/chemistry/holder.dm | 6 +-
.../chemistry/machinery/chem_dispenser.dm | 119 +++++++++++++++--
.../chemistry/machinery/chem_heater.dm | 2 +-
.../chemistry/machinery/chem_master.dm | 10 +-
.../reagents/chemistry/recipes/medicine.dm | 2 +
.../chemistry/reagents/fermi_reagents.dm | 28 +++-
.../packages/tgui/interfaces/ChemDispenser.js | 124 ++++++++++++++----
tgui/packages/tgui/interfaces/ChemMaster.js | 8 +-
8 files changed, 246 insertions(+), 53 deletions(-)
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index c489edf88e..fd6204a8e3 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -973,10 +973,8 @@
for(var/A in cached_reagents)
var/datum/reagent/R = A
if (R.type == reagent)
- if((total_volume - amount) <= 0)//Because this can result in 0, I don't want it to crash.
- pH = REAGENT_NORMAL_PH
//In practice this is really confusing and players feel like it randomly melts their beakers, but I'm not sure how else to handle it. We'll see how it goes and I can remove this if it confuses people.
- else if (!ignore_pH)
+ if(!ignore_pH)
//if (((pH > R.pH) && (pH <= 7)) || ((pH < R.pH) && (pH >= 7)))
pH = (((pH - R.pH) / total_volume) * amount) + pH
if(istype(my_atom, /obj/item/reagent_containers/))
@@ -987,6 +985,8 @@
amount = clamp(amount, 0, R.volume)
R.volume -= amount
update_total()
+ if(total_volume <= 0)//Because this can result in 0, I don't want it to crash.
+ pH = REAGENT_NORMAL_PH
if(!safety)//So it does not handle reactions when it need not to
handle_reactions()
if(my_atom)
diff --git a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
index db16a10d1d..0fe4898b76 100644
--- a/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_dispenser.dm
@@ -24,6 +24,7 @@
circuit = /obj/item/circuitboard/machine/chem_dispenser
var/obj/item/stock_parts/cell/cell
var/powerefficiency = 0.0666666
+ var/dispenceUnit = 5
var/amount = 30
var/recharge_amount = 10
var/recharge_counter = 0
@@ -32,6 +33,7 @@
var/nopower_state = "dispenser_nopower"
var/has_panel_overlay = TRUE
var/obj/item/reagent_containers/beaker = null
+ var/list/stored_beakers = list()
var/list/dispensable_reagents = list(
/datum/reagent/hydrogen,
/datum/reagent/lithium,
@@ -58,7 +60,9 @@
/datum/reagent/silver,
/datum/reagent/iodine,
/datum/reagent/bromine,
- /datum/reagent/stable_plasma
+ /datum/reagent/stable_plasma,
+ /datum/reagent/fermi/acidic_buffer/weak,
+ /datum/reagent/fermi/basic_buffer/weak
)
//These become available once upgraded.
var/list/upgrade_reagents = list(
@@ -102,6 +106,7 @@
if(upgrade_reagents3)
upgrade_reagents3 = sortList(upgrade_reagents3, /proc/cmp_reagents_asc)
dispensable_reagents = sortList(dispensable_reagents, /proc/cmp_reagents_asc)
+ create_reagents(200, NO_REACT)
update_icon()
/obj/machinery/chem_dispenser/Destroy()
@@ -190,13 +195,16 @@
data["amount"] = amount
data["energy"] = cell.charge ? cell.charge * powerefficiency : "0" //To prevent NaN in the UI.
data["maxEnergy"] = cell.maxcharge * powerefficiency
+ data["storedVol"] = reagents.total_volume
+ data["maxVol"] = reagents.maximum_volume
data["isBeakerLoaded"] = beaker ? 1 : 0
+ data["stepAmount"] = dispenceUnit
var/beakerContents[0]
var/beakerCurrentVolume = 0
if(beaker && beaker.reagents && beaker.reagents.reagent_list.len)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
- beakerContents.Add(list(list("name" = R.name, "volume" = R.volume))) // list in a list because Byond merges the first list...
+ beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = R.volume))) // list in a list because Byond merges the first list...
beakerCurrentVolume += R.volume
data["beakerContents"] = beakerContents
@@ -204,10 +212,9 @@
data["beakerCurrentVolume"] = beakerCurrentVolume
data["beakerMaxVolume"] = beaker.volume
data["beakerTransferAmounts"] = beaker.possible_transfer_amounts
- data["beakerCurrentpH"] = beaker.reagents.pH
//pH accuracy
for(var/obj/item/stock_parts/capacitor/C in component_parts)
- data["partRating"]= 10**(C.rating-1)
+ data["beakerCurrentpH"] = round(beaker.reagents.pH, 10**-(C.rating+1))
else
data["beakerCurrentVolume"] = null
@@ -225,11 +232,17 @@
var/chemname = temp.name
if(is_hallucinating && prob(5))
chemname = "[pick_list_replacements("hallucination.json", "chemicals")]"
- chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name))))
+ chemicals.Add(list(list("title" = chemname, "id" = ckey(temp.name), "pH" = temp.pH, "pHCol" = ConvertpHToCol(temp.pH))))
data["chemicals"] = chemicals
data["recipes"] = saved_recipes
data["recordingRecipe"] = recording_recipe
+
+ var/storedContents[0]
+ if(reagents.total_volume)
+ for(var/datum/reagent/N in reagents.reagent_list)
+ storedContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume)))
+ data["storedContents"] = storedContents
return data
/obj/machinery/chem_dispenser/ui_act(action, params)
@@ -240,10 +253,9 @@
if(!is_operational() || QDELETED(beaker))
return
var/target = text2num(params["target"])
- if(target in beaker.possible_transfer_amounts)
- amount = target
- work_animation()
- . = TRUE
+ SetAmount(target)
+ work_animation()
+ . = TRUE
if("dispense")
if(!is_operational() || QDELETED(cell))
return
@@ -268,10 +280,9 @@
if(!is_operational() || recording_recipe)
return
var/amount = text2num(params["amount"])
- if(beaker && (amount in beaker.possible_transfer_amounts))
- beaker.reagents.remove_all(amount)
- work_animation()
- . = TRUE
+ beaker.reagents.remove_all(amount) //This should be set correctly in "amount"
+ work_animation()
+ . = TRUE
if("eject")
replace_beaker(usr)
. = TRUE
@@ -338,6 +349,48 @@
recording_recipe = null
. = TRUE
+ //Storing and unstoring reagents
+ if("store")
+ if(!is_operational() || QDELETED(cell))
+ return
+ if(!beaker)
+ return
+ if(recording_recipe)
+ say("Cannot store while recording!")
+ return
+ if(beaker.reagents.fermiIsReacting)
+ say("Cannot store ongoing reactions!")
+ return
+ var/reagent = text2path(params["id"])
+ var/datum/reagent/R = beaker.reagents.has_reagent(reagent)
+ if(reagents.total_volume+amount > reagents.maximum_volume)
+ say("Not enough storage space left!")
+ return
+ beaker.reagents.trans_id_to(src, R.type, amount)
+ work_animation()
+ . = TRUE
+
+ if("unstore")
+ if(!is_operational() || QDELETED(cell))
+ return
+ if(!beaker)
+ return
+ if(recording_recipe)
+ say("Cannot distribute while recording!")
+ return
+ var/reagent = text2path(params["id"])
+ var/datum/reagent/R = reagents.has_reagent(reagent)
+ reagents.trans_id_to(beaker, R.type, amount)
+ work_animation()
+ . = TRUE
+
+/obj/machinery/chem_dispenser/proc/SetAmount(inputAmount)
+ if(inputAmount % 5 == 0) //Always allow 5u values
+ amount = inputAmount
+ return
+ inputAmount -= inputAmount % dispenceUnit
+ amount = inputAmount
+
/obj/machinery/chem_dispenser/attackby(obj/item/I, mob/user, params)
if(default_unfasten_wrench(user, I))
return
@@ -390,6 +443,8 @@
cell = P
for(var/obj/item/stock_parts/matter_bin/M in component_parts)
newpowereff += 0.0166666666*M.rating
+ if(reagents)
+ reagents.maximum_volume = 200*(M.rating+1)
for(var/obj/item/stock_parts/capacitor/C in component_parts)
recharge_amount *= C.rating
for(var/obj/item/stock_parts/manipulator/M in component_parts)
@@ -399,6 +454,15 @@
dispensable_reagents |= upgrade_reagents2
if(M.rating > 3)
dispensable_reagents |= upgrade_reagents3
+ switch(M.rating)
+ if(0)
+ dispenceUnit = 5
+ if(1)
+ dispenceUnit = 3
+ if(2)
+ dispenceUnit = 2
+ if(3 to INFINITY)
+ dispenceUnit = 1
powerefficiency = round(newpowereff, 0.01)
/obj/machinery/chem_dispenser/proc/replace_beaker(mob/living/user, obj/item/reagent_containers/new_beaker)
@@ -409,6 +473,8 @@
user.put_in_hands(B)
if(new_beaker)
beaker = new_beaker
+ if(amount > beaker.reagents.maximum_volume)
+ amount = beaker.reagents.maximum_volume
else
beaker = null
update_icon()
@@ -427,6 +493,32 @@
replace_beaker(user)
return TRUE
+/obj/machinery/chem_dispenser/proc/ConvertpHToCol(pH)
+ switch(pH)
+ if(-INFINITY to 1)
+ return "red"
+ if(1 to 2)
+ return "orange"
+ if(2 to 3)
+ return "average"
+ if(3 to 4)
+ return "yellow" //yellow looks really bad for some reason
+ if(4 to 5)
+ return "olive"
+ if(5 to 6)
+ return "good"
+ if(6 to 8)
+ return "green"
+ if(8 to 9.5)
+ return "teal"
+ if(9.5 to 11)
+ return "blue"
+ if(11 to 12.5)
+ return "violet"
+ if(12.5 to INFINITY)
+ return "purple"
+
+
/obj/machinery/chem_dispenser/drinks/Initialize()
. = ..()
AddComponent(/datum/component/simple_rotation, ROTATION_ALTCLICK | ROTATION_CLOCKWISE)
@@ -453,6 +545,7 @@
b_o.pixel_y = -7
b_o.pixel_x = rand(-9, 9)
return b_o
+
/obj/machinery/chem_dispenser/drinks
name = "soda dispenser"
diff --git a/code/modules/reagents/chemistry/machinery/chem_heater.dm b/code/modules/reagents/chemistry/machinery/chem_heater.dm
index 8c3b9c7f99..cd8ee2d986 100644
--- a/code/modules/reagents/chemistry/machinery/chem_heater.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_heater.dm
@@ -126,7 +126,7 @@
var beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
- beakerContents.Add(list(list("name" = R.name, "volume" = R.volume, "purity" = R.purity))) // list in a list because Byond merges the first list...
+ beakerContents.Add(list(list("name" = R.name, "volume" = round(R.volume, 0.01), "purity" = round(R.purity, 0.01)))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
return data
diff --git a/code/modules/reagents/chemistry/machinery/chem_master.dm b/code/modules/reagents/chemistry/machinery/chem_master.dm
index 32ac7cecba..cf49039fde 100644
--- a/code/modules/reagents/chemistry/machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry/machinery/chem_master.dm
@@ -184,13 +184,13 @@
var/beakerContents[0]
if(beaker)
for(var/datum/reagent/R in beaker.reagents.reagent_list)
- beakerContents.Add(list(list("name" = R.name, "id" = ckey(R.name), "volume" = R.volume))) // list in a list because Byond merges the first list...
+ beakerContents.Add(list(list("name" = R.name, "id" = R.type, "volume" = R.volume))) // list in a list because Byond merges the first list...
data["beakerContents"] = beakerContents
var/bufferContents[0]
if(reagents.total_volume)
for(var/datum/reagent/N in reagents.reagent_list)
- bufferContents.Add(list(list("name" = N.name, "id" = ckey(N.name), "volume" = N.volume))) // ^
+ bufferContents.Add(list(list("name" = N.name, "id" = N.type, "volume" = N.volume))) // ^
data["bufferContents"] = bufferContents
//Calculated at init time as it never changes
@@ -216,7 +216,7 @@
if(action == "transfer")
if(!beaker)
return FALSE
- var/reagent = GLOB.name2reagent[params["id"]]
+ var/reagent = text2path(params["id"])
var/amount = text2num(params["amount"])
var/to_container = params["to"]
// Custom amount
@@ -386,7 +386,7 @@
if(action == "analyze")
// var/datum/reagent/R = GLOB.name2reagent[params["id"]]
- var/reagent = GLOB.name2reagent[params["id"]]
+ var/reagent = text2path(params["id"])
var/datum/reagent/R = GLOB.chemical_reagents_list[reagent]
if(R)
var/state = "Unknown"
@@ -405,7 +405,7 @@
analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity, "inverseRatioF" = initial(R.inverse_chem_val), "purityE" = initial(Rcr.PurityMin), "minTemp" = initial(Rcr.OptimalTempMin), "maxTemp" = initial(Rcr.OptimalTempMax), "eTemp" = initial(Rcr.ExplodeTemp), "pHpeak" = pHpeakCache)
else
fermianalyze = FALSE
- analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold))
+ analyzeVars = list("name" = initial(R.name), "state" = state, "color" = initial(R.color), "description" = initial(R.description), "metaRate" = T, "overD" = initial(R.overdose_threshold), "addicD" = initial(R.addiction_threshold), "purityF" = R.purity)
screen = "analyze"
return TRUE
diff --git a/code/modules/reagents/chemistry/recipes/medicine.dm b/code/modules/reagents/chemistry/recipes/medicine.dm
index d4d66af240..1a92ba0ad9 100644
--- a/code/modules/reagents/chemistry/recipes/medicine.dm
+++ b/code/modules/reagents/chemistry/recipes/medicine.dm
@@ -117,6 +117,8 @@
if(St.purity < 1)
St.volume *= St.purity
St.purity = 1
+ if(!N)
+ return
var/amount = clamp(0.002, 0, N.volume)
N.volume -= amount
St.data["grown_volume"] = St.data["grown_volume"] + added_volume
diff --git a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
index 1801986ebe..453fe50e9c 100644
--- a/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
+++ b/modular_citadel/code/modules/reagents/chemistry/reagents/fermi_reagents.dm
@@ -335,11 +335,13 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
holder.clear_reagents()
/datum/reagent/fermi/acidic_buffer
- name = "Acidic buffer"
+ name = "Potent acidic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards acidity when added to another."
color = "#fbc314"
pH = 0
+ chemical_flags = REAGENT_FORCEONNEW
can_synth = TRUE
+ var/strength = 2
//Consumes self on addition and shifts pH
/datum/reagent/fermi/acidic_buffer/on_new(datapH)
@@ -348,18 +350,36 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
data = datapH
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
- holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
+ holder.pH = ((holder.pH * (holder.total_volume-volume))+(pH * (volume*strength)))/(holder.total_volume + volume)
holder.my_atom.visible_message("The beaker fizzes as the pH changes!")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
..()
+/datum/reagent/fermi/acidic_buffer/weak
+ name = "Acidic buffer"
+ description = "This reagent will consume itself and move the pH of a beaker towards acidity when added to another."
+ color = "#fbf344"
+ pH = 4
+ can_synth = TRUE
+ strength = 0.4
+
/datum/reagent/fermi/basic_buffer
- name = "Basic buffer"
+ name = "Potent basic buffer"
description = "This reagent will consume itself and move the pH of a beaker towards alkalinity when added to another."
color = "#3853a4"
pH = 14
+ chemical_flags = REAGENT_FORCEONNEW
can_synth = TRUE
+ var/strength = 2
+
+/datum/reagent/fermi/basic_buffer/weak
+ name = "Basic buffer"
+ description = "This reagent will consume itself and move the pH of a beaker towards alkalinity when added to another."
+ color = "#5873c4"
+ pH = 10
+ can_synth = TRUE
+ strength = 0.4
/datum/reagent/fermi/basic_buffer/on_new(datapH)
if(holder.has_reagent(/datum/reagent/stabilizing_agent))
@@ -367,7 +387,7 @@ datum/reagent/fermi/nanite_b_gone/reaction_obj(obj/O, reac_volume)
data = datapH
if(LAZYLEN(holder.reagent_list) == 1)
return ..()
- holder.pH = ((holder.pH * holder.total_volume)+(pH * (volume)))/(holder.total_volume + (volume))
+ holder.pH = ((holder.pH * (holder.total_volume-volume))+(pH * (volume*strength)))/(holder.total_volume + volume)
holder.my_atom.visible_message("The beaker froths as the pH changes!")
playsound(holder.my_atom, 'sound/FermiChem/bufferadd.ogg', 50, 1)
holder.remove_reagent(type, volume, ignore_pH = TRUE)
diff --git a/tgui/packages/tgui/interfaces/ChemDispenser.js b/tgui/packages/tgui/interfaces/ChemDispenser.js
index 0724a9e85f..5390552dca 100644
--- a/tgui/packages/tgui/interfaces/ChemDispenser.js
+++ b/tgui/packages/tgui/interfaces/ChemDispenser.js
@@ -1,13 +1,18 @@
import { toFixed } from 'common/math';
import { toTitleCase } from 'common/string';
import { Fragment } from 'inferno';
-import { useBackend } from '../backend';
-import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section } from '../components';
+import { useBackend, useLocalState } from '../backend';
+import { AnimatedNumber, Box, Button, Icon, LabeledList, ProgressBar, Section, Table, NumberInput } from '../components';
import { Window } from '../layouts';
export const ChemDispenser = (props, context) => {
const { act, data } = useBackend(context);
const recording = !!data.recordingRecipe;
+ const [hasCol, setHasCol] = useLocalState(
+ context, 'fs_title', false);
+ const {
+ storedContents = [],
+ } = data;
// TODO: Change how this piece of shit is built on server side
// It has to be a list, not a fucking OBJECT!
const recipes = Object.keys(data.recipes)
@@ -28,7 +33,7 @@ export const ChemDispenser = (props, context) => {
return (