mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 04:27:35 +01:00
TGUI Medical: Cryo Cell
This commit is contained in:
+46
-68
@@ -103,7 +103,7 @@
|
||||
beaker.forceMove(drop_location())
|
||||
beaker = null
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O as mob|obj, mob/living/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/MouseDrop_T(atom/movable/O, mob/living/user)
|
||||
if(O.loc == user) //no you can't pull things out of your ass
|
||||
return
|
||||
if(user.incapacitated()) //are you cuffed, dying, lying, stunned or other
|
||||
@@ -140,6 +140,7 @@
|
||||
add_attack_logs(user, L, "put into a cryo cell at [COORD(src)].", ATKLOG_ALL)
|
||||
if(user.pulling == L)
|
||||
user.stop_pulling()
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/process()
|
||||
..()
|
||||
@@ -177,7 +178,7 @@
|
||||
return FALSE
|
||||
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/relaymove(mob/user)
|
||||
if(user.stat)
|
||||
return
|
||||
go_out()
|
||||
@@ -194,36 +195,18 @@
|
||||
to_chat(usr, "<span class='boldnotice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
|
||||
/**
|
||||
* The ui_interact proc is used to open and update Nano UIs
|
||||
* If ui_interact is not used then the UI will not update correctly
|
||||
* ui_interact is currently defined for /atom/movable (which is inherited by /obj and /mob)
|
||||
*
|
||||
* @param user /mob The mob who is interacting with this ui
|
||||
* @param ui_key string A string key to use for this ui. Allows for multiple unique uis on one obj/mob (defaut value "main")
|
||||
* @param ui /datum/nanoui This parameter is passed by the nanoui process() proc when updating an open ui
|
||||
*
|
||||
* @return nothing
|
||||
*/
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_interact(mob/user, ui_key = "main", var/datum/nanoui/ui = null, var/force_open = 1)
|
||||
// update the ui if it exists, returns null if no ui is passed/found
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, datum/tgui/master_ui = null, datum/tgui_state/state = GLOB.tgui_default_state)
|
||||
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
if(!ui)
|
||||
// the ui does not exist, so we'll create a new() one
|
||||
// for a list of parameters and their descriptions see the code docs in \code\modules\nano\nanoui.dm
|
||||
ui = new(user, src, ui_key, "cryo.tmpl", "Cryo Cell Control System", 520, 480)
|
||||
// open the new ui window
|
||||
ui = new(user, src, ui_key, "Cryo", "Cryo Cell Control System", 520, 470)
|
||||
ui.open()
|
||||
// auto update every Master Controller tick
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/ui_data(mob/user, ui_key = "main", datum/topic_state/state = GLOB.default_state)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
data["isOperating"] = on
|
||||
data["hasOccupant"] = occupant ? 1 : 0
|
||||
data["hasOccupant"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -237,7 +220,7 @@
|
||||
occupantData["toxLoss"] = occupant.getToxLoss()
|
||||
occupantData["fireLoss"] = occupant.getFireLoss()
|
||||
occupantData["bodyTemperature"] = occupant.bodytemperature
|
||||
data["occupant"] = occupantData;
|
||||
data["occupant"] = occupantData
|
||||
|
||||
data["cellTemperature"] = round(air_contents.temperature)
|
||||
data["cellTemperatureStatus"] = "good"
|
||||
@@ -246,7 +229,7 @@
|
||||
else if(air_contents.temperature > TCRYO)
|
||||
data["cellTemperatureStatus"] = "average"
|
||||
|
||||
data["isBeakerLoaded"] = beaker ? 1 : 0
|
||||
data["isBeakerLoaded"] = beaker ? TRUE : FALSE
|
||||
data["beakerLabel"] = null
|
||||
data["beakerVolume"] = 0
|
||||
if(beaker)
|
||||
@@ -259,48 +242,41 @@
|
||||
data["auto_eject_dead"] = (auto_eject_prefs & AUTO_EJECT_DEAD) ? TRUE : FALSE
|
||||
return data
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/Topic(href, href_list)
|
||||
if(usr == occupant)
|
||||
return 0 // don't update UIs attached to this object
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/tgui_act(action, params)
|
||||
if(..() || usr == occupant)
|
||||
return
|
||||
|
||||
if(..())
|
||||
return 0 // don't update UIs attached to this object
|
||||
|
||||
if(href_list["switchOn"])
|
||||
on = TRUE
|
||||
update_icon()
|
||||
|
||||
if(href_list["switchOff"])
|
||||
on = FALSE
|
||||
update_icon()
|
||||
|
||||
if(href_list["auto_eject_healthy_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_healthy_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
|
||||
if(href_list["auto_eject_dead_on"])
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["auto_eject_dead_off"])
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
|
||||
if(href_list["ejectBeaker"])
|
||||
if(beaker)
|
||||
beaker.forceMove(get_step(loc, SOUTH))
|
||||
beaker = null
|
||||
|
||||
if(href_list["ejectOccupant"])
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return 0 // don't update UIs attached to this object
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
switch(action)
|
||||
if("switchOn")
|
||||
on = TRUE
|
||||
update_icon()
|
||||
if("switchOff")
|
||||
on = FALSE
|
||||
update_icon()
|
||||
if("auto_eject_healthy_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_healthy_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_HEALTHY
|
||||
if("auto_eject_dead_on")
|
||||
auto_eject_prefs |= AUTO_EJECT_DEAD
|
||||
if("auto_eject_dead_off")
|
||||
auto_eject_prefs &= ~AUTO_EJECT_DEAD
|
||||
if("ejectBeaker")
|
||||
if(beaker)
|
||||
beaker.forceMove(get_step(loc, SOUTH))
|
||||
beaker = null
|
||||
if("ejectOccupant")
|
||||
if(!occupant || isslime(usr) || ispAI(usr))
|
||||
return
|
||||
add_attack_logs(usr, occupant, "ejected from cryo cell at [COORD(src)]", ATKLOG_ALL)
|
||||
go_out()
|
||||
else
|
||||
return
|
||||
|
||||
add_fingerprint(usr)
|
||||
return 1 // update UIs attached to this object
|
||||
return TRUE // update UIs attached to this object
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G as obj, var/mob/user as mob, params)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/attackby(var/obj/item/G, var/mob/user, params)
|
||||
if(istype(G, /obj/item/reagent_containers/glass))
|
||||
var/obj/item/reagent_containers/B = G
|
||||
if(beaker)
|
||||
@@ -313,6 +289,7 @@
|
||||
beaker = B
|
||||
add_attack_logs(user, null, "Added [B] containing [B.reagents.log_list()] to a cryo cell at [COORD(src)]")
|
||||
user.visible_message("[user] adds \a [B] to [src]!", "You add \a [B] to [src]!")
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
if(exchange_parts(user, G))
|
||||
@@ -452,8 +429,9 @@
|
||||
playsound(loc, 'sound/machines/ding.ogg', 50, 1)
|
||||
if(AUTO_EJECT_DEAD)
|
||||
playsound(loc, 'sound/machines/buzz-sigh.ogg', 40)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M as mob)
|
||||
/obj/machinery/atmospherics/unary/cryo_cell/proc/put_mob(mob/living/carbon/M)
|
||||
if(!istype(M))
|
||||
to_chat(usr, "<span class='danger'>The cryo cell cannot handle such a lifeform!</span>")
|
||||
return
|
||||
@@ -527,7 +505,7 @@
|
||||
/datum/data/function/proc/reset()
|
||||
return
|
||||
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user as mob)
|
||||
/datum/data/function/proc/r_input(href, href_list, mob/user)
|
||||
return
|
||||
|
||||
/datum/data/function/proc/display()
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
<!--
|
||||
Title: Cryo Cell Status UI
|
||||
Used In File(s): \code\game\machinery\cryo.dm
|
||||
-->
|
||||
<h3>Cryo Cell Status</h3>
|
||||
|
||||
<div class="statusDisplay">
|
||||
{{if !data.hasOccupant}}
|
||||
<div class="line">Cell Unoccupied</div>
|
||||
{{else}}
|
||||
<div class="line">
|
||||
{{:data.occupant.name}} <i class="fa fa-arrow-right"></i>
|
||||
{{if data.occupant.stat == 0}}
|
||||
<span class="good">Conscious</span>
|
||||
{{else data.occupant.stat == 1}}
|
||||
<span class="average">Unconscious</span>
|
||||
{{else}}
|
||||
<span class="bad">DEAD</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
{{if data.occupant.stat < 2}}
|
||||
<div class="line">
|
||||
<div class="statusLabel">Health:</div>
|
||||
{{if data.occupant.health >= 0}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.maxHealth, 'good')}}
|
||||
{{else}}
|
||||
{{:helper.displayBar(data.occupant.health, 0, data.occupant.minHealth, 'average alignRight')}}
|
||||
{{/if}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.health)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Brute Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.bruteLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Resp. Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.oxyLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Toxin Damage:</div>
|
||||
{{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.toxLoss)}}</div>
|
||||
</div>
|
||||
|
||||
<div class="line">
|
||||
<div class="statusLabel"><i class="fa fa-arrow-right"></i> Burn Severity:</div>
|
||||
{{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth, 'bad')}}
|
||||
<div class="statusValue">{{:helper.smoothRound(data.occupant.fireLoss)}}</div>
|
||||
</div>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
<br>
|
||||
<hr>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Cell Temperature:</div><div class="statusValue">
|
||||
<span class="{{:data.cellTemperatureStatus}}">{{:helper.smoothRound(data.cellTemperature)}} K</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<h3>Cryo Cell Operation</h3>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Cryo Cell Status:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{:helper.link('On', 'power-off', {'switchOn' : 1}, data.isOperating ? 'selected' : null)}}{{:helper.link('Off', 'close', {'switchOff' : 1}, data.isOperating ? null : 'selected')}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectOccupant' : 1}, data.hasOccupant ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel">
|
||||
Beaker:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 40%;">
|
||||
{{if data.isBeakerLoaded}}
|
||||
{{:data.beakerLabel ? data.beakerLabel : '<span class="average">No label</span>'}}<br>
|
||||
{{if data.beakerVolume}}
|
||||
<span class="highlight">{{:helper.smoothRound(data.beakerVolume)}} units remaining</span><br>
|
||||
{{else}}
|
||||
<span class="bad">Beaker is empty</span>
|
||||
{{/if}}
|
||||
{{else}}
|
||||
<span class="average"><i>No beaker loaded</i></span>
|
||||
{{/if}}
|
||||
</div>
|
||||
<div class="itemContent" style="width: 26%;">
|
||||
{{:helper.link('Eject Beaker', 'eject', {'ejectBeaker' : 1}, data.isBeakerLoaded ? null : 'disabled')}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item"> </div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject healthy patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_healthy_on' : 1}, data.auto_eject_healthy ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_healthy_off' : 0}, data.auto_eject_healthy ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabel" style="width: 70%">
|
||||
Auto-eject dead patients:
|
||||
</div>
|
||||
<div class="itemContent" style="width: 30%;">
|
||||
{{:helper.link('On', 'power-off', {'auto_eject_dead_on' : 1}, data.auto_eject_dead ? 'selected' : null)}}{{:helper.link('Off', 'close', {'auto_eject_dead_off' : 0}, data.auto_eject_dead ? null : 'selected')}}
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,195 @@
|
||||
import { round, toFixed } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Window } from "../layouts";
|
||||
import { AnimatedNumber, Box, Button, LabeledList, ProgressBar, Section } from "../components";
|
||||
|
||||
const damageTypes = [
|
||||
{
|
||||
label: "Respiratory",
|
||||
type: "oxyLoss",
|
||||
},
|
||||
{
|
||||
label: "Toxin",
|
||||
type: "toxLoss",
|
||||
},
|
||||
{
|
||||
label: "Brute",
|
||||
type: "bruteLoss",
|
||||
},
|
||||
{
|
||||
label: "Burn",
|
||||
type: "fireLoss",
|
||||
},
|
||||
];
|
||||
|
||||
const statNames = [
|
||||
["good", "Conscious"],
|
||||
["average", "Unconscious"],
|
||||
["bad", "DEAD"],
|
||||
];
|
||||
|
||||
export const Cryo = (props, context) => {
|
||||
return (
|
||||
<Window>
|
||||
<Window.Content className="Layout__content--flexColumn">
|
||||
<CryoContent />
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const CryoContent = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isOperating,
|
||||
hasOccupant,
|
||||
occupant = [],
|
||||
cellTemperature,
|
||||
cellTemperatureStatus,
|
||||
isBeakerLoaded,
|
||||
auto_eject_healthy,
|
||||
auto_eject_dead,
|
||||
} = data;
|
||||
return (
|
||||
<Fragment>
|
||||
<Section
|
||||
title="Occupant"
|
||||
flexGrow="1"
|
||||
buttons={(
|
||||
<Button
|
||||
icon="user-slash"
|
||||
onClick={() => act('ejectOccupant')}
|
||||
disabled={!hasOccupant}>
|
||||
Eject
|
||||
</Button>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Occupant">
|
||||
{occupant.name || 'No Occupant'}
|
||||
</LabeledList.Item>
|
||||
{!!hasOccupant && (
|
||||
<Fragment>
|
||||
<LabeledList.Item
|
||||
label="State"
|
||||
color={statNames[occupant.stat][0]}>
|
||||
{statNames[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant.bodyTemperature)} />
|
||||
{' K'}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
value={occupant.health / occupant.maxHealth}
|
||||
color={occupant.health > 0 ? 'good' : 'average'}>
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant.health)} />
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
{(damageTypes.map(damageType => (
|
||||
<LabeledList.Item
|
||||
key={damageType.id}
|
||||
label={damageType.label}>
|
||||
<ProgressBar
|
||||
value={occupant[damageType.type]/100}
|
||||
ranges={{ bad: [0.01, Infinity] }}>
|
||||
<AnimatedNumber
|
||||
value={Math.round(occupant[damageType.type])} />
|
||||
</ProgressBar>
|
||||
</LabeledList.Item>
|
||||
)))}
|
||||
</Fragment>
|
||||
)}
|
||||
</LabeledList>
|
||||
</Section>
|
||||
<Section
|
||||
title="Cell"
|
||||
buttons={(
|
||||
<Button
|
||||
icon="eject"
|
||||
onClick={() => act('ejectBeaker')}
|
||||
disabled={!isBeakerLoaded}>
|
||||
Eject Beaker
|
||||
</Button>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Power">
|
||||
<Button
|
||||
icon="power-off"
|
||||
onClick={() => act(isOperating ? 'switchOff' : 'switchOn')}
|
||||
selected={isOperating}>
|
||||
{isOperating ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature" color={cellTemperatureStatus}>
|
||||
<AnimatedNumber value={cellTemperature} /> K
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Beaker">
|
||||
<CryoBeaker />
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Auto-eject healthy occupants">
|
||||
<Button
|
||||
icon={auto_eject_healthy ? "toggle-on" : "toggle-off"}
|
||||
selected={auto_eject_healthy}
|
||||
mt="1rem"
|
||||
onClick={() => act(auto_eject_healthy
|
||||
? 'auto_eject_healthy_off'
|
||||
: 'auto_eject_healthy_on'
|
||||
)}>
|
||||
{auto_eject_healthy ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Auto-eject dead occupants">
|
||||
<Button
|
||||
icon={auto_eject_dead ? "toggle-on" : "toggle-off"}
|
||||
selected={auto_eject_dead}
|
||||
onClick={() => act(auto_eject_dead
|
||||
? 'auto_eject_dead_off'
|
||||
: 'auto_eject_dead_on'
|
||||
)}>
|
||||
{auto_eject_dead ? "On" : "Off"}
|
||||
</Button>
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
</Fragment>
|
||||
);
|
||||
};
|
||||
|
||||
const CryoBeaker = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
isBeakerLoaded,
|
||||
beakerLabel,
|
||||
beakerVolume,
|
||||
} = data;
|
||||
if (isBeakerLoaded) {
|
||||
return (
|
||||
<Fragment>
|
||||
{beakerLabel
|
||||
? beakerLabel
|
||||
: (
|
||||
<Box color="average">
|
||||
No label
|
||||
</Box>
|
||||
)}
|
||||
<Box color={!beakerVolume && "bad"}>
|
||||
{beakerVolume ? (
|
||||
<AnimatedNumber
|
||||
value={beakerVolume}
|
||||
format={v => Math.round(v) + " units remaining"}
|
||||
/>
|
||||
) : "Beaker is empty"}
|
||||
</Box>
|
||||
</Fragment>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<Box color="average">
|
||||
No beaker loaded
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user