mirror of
https://github.com/SPLURT-Station/S.P.L.U.R.T-Station-13.git
synced 2025-12-11 10:22:13 +00:00
Ready for testmerge
This commit is contained in:
@@ -1,9 +1,11 @@
|
|||||||
/*
|
/*
|
||||||
Asset cache quick users guide:
|
Asset cache quick users guide:
|
||||||
|
|
||||||
Make a datum at the bottom of this file with your assets for your thing.
|
Make a datum at the bottom of this file with your assets for your thing.
|
||||||
The simple subsystem will most like be of use for most cases.
|
The simple subsystem will most like be of use for most cases.
|
||||||
Then call get_asset_datum() with the type of the datum you created and store the return
|
Then call get_asset_datum() with the type of the datum you created and store the return
|
||||||
Then call .send(client) on that stored return value.
|
Then call .send(client) on that stored return value.
|
||||||
|
|
||||||
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
You can set verify to TRUE if you want send() to sleep until the client has the assets.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
|||||||
|
|
||||||
//This proc sends the asset to the client, but only if it needs it.
|
//This proc sends the asset to the client, but only if it needs it.
|
||||||
//This proc blocks(sleeps) unless verify is set to false
|
//This proc blocks(sleeps) unless verify is set to false
|
||||||
/proc/send_asset(var/client/client, var/asset_name, var/verify = TRUE)
|
/proc/send_asset(client/client, asset_name, verify = TRUE)
|
||||||
if(!istype(client))
|
if(!istype(client))
|
||||||
if(ismob(client))
|
if(ismob(client))
|
||||||
var/mob/M = client
|
var/mob/M = client
|
||||||
@@ -70,7 +72,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
|||||||
return 1
|
return 1
|
||||||
|
|
||||||
//This proc blocks(sleeps) unless verify is set to false
|
//This proc blocks(sleeps) unless verify is set to false
|
||||||
/proc/send_asset_list(var/client/client, var/list/asset_list, var/verify = TRUE)
|
/proc/send_asset_list(client/client, list/asset_list, verify = TRUE)
|
||||||
if(!istype(client))
|
if(!istype(client))
|
||||||
if(ismob(client))
|
if(ismob(client))
|
||||||
var/mob/M = client
|
var/mob/M = client
|
||||||
@@ -120,7 +122,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
|||||||
|
|
||||||
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
//This proc will download the files without clogging up the browse() queue, used for passively sending files on connection start.
|
||||||
//The proc calls procs that sleep for long times.
|
//The proc calls procs that sleep for long times.
|
||||||
/proc/getFilesSlow(var/client/client, var/list/files, var/register_asset = TRUE)
|
/proc/getFilesSlow(client/client, list/files, register_asset = TRUE)
|
||||||
var/concurrent_tracker = 1
|
var/concurrent_tracker = 1
|
||||||
for(var/file in files)
|
for(var/file in files)
|
||||||
if (!client)
|
if (!client)
|
||||||
@@ -138,13 +140,13 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
|||||||
|
|
||||||
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
//This proc "registers" an asset, it adds it to the cache for further use, you cannot touch it from this point on or you'll fuck things up.
|
||||||
//if it's an icon or something be careful, you'll have to copy it before further use.
|
//if it's an icon or something be careful, you'll have to copy it before further use.
|
||||||
/proc/register_asset(var/asset_name, var/asset)
|
/proc/register_asset(asset_name, asset)
|
||||||
SSassets.cache[asset_name] = asset
|
SSassets.cache[asset_name] = asset
|
||||||
|
|
||||||
//Generated names do not include file extention.
|
//Generated names do not include file extention.
|
||||||
//Used mainly for code that deals with assets in a generic way
|
//Used mainly for code that deals with assets in a generic way
|
||||||
//The same asset will always lead to the same asset name
|
//The same asset will always lead to the same asset name
|
||||||
/proc/generate_asset_name(var/file)
|
/proc/generate_asset_name(file)
|
||||||
return "asset.[md5(fcopy_rsc(file))]"
|
return "asset.[md5(fcopy_rsc(file))]"
|
||||||
|
|
||||||
|
|
||||||
@@ -154,7 +156,7 @@ You can set verify to TRUE if you want send() to sleep until the client has the
|
|||||||
GLOBAL_LIST_EMPTY(asset_datums)
|
GLOBAL_LIST_EMPTY(asset_datums)
|
||||||
|
|
||||||
//get an assetdatum or make a new one
|
//get an assetdatum or make a new one
|
||||||
/proc/get_asset_datum(var/type)
|
/proc/get_asset_datum(type)
|
||||||
return GLOB.asset_datums[type] || new type()
|
return GLOB.asset_datums[type] || new type()
|
||||||
|
|
||||||
/datum/asset
|
/datum/asset
|
||||||
@@ -321,6 +323,13 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
|||||||
var/size_id = sprite[SPR_SIZE]
|
var/size_id = sprite[SPR_SIZE]
|
||||||
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
return {"<span class="[name][size_id] [sprite_name]"></span>"}
|
||||||
|
|
||||||
|
/datum/asset/spritesheet/proc/icon_class_name(sprite_name)
|
||||||
|
var/sprite = sprites[sprite_name]
|
||||||
|
if (!sprite)
|
||||||
|
return null
|
||||||
|
var/size_id = sprite[SPR_SIZE]
|
||||||
|
return {"[name][size_id] [sprite_name]"}
|
||||||
|
|
||||||
#undef SPR_SIZE
|
#undef SPR_SIZE
|
||||||
#undef SPR_IDX
|
#undef SPR_IDX
|
||||||
#undef SPRSZ_COUNT
|
#undef SPRSZ_COUNT
|
||||||
@@ -388,7 +397,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
|||||||
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
|
"shim-html5shiv.js" = 'tgui-next/packages/tgui/public/shim-html5shiv.js',
|
||||||
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
|
"shim-ie8.js" = 'tgui-next/packages/tgui/public/shim-ie8.js',
|
||||||
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
|
"shim-dom4.js" = 'tgui-next/packages/tgui/public/shim-dom4.js',
|
||||||
"shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js'
|
"shim-css-om.js" = 'tgui-next/packages/tgui/public/shim-css-om.js',
|
||||||
)
|
)
|
||||||
|
|
||||||
/datum/asset/group/tgui
|
/datum/asset/group/tgui
|
||||||
@@ -519,7 +528,7 @@ GLOBAL_LIST_EMPTY(asset_datums)
|
|||||||
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
"pill21" = 'icons/UI_Icons/Pills/pill21.png',
|
||||||
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
"pill22" = 'icons/UI_Icons/Pills/pill22.png',
|
||||||
)
|
)
|
||||||
|
|
||||||
/datum/asset/simple/IRV
|
/datum/asset/simple/IRV
|
||||||
assets = list(
|
assets = list(
|
||||||
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
|
"jquery-ui.custom-core-widgit-mouse-sortable-min.js" = 'html/IRV/jquery-ui.custom-core-widgit-mouse-sortable-min.js',
|
||||||
|
|||||||
@@ -8,7 +8,6 @@
|
|||||||
<link rel="stylesheet" type="text/css" href="browserOutput.css" />
|
<link rel="stylesheet" type="text/css" href="browserOutput.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="spritesheet_chat.css" />
|
<link rel="stylesheet" type="text/css" href="spritesheet_chat.css" />
|
||||||
<link rel="stylesheet" type="text/css" id="colorPresetLink"/>
|
<link rel="stylesheet" type="text/css" id="colorPresetLink"/>
|
||||||
<script type="text/javascript" src="errorHandler.js"></script>
|
|
||||||
<script type="text/javascript" src="jquery.min.js"></script>
|
<script type="text/javascript" src="jquery.min.js"></script>
|
||||||
<script type="text/javascript" src="json2.min.js"></script>
|
<script type="text/javascript" src="json2.min.js"></script>
|
||||||
</head>
|
</head>
|
||||||
@@ -56,4 +55,4 @@
|
|||||||
<audio class="hidden" id="adminMusic" autoplay></audio>
|
<audio class="hidden" id="adminMusic" autoplay></audio>
|
||||||
<script type="text/javascript" src="browserOutput.js"></script>
|
<script type="text/javascript" src="browserOutput.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -6,7 +6,6 @@
|
|||||||
******************************************/
|
******************************************/
|
||||||
|
|
||||||
//DEBUG STUFF
|
//DEBUG STUFF
|
||||||
var triggerError = attachErrorHandler('chatDebug', true);
|
|
||||||
var escaper = encodeURIComponent || escape;
|
var escaper = encodeURIComponent || escape;
|
||||||
var decoder = decodeURIComponent || unescape;
|
var decoder = decodeURIComponent || unescape;
|
||||||
window.onerror = function(msg, url, line, col, error) {
|
window.onerror = function(msg, url, line, col, error) {
|
||||||
|
|||||||
@@ -1,34 +0,0 @@
|
|||||||
(function(window, navigator) {
|
|
||||||
|
|
||||||
var escaper = encodeURIComponent || escape;
|
|
||||||
|
|
||||||
var triggerError = function(msg, url, line, col, error) {
|
|
||||||
window.onerror(msg, url, line, col, error);
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Directs JS errors to a byond proc for logging
|
|
||||||
*
|
|
||||||
* @param string file Name of the logfile to dump errors in, do not prepend with data/
|
|
||||||
* @param boolean overrideDefault True to prevent default JS errors (an big honking error prompt thing)
|
|
||||||
* @return boolean
|
|
||||||
*/
|
|
||||||
var attach = function(file, overrideDefault) {
|
|
||||||
overrideDefault = typeof overrideDefault === 'undefined' ? false : overrideDefault;
|
|
||||||
file = escaper(file);
|
|
||||||
|
|
||||||
window.onerror = function(msg, url, line, col, error) {
|
|
||||||
var extra = !col ? '' : ' | column: ' + col;
|
|
||||||
extra += !error ? '' : ' | error: ' + error;
|
|
||||||
extra += !navigator.userAgent ? '' : ' | user agent: ' + navigator.userAgent;
|
|
||||||
var debugLine = 'Error: ' + msg + ' | url: ' + url + ' | line: ' + line + extra;
|
|
||||||
window.location = '?action=debugFileOutput&file=' + file + '&message=' + escaper(debugLine);
|
|
||||||
return overrideDefault;
|
|
||||||
};
|
|
||||||
|
|
||||||
return triggerError;
|
|
||||||
};
|
|
||||||
|
|
||||||
window.attachErrorHandler = attach;
|
|
||||||
|
|
||||||
}(window, window.navigator));
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
/**
|
|
||||||
* This is a generic handler for logging your dumb JS errors generated by html popups
|
|
||||||
*
|
|
||||||
* 1. Add your logfile to the validFiles list
|
|
||||||
* 2. Include the "browserassets/js/errorHandler.js" file in your html file (if using chui, skip this step) (look at browserOutput.html for an example)
|
|
||||||
* 3. Call attachErrorHandler('yourLogFile'); at the top of your JS (again see browserOutput.js for an example)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/datum/debugFileOutput
|
|
||||||
var/directory = "data/popupErrors" //where to shove all the logfiles
|
|
||||||
var/ext = "log" //file extension
|
|
||||||
var/logFileLimit = 52428800 //50mb, so yeah pretty permissive
|
|
||||||
|
|
||||||
//Add your dumb file here. This is so some schmuck can't just shit out a bunch of spam logfiles and use all the diskspace. Relative to src.directory
|
|
||||||
var/list/validFiles = list(
|
|
||||||
"chatDebug",
|
|
||||||
"tooltipDebug",
|
|
||||||
"chemDispenser",
|
|
||||||
"banPanel",
|
|
||||||
"stationNamer"
|
|
||||||
)
|
|
||||||
|
|
||||||
/datum/debugFileOutput/proc/error(fileName, message, client/C)
|
|
||||||
if (!fileName || !message)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if (!(fileName in src.validFiles))
|
|
||||||
throw EXCEPTION("Debug log file '[fileName].[src.ext]' is not a valid path.")
|
|
||||||
|
|
||||||
var/logFile = file("[src.directory]/[fileName].[src.ext]")
|
|
||||||
var/fileSize = length(logFile)
|
|
||||||
if (fileSize >= src.logFileLimit)
|
|
||||||
CRASH("Debug Error Handling encountered an error! This is highly ironic! File: '[fileName]' has exceeded the filesize limit of: [src.logFileLimit] bytes")
|
|
||||||
|
|
||||||
message = "\[[time2text(world.realtime, "YYYY-MM-DD hh:mm:ss")]\] Client: \[[C && C.key ? C.key : "Unknown Client"]\] triggered: [message]"
|
|
||||||
WRITE_FILE(logFile, message)
|
|
||||||
return 1
|
|
||||||
|
|
||||||
/datum/debugFileOutput/proc/clear(fileName)
|
|
||||||
if (!fileName)
|
|
||||||
return 0
|
|
||||||
|
|
||||||
if (!fexists("[src.directory]/[fileName].[src.ext]"))
|
|
||||||
throw EXCEPTION("Debug log file '[fileName].[src.ext]' does not exist.")
|
|
||||||
|
|
||||||
if (!(fileName in src.validFiles))
|
|
||||||
throw EXCEPTION("Debug log file '[fileName].[src.ext]' is not a valid path.")
|
|
||||||
|
|
||||||
fdel("[src.directory]/[fileName].[src.ext]")
|
|
||||||
return 1
|
|
||||||
|
|
||||||
/datum/debugFileOutput/proc/clearAll()
|
|
||||||
var/list/deleted = new()
|
|
||||||
for (var/fileName in src.validFiles)
|
|
||||||
if (fexists("[src.directory]/[fileName].[src.ext]"))
|
|
||||||
fdel("[src.directory]/[fileName].[src.ext]")
|
|
||||||
deleted += fileName
|
|
||||||
|
|
||||||
return deleted
|
|
||||||
|
|
||||||
|
|
||||||
GLOBAL_DATUM_INIT(debugFileOutput, /datum/debugFileOutput, new)
|
|
||||||
|
|
||||||
/client/Topic(href, href_list)
|
|
||||||
..()
|
|
||||||
|
|
||||||
if (href_list["action"] && href_list["action"] == "debugFileOutput" && href_list["file"] && href_list["message"])
|
|
||||||
var/file = href_list["file"]
|
|
||||||
var/message = href_list["message"]
|
|
||||||
GLOB.debugFileOutput.error(file, message, src)
|
|
||||||
|
|
||||||
/client/proc/deleteJsLogFile(fileName as text)
|
|
||||||
set category = "Debug"
|
|
||||||
set name = "Delete JS Logfile"
|
|
||||||
set desc = "Delete a logfile for JS error reporting. Be sure you want to do this!"
|
|
||||||
set popup_menu = 0
|
|
||||||
if(!holder)
|
|
||||||
return
|
|
||||||
if (!fileName)
|
|
||||||
return
|
|
||||||
|
|
||||||
GLOB.debugFileOutput.clear(fileName)
|
|
||||||
|
|
||||||
log_admin("[key_name(usr)] deleted the '[fileName]' JS logfile")
|
|
||||||
message_admins("[key_name_admin(usr)] deleted the '[fileName]' JS logfile")
|
|
||||||
|
|
||||||
/client/proc/deleteAllJsLogFiles()
|
|
||||||
set category = null
|
|
||||||
set name = "Delete All JS Logfiles"
|
|
||||||
set desc = "Delete all logfiles for JS error reporting. Be extra sure you want to do this!"
|
|
||||||
|
|
||||||
if(!holder)
|
|
||||||
return
|
|
||||||
|
|
||||||
if (alert("Are you really sure you want to delete every single JS logfile?", "No", "Yes") == "No")
|
|
||||||
return
|
|
||||||
|
|
||||||
var/list/summary = GLOB.debugFileOutput.clearAll()
|
|
||||||
var/friendlySummary = summary.Join(", ")
|
|
||||||
|
|
||||||
log_admin("[key_name(usr)] deleted every JS logfile! ([friendlySummary])")
|
|
||||||
message_admins("[key_name_admin(usr)] deleted every JS logfile! ([friendlySummary])")
|
|
||||||
6393
tgstation.dme
6393
tgstation.dme
File diff suppressed because it is too large
Load Diff
@@ -1,180 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -1,367 +0,0 @@
|
|||||||
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;
|
|
||||||
if (screen === 'analyze') {
|
|
||||||
return <AnalysisResults state={state} />;
|
|
||||||
}
|
|
||||||
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>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const AnalysisResults = props => {
|
|
||||||
const { state } = 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',
|
|
||||||
})} />
|
|
||||||
)}>
|
|
||||||
<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>
|
|
||||||
</Section>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
Reference in New Issue
Block a user