Adds four TGUI Next UIs
This commit is contained in:
@@ -207,11 +207,14 @@
|
||||
|
||||
/obj/machinery/sleeper/ui_data()
|
||||
var/list/data = list()
|
||||
var/chemical_list = list()
|
||||
var/blood_percent = 0
|
||||
|
||||
data["occupied"] = occupant ? 1 : 0
|
||||
data["open"] = state_open
|
||||
data["efficiency"] = efficiency
|
||||
data["current_vol"] = reagents.total_volume
|
||||
data["tot_capacity"] = reagents.maximum_volume
|
||||
data["blood_levels"] = blood_percent
|
||||
data["blood_status"] = "Patient either has no blood, or does not require it to function."
|
||||
data["chemical_list"] = chemical_list
|
||||
|
||||
data["chems"] = list()
|
||||
for(var/chem in available_chems)
|
||||
@@ -248,9 +251,13 @@
|
||||
data["occupant"]["cloneLoss"] = mob_occupant.getCloneLoss()
|
||||
data["occupant"]["brainLoss"] = mob_occupant.getOrganLoss(ORGAN_SLOT_BRAIN)
|
||||
data["occupant"]["reagents"] = list()
|
||||
if(mob_occupant.reagents && mob_occupant.reagents.reagent_list.len)
|
||||
|
||||
if(mob_occupant.reagents.reagent_list.len)
|
||||
for(var/datum/reagent/R in mob_occupant.reagents.reagent_list)
|
||||
data["occupant"]["reagents"] += list(list("name" = R.name, "volume" = R.volume))
|
||||
chemical_list += list(list("name" = R.name, "volume" = R.volume))
|
||||
else
|
||||
chemical_list = "Patient has no reagents."
|
||||
|
||||
data["occupant"]["failing_organs"] = list()
|
||||
var/mob/living/carbon/C = mob_occupant
|
||||
if(C)
|
||||
@@ -259,21 +266,25 @@
|
||||
continue
|
||||
data["occupant"]["failing_organs"] += list(list("name" = Or.name))
|
||||
|
||||
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
|
||||
var/blood_id = C.get_blood_id()
|
||||
if(blood_id)
|
||||
data["occupant"]["blood"] = list() // We can start populating this list.
|
||||
var/blood_type = C.dna.blood_type
|
||||
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
|
||||
if(R)
|
||||
blood_type = R.name
|
||||
else
|
||||
blood_type = blood_id
|
||||
data["occupant"]["blood"]["maxBloodVolume"] = (BLOOD_VOLUME_NORMAL*C.blood_ratio)
|
||||
data["occupant"]["blood"]["currentBloodVolume"] = C.blood_volume
|
||||
data["occupant"]["blood"]["dangerBloodVolume"] = BLOOD_VOLUME_SAFE
|
||||
data["occupant"]["blood"]["bloodType"] = blood_type
|
||||
if(istype(C)) //Non-carbons shouldn't be able to enter sleepers, but this is to prevent runtimes if something ever breaks
|
||||
if(mob_occupant.has_dna()) // Blood-stuff is mostly a copy-paste from the healthscanner.
|
||||
blood_percent = round((C.blood_volume / BLOOD_VOLUME_NORMAL)*100)
|
||||
var/blood_id = C.get_blood_id()
|
||||
var/blood_warning = ""
|
||||
if(blood_percent < 80)
|
||||
blood_warning = "Patient has low blood levels."
|
||||
if(blood_percent < 60)
|
||||
blood_warning = "Patient has DANGEROUSLY low blood levels."
|
||||
if(blood_id)
|
||||
var/blood_type = C.dna.blood_type
|
||||
if(!(blood_id in GLOB.blood_reagent_types)) // special blood substance
|
||||
var/datum/reagent/R = GLOB.chemical_reagents_list[blood_id]
|
||||
if(R)
|
||||
blood_type = R.name
|
||||
else
|
||||
blood_type = blood_id
|
||||
data["blood_status"] = "Patient has [blood_type] type blood. [blood_warning]"
|
||||
data["blood_levels"] = blood_percent - (rand(1,35))
|
||||
return data
|
||||
|
||||
/obj/machinery/sleeper/ui_act(action, params)
|
||||
@@ -309,14 +320,14 @@
|
||||
if(allowed(usr))
|
||||
if(!is_operational())
|
||||
return
|
||||
reagents.remove_reagent(chem, 10)
|
||||
reagents.remove_reagent(chem, 1000)
|
||||
return
|
||||
if(chem in available_chems)
|
||||
if(!is_operational())
|
||||
return
|
||||
/*var/datum/reagent/R = reagents.has_reagent(chem) //For when purity effects are in
|
||||
if(R.purity < 0.8)*/
|
||||
reagents.remove_reagent(chem, 10)
|
||||
reagents.remove_reagent(chem, 1000)
|
||||
else
|
||||
visible_message("<span class='warning'>Access Denied.</span>")
|
||||
playsound(src, 'sound/machines/terminal_prompt_deny.ogg', 50, 0)
|
||||
|
||||
@@ -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,322 @@
|
||||
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,
|
||||
};
|
||||
}
|
||||
|
||||
render() {
|
||||
const { state, props } = this;
|
||||
const { ref } = props.state.config;
|
||||
const {
|
||||
pillAmount,
|
||||
patchAmount,
|
||||
bottleAmount,
|
||||
packAmount,
|
||||
} = 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="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>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,181 @@
|
||||
import { useBackend } from '../backend';
|
||||
import { Box, Section, LabeledList, Button, ProgressBar, Flex, AnimatedNumber } from '../components';
|
||||
import { Fragment } from 'inferno';
|
||||
|
||||
export const StasisSleeper = props => {
|
||||
const { act, data } = useBackend(props);
|
||||
|
||||
const {
|
||||
occupied,
|
||||
open,
|
||||
occupant = [],
|
||||
} = data;
|
||||
|
||||
const preSortChems = data.chems || [];
|
||||
const chems = preSortChems.sort((a, b) => {
|
||||
const descA = a.name.toLowerCase();
|
||||
const descB = b.name.toLowerCase();
|
||||
if (descA < descB) {
|
||||
return -1;
|
||||
}
|
||||
if (descA > descB) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
const synthchems = preSortChems.sort((a, b) => {
|
||||
const descA = a.name.toLowerCase();
|
||||
const descB = b.name.toLowerCase();
|
||||
if (descA < descB) {
|
||||
return -1;
|
||||
}
|
||||
if (descA > descB) {
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
|
||||
const damageTypes = [
|
||||
{
|
||||
label: 'Brute',
|
||||
type: 'bruteLoss',
|
||||
},
|
||||
{
|
||||
label: 'Burn',
|
||||
type: 'fireLoss',
|
||||
},
|
||||
{
|
||||
label: 'Toxin',
|
||||
type: 'toxLoss',
|
||||
},
|
||||
{
|
||||
label: 'Oxygen',
|
||||
type: 'oxyLoss',
|
||||
},
|
||||
];
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title={occupant.name ? occupant.name : 'No Occupant'}
|
||||
minHeight="210px"
|
||||
buttons={!!occupant.stat && (
|
||||
<Box
|
||||
inline
|
||||
bold
|
||||
color={occupant.statstate}>
|
||||
{occupant.stat}
|
||||
</Box>
|
||||
)}>
|
||||
{!!occupied && (
|
||||
<Fragment>
|
||||
<ProgressBar
|
||||
value={occupant.health}
|
||||
minValue={occupant.minHealth}
|
||||
maxValue={occupant.maxHealth}
|
||||
ranges={{
|
||||
good: [50, Infinity],
|
||||
average: [0, 50],
|
||||
bad: [-Infinity, 0],
|
||||
}} />
|
||||
<Box mt={1} />
|
||||
<LabeledList>
|
||||
{damageTypes.map(type => (
|
||||
<LabeledList.Item
|
||||
key={type.type}
|
||||
label={type.label}>
|
||||
<ProgressBar
|
||||
value={occupant[type.type]}
|
||||
minValue={0}
|
||||
maxValue={occupant.maxHealth}
|
||||
color="bad" />
|
||||
</LabeledList.Item>
|
||||
))}
|
||||
<LabeledList.Item
|
||||
label={'Blood'}>
|
||||
<ProgressBar
|
||||
value={data.blood_levels/100}
|
||||
color="bad">
|
||||
<AnimatedNumber value={data.blood_levels} />
|
||||
</ProgressBar>
|
||||
{data.blood_status}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Cells"
|
||||
color={occupant.cloneLoss ? 'bad' : 'good'}>
|
||||
{occupant.cloneLoss ? 'Damaged' : 'Healthy'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item
|
||||
label="Brain"
|
||||
color={occupant.brainLoss ? 'bad' : 'good'}>
|
||||
{occupant.brainLoss ? 'Abnormal' : 'Healthy'}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Fragment>
|
||||
)}
|
||||
</Section>
|
||||
<Section title="Chemical Analysis">
|
||||
<LabeledList.Item label="Chemical Contents">
|
||||
{data.chemical_list.map(specificChem => (
|
||||
<Box
|
||||
key={specificChem.id}
|
||||
color="good" >
|
||||
{specificChem.volume} units of {specificChem.name}
|
||||
</Box>
|
||||
),
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</Section>
|
||||
<Section
|
||||
title="Inject Chemicals"
|
||||
minHeight="105px"
|
||||
buttons={(
|
||||
<Button
|
||||
icon={open ? 'door-open' : 'door-closed'}
|
||||
content={open ? 'Open' : 'Closed'}
|
||||
onClick={() => act('door')} />
|
||||
)}>
|
||||
{chems.map(chem => (
|
||||
<Button
|
||||
key={chem.name}
|
||||
icon="flask"
|
||||
content={chem.name}
|
||||
disabled={!(occupied && chem.allowed)}
|
||||
width="140px"
|
||||
onClick={() => act('inject', {
|
||||
chem: chem.id,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Section>
|
||||
<Section
|
||||
title="Synthesize Chemicals">
|
||||
{synthchems.map(chem => (
|
||||
<Button
|
||||
key={chem.name}
|
||||
content={chem.name}
|
||||
disabled={!(chem.allowed)}
|
||||
width="140px"
|
||||
onClick={() => act('synth', {
|
||||
chem: chem.id,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Section>
|
||||
<Section
|
||||
title="Purge Chemicals">
|
||||
{chems.map(chem => (
|
||||
<Button
|
||||
key={chem.name}
|
||||
content={chem.name}
|
||||
disabled={!(chem.allowed)}
|
||||
width="140px"
|
||||
onClick={() => act('purge', {
|
||||
chem: chem.id,
|
||||
})}
|
||||
/>
|
||||
))}
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
@@ -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';
|
||||
@@ -76,6 +79,7 @@ import { RapidPipeDispenser } from './interfaces/RapidPipeDispenser';
|
||||
import { SatelliteControl } from './interfaces/SatelliteControl';
|
||||
import { ScannerGate } from './interfaces/ScannerGate';
|
||||
import { ShuttleManipulator } from './interfaces/ShuttleManipulator';
|
||||
import { Sleeper } from './interfaces/Sleeper';
|
||||
import { SlimeBodySwapper } from './interfaces/SlimeBodySwapper';
|
||||
import { Signaler } from './interfaces/Signaler';
|
||||
import { SmartVend } from './interfaces/SmartVend';
|
||||
@@ -185,10 +189,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,
|
||||
|
||||
Reference in New Issue
Block a user