Merge pull request #11681 from PersianXerxes/medicalTGUINext

TGUI Next in the Medbay
This commit is contained in:
kevinz000
2021-01-09 15:27:10 -03:00
committed by Archie
parent 252df3c98b
commit ec5e8eea05
5 changed files with 864 additions and 212 deletions
@@ -199,86 +199,129 @@
//Calculated at init time as it never changes
data["pillStyles"] = pillStyles
return data
/obj/machinery/chem_master/ui_act(action, params)
if(..())
return
switch(action)
if("eject")
replace_beaker(usr)
. = TRUE
if("ejectp")
if("ejectPillBottle")
replace_pillbottle(usr)
. = TRUE
if("transferToBuffer")
if(beaker)
var/reagent = text2path(params["id"]) //This change was necessary due to some byond fuckery with reagents being translated back to their paths. Please do not modify this under any circumstance, otherwise you will break synthtissue.
var/amount = text2num(params["amount"])
if (amount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, useramount)
. = TRUE
if("transferFromBuffer")
if("transfer")
if(!beaker)
return FALSE
var/reagent = text2path(params["id"]) //This change was necessary due to some byond fuckery with reagents being translated back to their paths. Please do not modify this under any circumstance, otherwise you will break synthtissue.
var/amount = text2num(params["amount"])
if (amount > 0)
if(mode)
reagents.trans_id_to(beaker, reagent, amount)
. = TRUE
else
reagents.remove_reagent(reagent, amount)
. = TRUE
else if (amount == -1) // -1 means custom amount
useramount = input("Enter the Amount you want to transfer:", name, useramount) as num|null
if (useramount > 0)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, useramount)
. = TRUE
var/to_container = params["to"]
// Custom amount
if (amount == -1)
amount = text2num(input(
"Enter the amount you want to transfer:",
name, ""))
if (amount == null || amount <= 0)
return FALSE
if (to_container == "buffer")
end_fermi_reaction()
beaker.reagents.trans_id_to(src, reagent, amount)
return TRUE
if (to_container == "beaker" && mode)
end_fermi_reaction()
reagents.trans_id_to(beaker, reagent, amount)
return TRUE
if (to_container == "beaker" && !mode)
end_fermi_reaction()
reagents.remove_reagent(reagent, amount)
return TRUE
return FALSE
if("toggleMode")
mode = !mode
. = TRUE
if("createPill")
var/many = params["many"]
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
return TRUE
if("create")
if(reagents.total_volume == 0)
return
if(!condi)
var/amount = 1
var/vol_each = min(reagents.total_volume, 50)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many pills?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 50)
var/name = html_decode(stripped_input(usr,"Name:","Name your pill!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
return FALSE
var/item_type = params["type"]
// Get amount of items
var/amount = text2num(params["amount"])
if(amount == null)
amount = text2num(input(usr,
"Max 10. Buffer content will be split evenly.",
"How many to make?", 1))
amount = clamp(round(amount), 0, 10)
if (amount <= 0)
return FALSE
// Get units per item
var/vol_each = text2num(params["volume"])
var/vol_each_text = params["volume"]
var/vol_each_max = reagents.total_volume / amount
if (item_type == "pill")
vol_each_max = min(50, vol_each_max)
else if (item_type == "patch")
vol_each_max = min(40, vol_each_max)
else if (item_type == "bottle")
vol_each_max = min(30, vol_each_max)
else if (item_type == "condimentPack")
vol_each_max = min(10, vol_each_max)
else if (item_type == "condimentBottle")
vol_each_max = min(50, vol_each_max)
else if (item_type == "hypoVial")
vol_each_max = min(60, vol_each_max)
else if (item_type == "smartDart")
vol_each_max = min(20, vol_each_max)
else
return FALSE
if(vol_each_text == "auto")
vol_each = vol_each_max
if(vol_each == null)
vol_each = text2num(input(usr,
"Maximum [vol_each_max] units per item.",
"How many units to fill?",
vol_each_max))
vol_each = clamp(vol_each, 0, vol_each_max)
if(vol_each <= 0)
return FALSE
// Get item name
var/name = params["name"]
var/name_has_units = item_type == "pill" || item_type == "patch"
if(!name)
var/name_default = reagents.get_master_reagent_name()
if (name_has_units)
name_default += " ([vol_each]u)"
name = stripped_input(usr,
"Name:",
"Give it a name!",
name_default,
MAX_NAME_LEN)
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return FALSE
// Start filling
if(item_type == "pill")
var/obj/item/reagent_containers/pill/P
var/target_loc = drop_location()
var/drop_threshold = INFINITY
if(bottle)
var/datum/component/storage/STRB = bottle.GetComponent(/datum/component/storage)
var/datum/component/storage/STRB = bottle.GetComponent(
/datum/component/storage)
if(STRB)
drop_threshold = STRB.max_items - bottle.contents.len
target_loc = bottle
for(var/i in 1 to amount)
if(i <= drop_threshold)
P = new(target_loc)
for(var/i = 0; i < amount; i++)
if(i < drop_threshold)
P = new/obj/item/reagent_containers/pill(target_loc)
else
P = new(drop_location())
P = new/obj/item/reagent_containers/pill(drop_location())
P.name = trim("[name] pill")
if(chosenPillStyle == RANDOM_PILL_STYLE)
P.icon_state ="pill[rand(1,21)]"
@@ -287,171 +330,62 @@
if(P.icon_state == "pill4")
P.desc = "A tablet or capsule, but not just any, a red one, one taken by the ones not scared of knowledge, freedom, uncertainty and the brutal truths of reality."
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
else
var/name = html_decode(stripped_input(usr, "Name:", "Name your pack!", reagents.get_master_reagent_name(), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/pack/P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P,10)
. = TRUE
if("pillStyle")
var/id = text2num(params["id"])
chosenPillStyle = id
if("createPatch")
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 40)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many patches?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 40)
var/name = html_decode(stripped_input(usr,"Name:","Name your patch!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/pill/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P,vol_each)
. = TRUE
if("createBottle")
var/many = params["many"]
if(reagents.total_volume == 0)
return
if(condi)
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/food/condiment/P = new(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, P.volume)
else
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 30)
if(text2num(many))
amount_full = round(reagents.total_volume / 30)
vol_part = ((reagents.total_volume*1000) % 30000) / 1000 //% operator doesn't support decimals.
var/name = html_decode(stripped_input(usr, "Name:","Name your bottle!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "patch")
var/obj/item/reagent_containers/pill/patch/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/pill/patch(drop_location())
P.name = trim("[name] patch")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "bottle")
var/obj/item/reagent_containers/glass/bottle/P
for(var/i = 0; i < amount_full; i++)
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
P.name = trim("[name] bottle")
adjust_item_drop_location(P)
reagents.trans_to(P, 30)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle(drop_location())
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentPack")
var/obj/item/reagent_containers/food/condiment/pack/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment/pack(drop_location())
P.originalname = name
P.name = trim("[name] pack")
P.desc = "A small condiment pack. The label says it contains [name]."
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "condimentBottle")
var/obj/item/reagent_containers/food/condiment/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/food/condiment(drop_location())
P.originalname = name
P.name = trim("[name] bottle")
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "hypoVial")
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
//CITADEL ADD Hypospray Vials
if("createVial")
var/many = params["many"]
if(reagents.total_volume == 0)
return
reagents.trans_to(P, vol_each)
return TRUE
if(item_type == "smartDart")
var/obj/item/reagent_containers/syringe/dart/P
for(var/i = 0; i < amount; i++)
P = new /obj/item/reagent_containers/syringe/dart(drop_location())
P.name = trim("[name] SmartDart")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_each)
P.mode=!mode
P.update_icon()
return TRUE
return FALSE
var/amount_full = 0
var/vol_part = min(reagents.total_volume, 60)
if(text2num(many))
amount_full = round(reagents.total_volume / 60)
vol_part = reagents.total_volume % 60
var/name = html_decode(stripped_input(usr, "Name:","Name your hypovial!", (reagents.total_volume ? reagents.get_master_reagent_name() : " "), MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/glass/bottle/vial/small/P
for(var/i = 0; i < amount_full; i++)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, 60)
if(vol_part)
P = new/obj/item/reagent_containers/glass/bottle/vial/small(drop_location())
P.name = trim("[name] hypovial")
adjust_item_drop_location(P)
reagents.trans_to(P, vol_part)
. = TRUE
if("createDart")
for(var/datum/reagent/R in reagents.reagent_list)
if(!(istype(R, /datum/reagent/medicine)))
visible_message("<b>The [src]</b> beeps, \"<span class='warning'>SmartDarts are insoluble with non-medicinal compounds.\"</span>")
return
var/many = params["many"]
if(reagents.total_volume == 0)
return
var/amount = 1
var/vol_each = min(reagents.total_volume, 20)
if(text2num(many))
amount = CLAMP(round(input(usr, "Max 10. Buffer content will be split evenly.", "How many darts?", amount) as num|null), 0, 10)
if(!amount)
return
vol_each = min(reagents.total_volume / amount, 20)
var/name = html_decode(stripped_input(usr,"Name:","Name your SmartDart!", "[reagents.get_master_reagent_name()] ([vol_each]u)", MAX_NAME_LEN))
if(!name || !reagents.total_volume || !src || QDELETED(src) || !usr.canUseTopic(src, !issilicon(usr)))
return
var/obj/item/reagent_containers/syringe/dart/D
for(var/i = 0; i < amount; i++)
D = new /obj/item/reagent_containers/syringe/dart(drop_location())
D.name = trim("[name] SmartDart")
adjust_item_drop_location(D)
reagents.trans_to(D, vol_each)
D.mode=!mode
D.update_icon()
. = TRUE
//END CITADEL ADDITIONS
if("analyzeBeak")
var/datum/reagent/R = text2path(params["id"])
if(R)
var/state = "Unknown"
if(initial(R.reagent_state) == 1)
state = "Solid"
else if(initial(R.reagent_state) == 2)
state = "Liquid"
else if(initial(R.reagent_state) == 3)
state = "Gas"
var/const/P = 3 //The number of seconds between life ticks
var/T = initial(R.metabolization_rate) * (60 / P)
var/datum/chemical_reaction/Rcr = get_chemical_reaction(R)
if(Rcr && Rcr.FermiChem)
fermianalyze = TRUE
var/pHpeakCache = (Rcr.OptimalpHMin + Rcr.OptimalpHMax)/2
var/datum/reagent/targetReagent = beaker.reagents.has_reagent(R)
if(!targetReagent)
CRASH("Tried to find a reagent that doesn't exist in the chem_master!")
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" = targetReagent.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))
screen = "analyze"
return
if("analyzeBuff")
if("analyze")
var/datum/reagent/R = text2path(params["id"])
if(R)
var/state = "Unknown"
@@ -476,7 +410,7 @@
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))
screen = "analyze"
return
return TRUE
if("goScreen")
screen = params["screen"]
@@ -527,4 +461,4 @@
condi = TRUE
#undef PILL_STYLE_COUNT
#undef RANDOM_PILL_STYLE
#undef RANDOM_PILL_STYLE
@@ -0,0 +1,180 @@
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';
export const ChemDispenser = props => {
const { act, data } = useBackend(props);
const recording = !!data.recordingRecipe;
// 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)
.map(name => ({
name,
contents: data.recipes[name],
}));
const beakerTransferAmounts = data.beakerTransferAmounts || [];
const beakerContents = recording
&& Object.keys(data.recordingRecipe)
.map(id => ({
id,
name: toTitleCase(id.replace(/_/, ' ')),
volume: data.recordingRecipe[id],
}))
|| data.beakerContents
|| [];
return (
<Fragment>
<Section
title="Status"
buttons={recording && (
<Box inline mx={1} color="red">
<Icon name="circle" mr={1} />
Recording
</Box>
)}>
<LabeledList>
<LabeledList.Item label="Energy">
<ProgressBar
value={data.energy / data.maxEnergy}
content={toFixed(data.energy) + ' units'} />
</LabeledList.Item>
</LabeledList>
</Section>
<Section
title="Recipes"
buttons={(
<Fragment>
{!recording && (
<Box inline mx={1}>
<Button
color="transparent"
content="Clear recipes"
onClick={() => act('clear_recipes')} />
</Box>
)}
{!recording && (
<Button
icon="circle"
disabled={!data.isBeakerLoaded}
content="Record"
onClick={() => act('record_recipe')} />
)}
{recording && (
<Button
icon="ban"
color="transparent"
content="Discard"
onClick={() => act('cancel_recording')} />
)}
{recording && (
<Button
icon="save"
color="green"
content="Save"
onClick={() => act('save_recording')} />
)}
</Fragment>
)}>
<Box mr={-1}>
{recipes.map(recipe => (
<Button key={recipe.name}
icon="tint"
width="129.5px"
lineHeight="21px"
content={recipe.name}
onClick={() => act('dispense_recipe', {
recipe: recipe.name,
})} />
))}
{recipes.length === 0 && (
<Box color="light-gray">
No recipes.
</Box>
)}
</Box>
</Section>
<Section
title="Dispense"
buttons={(
beakerTransferAmounts.map(amount => (
<Button key={amount}
icon="plus"
selected={amount === data.amount}
content={amount}
onClick={() => act('amount', {
target: amount,
})} />
))
)}>
<Box mr={-1}>
{data.chemicals.map(chemical => (
<Button key={chemical.id}
icon="tint"
width="129.5px"
lineHeight="21px"
content={chemical.title}
onClick={() => act('dispense', {
reagent: chemical.id,
})} />
))}
</Box>
</Section>
<Section
title="Beaker"
buttons={(
beakerTransferAmounts.map(amount => (
<Button key={amount}
icon="minus"
disabled={recording}
content={amount}
onClick={() => act('remove', { amount })} />
))
)}>
<LabeledList>
<LabeledList.Item
label="Beaker"
buttons={!!data.isBeakerLoaded && (
<Button
icon="eject"
content="Eject"
disabled={!data.isBeakerLoaded}
onClick={() => act('eject')} />
)}>
{recording
&& 'Virtual beaker'
|| data.isBeakerLoaded
&& (
<Fragment>
<AnimatedNumber
initial={0}
value={data.beakerCurrentVolume} />
/{data.beakerMaxVolume} units
</Fragment>
)
|| 'No beaker'}
</LabeledList.Item>
<LabeledList.Item
label="Contents">
<Box color="label">
{(!data.isBeakerLoaded && !recording) && 'N/A'
|| beakerContents.length === 0 && 'Nothing'}
</Box>
{beakerContents.map(chemical => (
<Box
key={chemical.name}
color="label">
<AnimatedNumber
initial={0}
value={chemical.volume} />
{' '}
units of {chemical.name}
</Box>
))}
</LabeledList.Item>
</LabeledList>
</Section>
</Fragment>
);
};
@@ -0,0 +1,75 @@
import { round, toFixed } from 'common/math';
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { AnimatedNumber, Box, Button, LabeledList, NumberInput, Section } from '../components';
import { BeakerContents } from './common/BeakerContents';
export const ChemHeater = props => {
const { act, data } = useBackend(props);
const {
targetTemp,
isActive,
isBeakerLoaded,
currentTemp,
beakerCurrentVolume,
beakerMaxVolume,
beakerContents = [],
} = data;
return (
<Fragment>
<Section
title="Thermostat"
buttons={(
<Button
icon={isActive ? 'power-off' : 'times'}
selected={isActive}
content={isActive ? 'On' : 'Off'}
onClick={() => act('power')} />
)}>
<LabeledList>
<LabeledList.Item label="Target">
<NumberInput
width="65px"
unit="K"
step={2}
stepPixelSize={1}
value={round(targetTemp)}
minValue={0}
maxValue={1000}
onDrag={(e, value) => act('temperature', {
target: value,
})} />
</LabeledList.Item>
<LabeledList.Item label="Reading">
<Box
width="60px"
textAlign="right">
{isBeakerLoaded && (
<AnimatedNumber
value={currentTemp}
format={value => toFixed(value) + ' K'} />
) || '—'}
</Box>
</LabeledList.Item>
</LabeledList>
</Section>
<Section
title="Beaker"
buttons={!!isBeakerLoaded && (
<Fragment>
<Box inline color="label" mr={2}>
{beakerCurrentVolume} / {beakerMaxVolume} units
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act('eject')} />
</Fragment>
)}>
<BeakerContents
beakerLoaded={isBeakerLoaded}
beakerContents={beakerContents} />
</Section>
</Fragment>
);
};
@@ -0,0 +1,448 @@
import { Component, Fragment } from 'inferno';
import { act } from '../byond';
import { AnimatedNumber, Box, Button, ColorBox, LabeledList, NumberInput, Section, Table } from '../components';
export const ChemMaster = props => {
const { state } = props;
const { config, data } = state;
const { ref } = config;
const {
screen,
beakerContents = [],
bufferContents = [],
beakerCurrentVolume,
beakerMaxVolume,
isBeakerLoaded,
isPillBottleLoaded,
pillBottleCurrentAmount,
pillBottleMaxAmount,
} = data;
return (
<Fragment>
<Section
title="Beaker"
buttons={!!data.isBeakerLoaded && (
<Fragment>
<Box inline color="label" mr={2}>
<AnimatedNumber
value={beakerCurrentVolume}
initial={0} />
{` / ${beakerMaxVolume} units`}
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act(ref, 'eject')} />
</Fragment>
)}>
{!isBeakerLoaded && (
<Box color="label" mt="3px" mb="5px">
No beaker loaded.
</Box>
)}
{!!isBeakerLoaded && beakerContents.length === 0 && (
<Box color="label" mt="3px" mb="5px">
Beaker is empty.
</Box>
)}
<ChemicalBuffer>
{beakerContents.map(chemical => (
<ChemicalBufferEntry
key={chemical.id}
state={state}
chemical={chemical}
transferTo="buffer" />
))}
</ChemicalBuffer>
</Section>
<Section
title="Buffer"
buttons={(
<Fragment>
<Box inline color="label" mr={1}>
Mode:
</Box>
<Button
color={data.mode ? 'good' : 'bad'}
icon={data.mode ? 'exchange-alt' : 'times'}
content={data.mode ? 'Transfer' : 'Destroy'}
onClick={() => act(ref, 'toggleMode')} />
</Fragment>
)}>
{bufferContents.length === 0 && (
<Box color="label" mt="3px" mb="5px">
Buffer is empty.
</Box>
)}
<ChemicalBuffer>
{bufferContents.map(chemical => (
<ChemicalBufferEntry
key={chemical.id}
state={state}
chemical={chemical}
transferTo="beaker" />
))}
</ChemicalBuffer>
</Section>
<Section
title="Packaging">
<PackagingControls state={state} />
</Section>
{!!isPillBottleLoaded && (
<Section
title="Pill Bottle"
buttons={(
<Fragment>
<Box inline color="label" mr={2}>
{pillBottleCurrentAmount} / {pillBottleMaxAmount} pills
</Box>
<Button
icon="eject"
content="Eject"
onClick={() => act(ref, 'ejectPillBottle')} />
</Fragment>
)} />
)}
</Fragment>
);
};
const ChemicalBuffer = Table;
const ChemicalBufferEntry = props => {
const { state, chemical, transferTo } = props;
const { ref } = state.config;
return (
<Table.Row key={chemical.id}>
<Table.Cell color="label">
<AnimatedNumber
value={chemical.volume}
initial={0} />
{` units of ${chemical.name}`}
</Table.Cell>
<Table.Cell collapsing>
<Button
content="1"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 1,
to: transferTo,
})} />
<Button
content="5"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 5,
to: transferTo,
})} />
<Button
content="10"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 10,
to: transferTo,
})} />
<Button
content="All"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: 1000,
to: transferTo,
})} />
<Button
icon="ellipsis-h"
title="Custom amount"
onClick={() => act(ref, 'transfer', {
id: chemical.id,
amount: -1,
to: transferTo,
})} />
<Button
icon="question"
title="Analyze"
onClick={() => act(ref, 'analyze', {
id: chemical.id,
})} />
</Table.Cell>
</Table.Row>
);
};
const PackagingControlsItem = props => {
const {
label,
amountUnit,
amount,
onChangeAmount,
onCreate,
sideNote,
} = props;
return (
<LabeledList.Item label={label}>
<NumberInput
width={14}
unit={amountUnit}
step={1}
stepPixelSize={15}
value={amount}
minValue={1}
maxValue={10}
onChange={onChangeAmount} />
<Button ml={1}
content="Create"
onClick={onCreate} />
<Box inline ml={1}
color="label"
content={sideNote} />
</LabeledList.Item>
);
};
class PackagingControls extends Component {
constructor() {
super();
this.state = {
pillAmount: 1,
patchAmount: 1,
bottleAmount: 1,
packAmount: 1,
vialAmount: 1,
dartAmount: 1,
};
}
render() {
const { state, props } = this;
const { ref } = props.state.config;
const {
pillAmount,
patchAmount,
bottleAmount,
packAmount,
vialAmount,
dartAmount,
} = this.state;
const {
condi,
chosenPillStyle,
pillStyles = [],
} = props.state.data;
return (
<LabeledList>
{!condi && (
<LabeledList.Item label="Pill type">
{pillStyles.map(pill => (
<Button
key={pill.id}
width={5}
selected={pill.id === chosenPillStyle}
textAlign="center"
color="transparent"
onClick={() => act(ref, 'pillStyle', { id: pill.id })}>
<Box mx={-1} className={pill.className} />
</Button>
))}
</LabeledList.Item>
)}
{!condi && (
<PackagingControlsItem
label="Pills"
amount={pillAmount}
amountUnit="pills"
sideNote="max 50u"
onChangeAmount={(e, value) => this.setState({
pillAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'pill',
amount: pillAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Patches"
amount={patchAmount}
amountUnit="patches"
sideNote="max 40u"
onChangeAmount={(e, value) => this.setState({
patchAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'patch',
amount: patchAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Bottles"
amount={bottleAmount}
amountUnit="bottles"
sideNote="max 30u"
onChangeAmount={(e, value) => this.setState({
bottleAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'bottle',
amount: bottleAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Hypovials"
amount={vialAmount}
amountUnit="vials"
sideNote="max 60u"
onChangeAmount={(e, value) => this.setState({
vialAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'hypoVial',
amount: vialAmount,
volume: 'auto',
})} />
)}
{!condi && (
<PackagingControlsItem
label="Smartdarts"
amount={dartAmount}
amountUnit="darts"
sideNote="max 20u"
onChangeAmount={(e, value) => this.setState({
dartAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'smartDart',
amount: dartAmount,
volume: 'auto',
})} />
)}
{!!condi && (
<PackagingControlsItem
label="Packs"
amount={packAmount}
amountUnit="packs"
sideNote="max 10u"
onChangeAmount={(e, value) => this.setState({
packAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'condimentPack',
amount: packAmount,
volume: 'auto',
})} />
)}
{!!condi && (
<PackagingControlsItem
label="Bottles"
amount={bottleAmount}
amountUnit="bottles"
sideNote="max 50u"
onChangeAmount={(e, value) => this.setState({
bottleAmount: value,
})}
onCreate={() => act(ref, 'create', {
type: 'condimentBottle',
amount: bottleAmount,
volume: 'auto',
})} />
)}
</LabeledList>
);
}
}
const AnalysisResults = props => {
const { state, fermianalyze } = props;
const { ref } = state.config;
const { analyzeVars } = state.data;
return (
<Section
title="Analysis Results"
buttons={(
<Button
icon="arrow-left"
content="Back"
onClick={() => act(ref, 'goScreen', {
screen: 'home',
})} />
)}>
{!fermianalyze && (
<LabeledList>
<LabeledList.Item label="Name">
{analyzeVars.name}
</LabeledList.Item>
<LabeledList.Item label="State">
{analyzeVars.state}
</LabeledList.Item>
<LabeledList.Item label="Color">
<ColorBox color={analyzeVars.color} mr={1} />
{analyzeVars.color}
</LabeledList.Item>
<LabeledList.Item label="Description">
{analyzeVars.description}
</LabeledList.Item>
<LabeledList.Item label="Metabolization Rate">
{analyzeVars.metaRate} u/minute
</LabeledList.Item>
<LabeledList.Item label="Overdose Threshold">
{analyzeVars.overD}
</LabeledList.Item>
<LabeledList.Item label="Addiction Threshold">
{analyzeVars.addicD}
</LabeledList.Item>
</LabeledList>
)}
{!! data.fermianalyze && (
<LabeledList>
<LabeledList.Item label="Name">
{analyzeVars.name}
</LabeledList.Item>
<LabeledList.Item label="State">
{analyzeVars.state}
</LabeledList.Item>
<LabeledList.Item label="Color">
<ColorBox color={analyzeVars.color} mr={1} />
{analyzeVars.color}
</LabeledList.Item>
<LabeledList.Item label="Description">
{analyzeVars.description}
</LabeledList.Item>
<LabeledList.Item label="Metabolization Rate">
{analyzeVars.metaRate} u/minute
</LabeledList.Item>
<LabeledList.Item label="Overdose Threshold">
{analyzeVars.overD}
</LabeledList.Item>
<LabeledList.Item label="Addiction Threshold">
{analyzeVars.addicD}
</LabeledList.Item>
<LabeledList.Item label="Purity">
{analyzeVars.purityF}
</LabeledList.Item>
<LabeledList.Item label="Inverse Ratio">
{analyzeVars.inverseRatioF}
</LabeledList.Item>
<LabeledList.Item label="Purity E">
{analyzeVars.purityE}
</LabeledList.Item>
<LabeledList.Item label="Lower Optimal Temperature">
{analyzeVars.minTemp}
</LabeledList.Item>
<LabeledList.Item label="Upper Optimal Temperature">
{analyzeVars.maxTemp}
</LabeledList.Item>
<LabeledList.Item label="Explosive Temperature">
{analyzeVars.eTemp}
</LabeledList.Item>
<LabeledList.Item label="pH Peak">
{analyzeVars.pHpeak}
</LabeledList.Item>
</LabeledList>
)}
</Section>
);
};
+15
View File
@@ -19,7 +19,10 @@ import { CellularEmporium } from './interfaces/CellularEmporium';
import { CentcomPodLauncher } from './interfaces/CentcomPodLauncher';
import { ChemAcclimator } from './interfaces/ChemAcclimator';
import { ChemDebugSynthesizer } from './interfaces/ChemDebugSynthesizer';
import { ChemDispenser } from './interfaces/ChemDispenser';
import { ChemFilter } from './interfaces/ChemFilter';
import { ChemHeater } from './interfaces/ChemHeater';
import { ChemMaster } from './interfaces/ChemMaster';
import { ChemPress } from './interfaces/ChemPress';
import { ChemReactionChamber } from './interfaces/ChemReactionChamber';
import { ChemSplitter } from './interfaces/ChemSplitter';
@@ -179,10 +182,22 @@ const ROUTES = {
component: () => ChemAcclimator,
scrollable: false,
},
chem_dispenser: {
component: () => ChemDispenser,
scrollable: true,
},
chemical_filter: {
component: () => ChemFilter,
scrollable: true,
},
chem_heater: {
component: () => ChemHeater,
scrollable: true,
},
chem_master: {
component: () => ChemMaster,
scrollable: true,
},
chem_press: {
component: () => ChemPress,
scrollable: false,