cleanup, icon_stuff, tutorial, sound, balance tweaks

This commit is contained in:
Darlantan
2022-09-27 02:20:10 -04:00
parent 28ca297677
commit a84d9c68e3
6 changed files with 213 additions and 217 deletions

View File

@@ -73256,6 +73256,7 @@
/turf/simulated/floor/tiled/white,
/area/medical/medbay)
"tpy" = (
/obj/machinery/chemical_synthesizer,
/obj/machinery/hologram/holopad,
/obj/machinery/atmospherics/pipe/simple/hidden/supply{
dir = 10

View File

@@ -4,27 +4,7 @@
#define RECIPE_MAX_STRING 160
#define RECIPE_MAX_STEPS 16
// Recipes are stored as a list which alternates between chemical id's and volumes to add.
// TODO:
// Design UI
// DONE TGUI procs
// DONE Create procs to take synthesis steps as an input and stores as a 1 click synthesis button. Needs name, expected output volume.
// DONE Create procs to actually perform the reagent transfer/etc. for a synthesis, reading the stored synthesis steps.
// DONE Implement a step-mode where the player manually clicks on each step and an expert mode where players input a comma-delineated list.
// DONE Add process() code which makes the machine actually work. Perhaps tie a boolean and single start proc into process().
// DONE Give the machine queue-behavior which allows players to queue up multiple recipes, even when the machine is busy. Reference protolathe code.
// DONE Give the machine a way to stop a synthesis and purge/bottle the reaction vessel.
// DONE Perhaps use recipes as a "ID" "num" "ID" "num" list to avoid using multiple lists.
// DONE Panel open button.
// DONE Code for power usage.
// Update_icon() overrides.
// Underlay code for the reaction vessel.
// DONE Add an eject catalyst bottle button.
// DONE Make sure recipes can only be removed when the machine is idle. Adding should be fine.
// May need yet another list which is just strings which match recipe ID's.
// For user recipes, make clicking on the recipe give a prompt with "add to queue," "export recipe," and "delete recipe."
// Recipes are stored as a list which alternates between chemical id's and volumes to add, e.g. 1 = 'Carbon', 2 = 20, 3 = 'Silicon', 4 = 20
/obj/machinery/chemical_synthesizer
name = "chemical synthesizer"
desc = "A programmable machine capable of automatically synthesizing medicine."
@@ -43,11 +23,9 @@
var/busy = FALSE
var/production_mode = FALSE // Toggle between click-step input and comma-delineated text input for creating recipes.
var/use_catalyst = TRUE // Determines whether or not the catalyst will be added to reagents while processing a recipe.
var/delay_modifier = 3 // This is multiplied by the volume of a step to determine how long each step takes. Bigger volume = slower.
var/delay_modifier = 4 // This is multiplied by the volume of a step to determine how long each step takes. Bigger volume = slower.
var/obj/item/weapon/reagent_containers/glass/catalyst = null // This is where the user adds catalyst. Usually phoron.
var/list/debug_data // DELETE THIS ONCE DONE TESTNG
var/list/recipes = list() // This holds chemical recipes up to a maximum determined by SYNTHESIZER_MAX_RECIPES. Two-dimensional.
var/list/queue = list() // This holds the recipe id's for queued up recipes.
var/list/catalyst_ids = list() // This keeps track of the chemicals in the catalyst to remove before bottling.
@@ -98,11 +76,72 @@
add_cartridge(new type(src))
panel_open = FALSE
var/obj/item/weapon/paper/P = new /obj/item/weapon/paper(get_turf(src))
P.name = "Synthesizer Instructions"
P.desc = "A photocopy of a handwritten note."
P.info = {"Hello there! This device is a new NanoTrasen product currently being shipped to select facilities \
for internal testing! We haven't finished the instruction manual yet so each unit shipped with this pamphlet \
(I really hope you can read my handwriting). This machine is a programmable chemical synthesizer which, if used \
correctly, will allow you to queue up some recipes and go work on something else while the medicine manufactures. \
It's slower than doing things by hand but it also keeps your hands free! And yes, it bottles automatically. \
<BR><BR>To get started, you need to program some recipes. The machine has two modes for this: tutorial and production. \
Tutorial is intended to teach you how recipes work, or to create recipes for later use with production mode. This one \
should be self-explanatory, just follow the prompts. Production mode allows you to rapidly import recipes in CSV format. \
If I've lost you, just keep reading; once you give it a name and tell the machine how many steps are in the recipe, just \
input the recipe as a comma-separated string of chemical names and volumes to be added, like "Chem1,10,Chem2,20,... \
<BR><BR>If that still doesn't make sense, I've included an example for Dylovene at the bottom. Also, don't include \
catalyst reagents in the recipe, read below for that part. Also also, remember that chemical names are case sensitive and \
cartridge names are usually Capitalized Like These Words (AND FOR THE LOVE OF GOD KEVIN, STOP CHANGING THE NAMES ON THE \
LABELS WHEN THE CHEMISTS AREN'T LOOKING IT ISN'T FUNNY ANYMORE). \
<BR><BR>Next important concept is the catalyst, intended for catalyst reagents (usually phoron). When the catalyst option is \
enabled, whatever is in the catalyst bottle gets added to the reaction chamber before synthesis begins. When the \
recipe is done, it extracts the catalyst, bottles whatever you made, then adds the catalyst back before starting \
the next recipe in the queue. It's up to you to make sure no unwanted side reactions happen, and yes, this means \
you cannot queue up catalyst recipes with recipes ruined by the catalyst. Maybe add "NO CAT" or something to the \
name for recipes like that? \
<BR><BR>And that's the really important stuff. Remember you can export recipes for later shifts, just copy the \
output into your PDA or something. Oh, and stalling. Say you're missing a cartridge or the vessel is full (the \
capacity is [src.reagents.maximum_volume]) or you press the emergency stop button. The machine will stall, \
clearing the temporary memory. To get it started again, you just need to empty the vessel. Anyway, here's \
example recipe. \
<BR><BR> Name: Dylovene (60u) \
<BR> Number of steps: 3 \
<BR> Recipe string: Silicon,20,Nitrogen,20,Potassium,20"}
/obj/machinery/chemical_synthesizer/examine(mob/user)
. = ..()
if(panel_open)
. += "It has [cartridges.len] cartridges installed, and has space for [SYNTHESIZER_MAX_CARTRIDGES - cartridges.len] more."
/obj/machinery/chemical_synthesizer/power_change()
. = ..()
update_icon()
/obj/machinery/chemical_synthesizer/update_icon()
underlays.Cut()
if(stat & BROKEN)
icon_state = "synth_broken"
return
if(stat & NOPOWER)
icon_state = "synth_off"
return
if(!busy)
if(catalyst)
icon_state = "synth_idle_bottle"
else
icon_state = "synth_idle"
else
icon_state = "synth_working"
if(catalyst) // All underlay icon_states requires the catalyst bottle to be present, so this works as a check.
if(catalyst.reagents.reagent_list.len)
var/image/cat_filling = image(icon, src, "synth_catalyst", -1)
cat_filling.color = catalyst.reagents.get_color()
underlays += cat_filling
if(src.reagents.reagent_list.len)
var/image/ves_filling = image(icon, src, "synth_vessel", -2)
ves_filling.color = src.reagents.get_color()
underlays += ves_filling
/obj/machinery/chemical_synthesizer/proc/add_cartridge(obj/item/weapon/reagent_containers/chem_disp_cartridge/C, mob/user)
if(!panel_open)
if(user)
@@ -169,6 +208,9 @@
if(catalyst)
to_chat(user, "<span class='warning'>There is already \a [catalyst] in \the [src] catalyst slot!</span>")
return
if(stat & (BROKEN|NOPOWER))
to_chat(user, "<span class='warning'>The clamp will not secure the catalyst while the machine is down!</span>")
return
var/obj/item/weapon/reagent_containers/RC = W
@@ -223,7 +265,6 @@
data["panel_open"] = panel_open
data["use_catalyst"] = use_catalyst
// Queue and recipe lists might not be formatted correctly here. Delete this once you've confirmed.
var/list/tmp_queue = list()
for(var/i = 1, i <= queue.len, i++)
tmp_queue.Add(list(list("name" = queue[i], "index" = i))) // Thanks byond
@@ -263,7 +304,6 @@
chemicals.Add(list(list("title" = label, "id" = label, "amount" = C.reagents.total_volume))) // list in a list because Byond merges the first list
data["chemicals"] = chemicals
debug_data = data
return data
/obj/machinery/chemical_synthesizer/tgui_act(action, params)
@@ -297,6 +337,7 @@
if(!busy && catalyst)
catalyst.forceMove(get_turf(src))
catalyst = null
update_icon()
if("toggle_catalyst")
// Decides if the machine uses the catalyst.
if(!busy)
@@ -471,6 +512,7 @@
catalyst.reagents.trans_to_holder(src.reagents, catalyst.reagents.total_volume)
// Start the first recipe in the queue, starting with step 1.
update_icon()
follow_recipe(queue[1], 1)
@@ -480,7 +522,6 @@
stall()
return
icon_state = "synth_working"
if(!step)
step = 1
@@ -519,13 +560,13 @@
// After all this mess of code, we reach the line where the magic happens.
C.reagents.trans_to_holder(src.reagents, quantity)
// playsound(src, 'sound/machinery/HPLC_binary_pump.ogg', 25, 1)
update_icon() // Update underlays.
playsound(src, 'modular_chomp/sound/machines/HPLC_binary_pump.ogg', 15, 1)
// Advance to the next step in the recipe. If this is outside of the recipe's index, we're finished. Otherwise, proceed to next step.
step += 2
var/list/tmp = recipes[r_id]
if(step > tmp.len)
icon_state = "synth_finished"
// First extract the catalyst(s), if any remain.
if(use_catalyst)
@@ -536,6 +577,8 @@
// Add a delay of 1 tick per unit of reagent. Clear the catalyst_ids.
catalyst_ids = list()
var/delay = reagents.total_volume
update_icon() // Update the icon first to remove underlays, then switch to the new icon_state.
icon_state = "synth_finished"
addtimer(CALLBACK(src, .proc/bottle_product, r_id), delay)
else
@@ -569,6 +612,7 @@
for(var/datum/reagent/chem in catalyst.reagents.reagent_list)
catalyst_ids += chem.id
catalyst.reagents.trans_to_holder(src.reagents, catalyst.reagents.total_volume)
update_icon()
follow_recipe(queue[1], 1)
else

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

View File

@@ -1,18 +1,14 @@
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Box, Button, Flex, LabeledList, Section } from "../components";
import { Window } from "../layouts";
import { useBackend } from '../backend';
import { Box, Button, Flex, LabeledList, Section } from '../components';
import { Window } from '../layouts';
import { BeakerContents } from './common/BeakerContents';
export const ChemSynthesizer = (props, context) => {
return (
<Window
width={1100}
height={640}
resizable>
<Window width={1100} height={640} resizable>
<Window.Content>
<Flex
height="100%">
<Flex height="100%">
<Flex.Item grow={1} maxWidth="33%">
<ChemSynthesizerQueueRecipes />
</Flex.Item>
@@ -30,23 +26,11 @@ export const ChemSynthesizer = (props, context) => {
const ChemSynthesizerQueueRecipes = (props, context) => {
const { act, data } = useBackend(context);
const {
busy,
use_catalyst,
queue = [],
recipes = [],
production_mode,
} = data;
const { busy, use_catalyst, queue = [], recipes = [], production_mode } = data;
return (
<Flex
height="100%"
width="100%"
direction="column">
<Flex.Item
maxHeight="50%"
grow={1}
basis={0}>
<Flex height="100%" width="100%" direction="column">
<Flex.Item maxHeight="50%" grow={1} basis={0}>
<Section
height="100%"
title="Queue"
@@ -55,35 +39,33 @@ const ChemSynthesizerQueueRecipes = (props, context) => {
<Fragment>
<Button
disabled={!!busy}
color={use_catalyst ? "green" : "bad"}
color={use_catalyst ? 'green' : 'bad'}
icon="wrench"
tooltip="Enable/Disable the catalyst BEFORE starting the queue."
content={use_catalyst ? "Catalyst Active" : "Catalyst Disabled"}
onClick={() => act("toggle_catalyst")} />
content={use_catalyst ? 'Catalyst Active' : 'Catalyst Disabled'}
onClick={() => act('toggle_catalyst')}
/>
<Button.Confirm
disabled={!queue.length}
color="bad"
icon="minus-circle"
tooltip="Clear Queue"
onClick={() => act("clear_queue")} />
{(!busy && (
<Button
disabled={!queue.length}
icon="play"
tooltip="Start Queue"
onClick={() => act("start_queue")} />
))}
onClick={() => act('clear_queue')}
/>
{!busy && (
<Button disabled={!queue.length} icon="play" tooltip="Start Queue" onClick={() => act('start_queue')} />
)}
</Fragment>
}>
<LabeledList>
{(queue.length && queue.map((item) => {
if ((item.index === 1) && !!busy) {
{(queue.length &&
queue.map((item) => {
if (item.index === 1 && !!busy) {
return (
<LabeledList.Item label={item.name} labelColor="bad">
{
<Box>
<Button
disabled icon="trash">
<Button disabled icon="trash">
Delete
</Button>
</Box>
@@ -95,25 +77,20 @@ const ChemSynthesizerQueueRecipes = (props, context) => {
<LabeledList.Item label={item.name}>
<Button
icon="trash"
onClick={() => act("rem_queue", {
onClick={() =>
act('rem_queue', {
q_index: item.index,
})}>
})
}>
Delete
</Button>
</LabeledList.Item>
);
})) || (
<Box m={1}>
Queue Empty.
</Box>
)}
})) || <Box m={1}>Queue Empty.</Box>}
</LabeledList>
</Section>
</Flex.Item>
<Flex.Item
maxHeight="50%"
grow={1}
basis={0}>
<Flex.Item maxHeight="50%" grow={1} basis={0}>
<Section
height="100%"
title="Recipes"
@@ -121,40 +98,47 @@ const ChemSynthesizerQueueRecipes = (props, context) => {
buttons={
<Button
icon="plus"
tooltip={production_mode ? "Import Recipe" : "Generate Recipe"}
onClick={() => act("add_recipe")} />
tooltip={production_mode ? 'Import Recipe' : 'Generate Recipe'}
onClick={() => act('add_recipe')}
/>
}>
<LabeledList>
{(recipes.length && recipes.map((item) => {
{(recipes.length &&
recipes.map((item) => {
return (
<LabeledList.Item label={item.name}>
<Button
icon="plus"
tooltip="Add to Queue"
onClick={() => act("add_queue", {
onClick={() =>
act('add_queue', {
qa_index: item.name,
})} />
})
}
/>
<Button
icon="inbox"
tooltip="Export Recipe"
onClick={() => act("exp_recipe", {
onClick={() =>
act('exp_recipe', {
exp_index: item.name,
})} />
})
}
/>
<Button
color="bad"
icon="minus-circle"
tooltip="Delete Recipe"
disabled={!!busy}
onClick={() => act("rem_recipe", {
onClick={() =>
act('rem_recipe', {
rm_index: item.name,
})} />
})
}
/>
</LabeledList.Item>
);
})) || (
<Box m={1}>
No recipes found.
</Box>
)}
})) || <Box m={1}>No recipes found.</Box>}
</LabeledList>
</Section>
</Flex.Item>
@@ -179,16 +163,9 @@ const ChemSynthesizerChemicals = (props, context) => {
flexFillers.push(true);
}
return (
<Flex
direction="column">
<Section
title="Cartridge Reagents"
flexGrow="1">
<Flex
direction="row"
wrap="wrap"
height="100%"
align="flex-start">
<Flex direction="column">
<Section title="Cartridge Reagents" flexGrow="1">
<Flex direction="row" wrap="wrap" height="100%" align="flex-start">
{chemicals.map((c, i) => (
<Flex.Item key={i} grow="1" m={0.2} basis="40%" height="20px">
<Button
@@ -206,44 +183,28 @@ const ChemSynthesizerChemicals = (props, context) => {
))}
</Flex>
</Section>
<Section
title="Reaction Vessel">
{(rxn_vessel.length > 0)
? (
<BeakerContents
beakerLoaded
beakerContents={rxn_vessel}
/>
)
: (
<Box color="label">
Vessel is empty.
</Box>
<Section title="Reaction Vessel">
{rxn_vessel.length > 0 ? (
<BeakerContents beakerLoaded beakerContents={rxn_vessel} />
) : (
<Box color="label">Vessel is empty.</Box>
)}
</Section>
<Section
title="Catalyst"
flex="content"
minHeight="25%"
buttons={(
buttons={
<Box>
{!!catalyst && (
<Box inline color="label" mr={2}>
{catalystCurrentVolume} / {catalystMaxVolume} units
</Box>
)}
<Button
icon="eject"
content="Eject"
disabled={!catalyst || !!busy}
onClick={() => act("eject_catalyst")}
/>
<Button icon="eject" content="Eject" disabled={!catalyst || !!busy} onClick={() => act('eject_catalyst')} />
</Box>
)}>
<BeakerContents
beakerLoaded={catalyst}
beakerContents={catalyst_reagents}
/>
}>
<BeakerContents beakerLoaded={catalyst} beakerContents={catalyst_reagents} />
</Section>
</Flex>
);
@@ -251,52 +212,41 @@ const ChemSynthesizerChemicals = (props, context) => {
const ChemSynthesizerSettings = (props, context) => {
const { act, data } = useBackend(context);
const {
busy,
production_mode,
panel_open,
rxn_vessel,
} = data;
const { busy, production_mode, panel_open, rxn_vessel } = data;
return (
<Flex
height="100%"
width="100%"
direction="column">
<Flex.Item
height={0}
grow={1}>
<Section
height="100%"
title="Settings"
overflowY="auto">
<Flex
direction="column">
<Flex height="100%" width="100%" direction="column">
<Flex.Item height={0} grow={1}>
<Section height="100%" title="Settings" overflowY="auto">
<Flex direction="column">
<Flex.Item>
<Button
color={production_mode ? "green" : "bad"}
color={production_mode ? 'green' : 'bad'}
icon="wrench"
content={production_mode ? "Recipe mode: Import" : "Recipe mode: Tutorial"}
onClick={() => act("mode_toggle")} />
content={production_mode ? 'Recipe mode: Import' : 'Recipe mode: Tutorial'}
onClick={() => act('mode_toggle')}
/>
</Flex.Item>
<Flex.Item>
<Button
disabled={!!busy}
color={panel_open ? "bad" : "green"}
color={panel_open ? 'bad' : 'green'}
icon="wrench"
content={panel_open ? "Panel Open" : "Panel Closed"}
onClick={() => act("panel_toggle")} />
content={panel_open ? 'Panel Open' : 'Panel Closed'}
onClick={() => act('panel_toggle')}
/>
</Flex.Item>
<Flex.Item>
{(!busy && (
{!busy && (
<Button
disabled={!rxn_vessel.length}
color="bad"
icon="flask"
tooltip="For emptying the reaction vessel if the machine stalls."
content="Bottle Manually"
onClick={() => act("bottle_product")} />
))}
onClick={() => act('bottle_product')}
/>
)}
</Flex.Item>
<Flex.Item>
<Button
@@ -304,7 +254,8 @@ const ChemSynthesizerSettings = (props, context) => {
color="bad"
icon="minus-circle"
content="EMERGENCY STOP"
onClick={() => act("emergency_stop")} />
onClick={() => act('emergency_stop')}
/>
</Flex.Item>
</Flex>
</Section>

File diff suppressed because one or more lines are too long