mirror of
https://github.com/ParadiseSS13/Paradise.git
synced 2026-08-24 04:27:35 +01:00
TGUI Medical: Body Scanner
This commit is contained in:
@@ -65,6 +65,7 @@
|
||||
icon_state = "body_scanner_1"
|
||||
add_fingerprint(user)
|
||||
qdel(TYPECAST_YOUR_SHIT)
|
||||
SStgui.update_uis(src)
|
||||
return
|
||||
|
||||
return ..()
|
||||
@@ -127,6 +128,7 @@
|
||||
occupant = H
|
||||
icon_state = "bodyscanner"
|
||||
add_fingerprint(user)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/attack_ai(user)
|
||||
return attack_hand(user)
|
||||
@@ -145,7 +147,7 @@
|
||||
to_chat(user, "<span class='notice'>Close the maintenance panel first.</span>")
|
||||
return
|
||||
|
||||
ui_interact(user)
|
||||
tgui_interact(user)
|
||||
|
||||
/obj/machinery/bodyscanner/relaymove(mob/user)
|
||||
if(user.incapacitated())
|
||||
@@ -171,6 +173,7 @@
|
||||
// eject trash the occupant dropped
|
||||
for(var/atom/movable/A in contents - component_parts)
|
||||
A.forceMove(loc)
|
||||
SStgui.update_uis(src)
|
||||
|
||||
/obj/machinery/bodyscanner/ex_act(severity)
|
||||
if(occupant)
|
||||
@@ -189,17 +192,16 @@
|
||||
new /obj/effect/gibspawner/generic(get_turf(loc)) //I REPLACE YOUR TECHNOLOGY WITH FLESH!
|
||||
qdel(src)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 1)
|
||||
ui = SSnanoui.try_update_ui(user, src, ui_key, ui, force_open)
|
||||
/obj/machinery/bodyscanner/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)
|
||||
ui = new(user, src, ui_key, "adv_med.tmpl", "Body Scanner", 690, 600)
|
||||
ui = new(user, src, ui_key, "BodyScanner", "Body Scanner", 690, 600)
|
||||
ui.open()
|
||||
ui.set_auto_update(1)
|
||||
|
||||
/obj/machinery/bodyscanner/ui_data(mob/user, datum/topic_state/state)
|
||||
/obj/machinery/bodyscanner/tgui_data(mob/user)
|
||||
var/data[0]
|
||||
|
||||
data["occupied"] = occupant ? 1 : 0
|
||||
data["occupied"] = occupant ? TRUE : FALSE
|
||||
|
||||
var/occupantData[0]
|
||||
if(occupant)
|
||||
@@ -233,9 +235,9 @@
|
||||
occupantData["hasBorer"] = occupant.has_brain_worms()
|
||||
|
||||
var/bloodData[0]
|
||||
bloodData["hasBlood"] = 0
|
||||
bloodData["hasBlood"] = FALSE
|
||||
if(!(NO_BLOOD in occupant.dna.species.species_traits))
|
||||
bloodData["hasBlood"] = 1
|
||||
bloodData["hasBlood"] = TRUE
|
||||
bloodData["volume"] = occupant.blood_volume
|
||||
bloodData["percent"] = round(((occupant.blood_volume / BLOOD_VOLUME_NORMAL)*100))
|
||||
bloodData["pulse"] = occupant.get_pulse(GETPULSE_TOOL)
|
||||
@@ -279,19 +281,19 @@
|
||||
if(E.status & ORGAN_BROKEN)
|
||||
organStatus["broken"] = E.broken_description
|
||||
if(E.is_robotic())
|
||||
organStatus["robotic"] = 1
|
||||
organStatus["robotic"] = TRUE
|
||||
if(E.status & ORGAN_SPLINTED)
|
||||
organStatus["splinted"] = 1
|
||||
organStatus["splinted"] = TRUE
|
||||
if(E.status & ORGAN_DEAD)
|
||||
organStatus["dead"] = 1
|
||||
organStatus["dead"] = TRUE
|
||||
|
||||
organData["status"] = organStatus
|
||||
|
||||
if(istype(E, /obj/item/organ/external/chest) && occupant.is_lung_ruptured())
|
||||
organData["lungRuptured"] = 1
|
||||
organData["lungRuptured"] = TRUE
|
||||
|
||||
if(E.internal_bleeding)
|
||||
organData["internalBleeding"] = 1
|
||||
organData["internalBleeding"] = TRUE
|
||||
|
||||
extOrganData.Add(list(organData))
|
||||
|
||||
@@ -316,27 +318,31 @@
|
||||
|
||||
occupantData["blind"] = (BLINDNESS in occupant.mutations)
|
||||
occupantData["colourblind"] = (COLOURBLIND in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
occupantData["nearsighted"] = (NEARSIGHTED in occupant.mutations)
|
||||
|
||||
data["occupant"] = occupantData
|
||||
return data
|
||||
|
||||
/obj/machinery/bodyscanner/Topic(href, href_list)
|
||||
/obj/machinery/bodyscanner/tgui_act(action, params)
|
||||
if(..())
|
||||
return 1
|
||||
return
|
||||
|
||||
if(href_list["ejectify"])
|
||||
eject()
|
||||
|
||||
if(href_list["print_p"])
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, 1)
|
||||
P.info = "<CENTER><B>Body Scan - [href_list["name"]]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [href_list["name"]]"
|
||||
. = TRUE
|
||||
switch(action)
|
||||
if("ejectify")
|
||||
eject()
|
||||
if("print_p")
|
||||
visible_message("<span class='notice'>[src] rattles and prints out a sheet of paper.</span>")
|
||||
var/obj/item/paper/P = new /obj/item/paper(loc)
|
||||
playsound(loc, 'sound/goonstation/machines/printer_dotmatrix.ogg', 50, TRUE)
|
||||
var/name = occupant ? occupant.name : "Unknown"
|
||||
P.info = "<CENTER><B>Body Scan - [name]</B></CENTER><BR>"
|
||||
P.info += "<b>Time of scan:</b> [station_time_timestamp()]<br><br>"
|
||||
P.info += "[generate_printing_text()]"
|
||||
P.info += "<br><br><b>Notes:</b><br>"
|
||||
P.name = "Body Scan - [name]"
|
||||
else
|
||||
return FALSE
|
||||
|
||||
/obj/machinery/bodyscanner/proc/generate_printing_text()
|
||||
var/dat = ""
|
||||
|
||||
@@ -1,231 +0,0 @@
|
||||
<!--
|
||||
Title: Body Scanner UI
|
||||
Used In File(s): \code\game\machinery\adv_med.dm
|
||||
-->
|
||||
|
||||
{{if !data.occupied}}
|
||||
<h3>No occupant detected.</h3>
|
||||
{{else}}
|
||||
<h4><b>Occupant Data:</b></h4>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Name:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:data.occupant.name}}
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Health:
|
||||
</div>
|
||||
{{:helper.displayBar(data.occupant.health, -100, 100, (data.occupant.health >= 50) ? 'good' : (data.occupant.health >= 0) ? 'average' : 'bad')}}
|
||||
<div class="itemContent" style="width: 60px">
|
||||
{{:helper.smoothRound(data.occupant.health)}}%
|
||||
</div>
|
||||
</div>
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Status:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{if data.occupant.stat==0}}
|
||||
<span class="good"> Alive </span>
|
||||
{{else data.occupant.stat==1}}
|
||||
<span class="average"> Critical </span>
|
||||
{{else}}
|
||||
<span class="bad"> Dead </span>
|
||||
{{/if}}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="item">
|
||||
<div class="itemLabelNarrow">
|
||||
Temperature:
|
||||
</div>
|
||||
<div class="itemContent">
|
||||
{{:helper.smoothRound(data.occupant.bodyTempC)}}°C, {{:helper.smoothRound(data.occupant.bodyTempF)}}°F
|
||||
</div>
|
||||
</div>
|
||||
{{if data.occupant.hasBorer}}
|
||||
<span class="bad">
|
||||
Large growth detected in frontal lobe, possibly cancerous. Surgical removal is recommended. </span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.blind}}
|
||||
<span class="average">Cataracts detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.colourblind}}
|
||||
<span class="average">Photoreceptor abnormalities detected.</span><br>
|
||||
{{/if}}
|
||||
{{if data.occupant.nearsighted}}
|
||||
<span class="average">Retinal misalignment detected.</span> <br>
|
||||
{{/if}}
|
||||
|
||||
<br>
|
||||
{{:helper.link('Print', 'print', {'print_p' : 1, 'name' : data.occupant.name})}}
|
||||
{{:helper.link('Eject Occupant', 'arrow-circle-o-down', {'ejectify' : 1}, data.occupied ? null : 'disabled')}}
|
||||
<br> <br>
|
||||
|
||||
<b>Damage: </b>
|
||||
<table> <tbody>
|
||||
<tr>
|
||||
<td> Brute Damage: </td>
|
||||
<td> Brain Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.bruteLoss, 0, data.occupant.maxHealth+100, (data.occupant.bruteLoss < 15) ? 'notgood' : (data.occupant.bruteLoss < 40) ? 'average' : 'bad', data.occupant.bruteLoss) }} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.brainLoss, 0, data.occupant.maxHealth+100, (data.occupant.brainLoss < 15) ? 'notgood' : (data.occupant.brainLoss < 40) ? 'average' : 'bad', data.occupant.brainLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Resp. Damage: </td>
|
||||
<td> Radiation Level: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.oxyLoss, 0, data.occupant.maxHealth+100, (data.occupant.oxyLoss < 15) ? 'notgood' : (data.occupant.oxyLoss < 40) ? 'average' : 'bad', data.occupant.oxyLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.radLoss, 0, data.occupant.maxHealth+100, (data.occupant.radLoss < 15) ? 'notgood' : (data.occupant.radLoss < 40) ? 'average' : 'bad', data.occupant.radLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Toxin Damage: </td>
|
||||
<td> Genetic Damage: </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.toxLoss, 0, data.occupant.maxHealth+100, (data.occupant.toxLoss < 15) ? 'notgood' : (data.occupant.toxLoss < 40) ? 'average' : 'bad', data.occupant.toxLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.cloneLoss, 0, data.occupant.maxHealth+100, (data.occupant.cloneLoss < 15) ? 'notgood' : (data.occupant.cloneLoss < 40) ? 'average' : 'bad', data.occupant.cloneLoss)}} </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> Burn Severity: </td>
|
||||
<td> Paralysis %: ({{:helper.smoothRound(data.occupant.paralysisSeconds)}} seconds left) </td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td> {{:helper.displayBar(data.occupant.fireLoss, 0, data.occupant.maxHealth+100, (data.occupant.fireLoss < 15) ? 'notgood' : (data.occupant.fireLoss < 40) ? 'average' : 'bad', data.occupant.fireLoss)}} </td>
|
||||
<td> {{:helper.displayBar(data.occupant.paralysis, 0, 100, (data.occupant.paralysis < 25) ? 'notgood' : (data.occupant.paralysis < 50) ? 'average' : 'bad', data.occupant.paralysis)}} </td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
{{if data.occupant.blood.hasBlood}}
|
||||
<br>
|
||||
<b>Blood:</b>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Pulse:</div> <div class="statusValue">{{:data.occupant.blood.pulse}} bpm</div>
|
||||
</div>
|
||||
<div class="line">
|
||||
<div class="statusLabel">Blood Level:</div>
|
||||
{{:helper.displayBar(data.occupant.blood.bloodLevel, 0, data.occupant.blood.bloodMax, (data.occupant.blood.percent <= 60) ? 'bad' : (data.occupant.blood.percent <= 90) ? 'average' : 'good' )}}
|
||||
<div class="statusValue"> {{:helper.smoothRound(data.occupant.blood.percent)}}%, {{:helper.smoothRound(data.occupant.blood.bloodLevel)}}cl </div>
|
||||
</div>
|
||||
{{/if}}
|
||||
<br>
|
||||
{{if data.occupant.hasVirus}}
|
||||
<span class="bad">
|
||||
Viral pathogen detected in blood stream.
|
||||
</span> <br>
|
||||
{{/if}}
|
||||
{{if data.occupant.implant_len}}
|
||||
<br>
|
||||
<b>Implants</b>
|
||||
<table style="width: 30%">
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.implant}}
|
||||
<tr><td>{{:value.name}}</td></tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
{{/if}}
|
||||
<b>External Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th style="width: 25%"> Name </th>
|
||||
<th style='width: 15%'> Total damage </th>
|
||||
<th style="width: 15%"> Brute damage </th>
|
||||
<th style="width: 15%"> Burn damage </th>
|
||||
<th style="width: 30%"> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.extOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} </td>
|
||||
<td> {{:helper.displayBar(value.totalLoss, 0, value.maxHealth, (value.totalLoss < value.bruised) ? 'notgood' : (value.totalLoss < value.broken) ? 'average' : 'bad', value.totalLoss) }} </td>
|
||||
<td> {{if value.bruteLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.bruteLoss)}} </span> </td>
|
||||
<td> {{if value.fireLoss> 0}} <span class='average'> {{else}} <span> {{/if}} {{:helper.smoothRound(value.fireLoss)}} </span> </td>
|
||||
<td>
|
||||
<span class='average'>
|
||||
{{if value.internalBleeding}} internal bleeding <br> {{/if}}
|
||||
{{if value.lungRuptured}} lung ruptured <br> {{/if}}
|
||||
{{if value.status.broken}} {{:value.status.broken}} <br> {{/if}}
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
{{if value.open}} open incision <br> {{/if}}
|
||||
</span>
|
||||
{{if value.status.splinted}} splinted <br> {{/if}}
|
||||
{{if value.status.robotic}} robotic <br> {{/if}}
|
||||
{{if value.status.dead}} <span class='bad'>DEAD</span> <br {{/if}}
|
||||
{{if value.shrapnel_len}}
|
||||
{{for value.shrapnel : shrapValue:shrapindex}}
|
||||
{{:shrapValue.known ? shrapValue.name : "unknown object"}} <br>
|
||||
{{/for}}
|
||||
{{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
<br>
|
||||
<b>Internal Organs</b>
|
||||
<table> <thead>
|
||||
<tr>
|
||||
<th width=25%> Name </th>
|
||||
<th width=35%> Brute damage </th>
|
||||
<th widht=40%> Injuries </th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="striped">
|
||||
{{for data.occupant.intOrgan}}
|
||||
<tr>
|
||||
<td> {{:value.name}} <br> </td>
|
||||
<td> {{:helper.displayBar(value.damage, 0, value.maxHealth, (value.damage < value.bruised) ? 'notgood' : (value.damage < value.broken) ? 'average' : 'bad', value.damage) }} </td>
|
||||
<td>
|
||||
<span class="average">
|
||||
{{if value.germ_level > 100}}
|
||||
{{if value.germ_level < 300}}
|
||||
mild infection <br>
|
||||
{{else value.germ_level < 400}}
|
||||
mild infection+ <br>
|
||||
{{else value.germ_level < 500}}
|
||||
mild infection++ <br>
|
||||
{{else value.germ_level < 700}}
|
||||
acute Infection <br>
|
||||
{{else value.germ_level < 800}}
|
||||
acute Infection+ <br>
|
||||
{{else value.germ_level < 900}}
|
||||
acute Infection++ <br>
|
||||
{{else value.germ_level >= 900}}
|
||||
septic <br>
|
||||
{{/if}}
|
||||
{{/if}}
|
||||
</span>
|
||||
{{if value.robotic == 1}} robotic <br> {{/if}}
|
||||
{{if value.robotic == 2}} assisted <br> {{/if}}
|
||||
{{if value.dead}} <span class='bad'>DEAD</span> <br> {{/if}}
|
||||
</td>
|
||||
</tr>
|
||||
{{/for}}
|
||||
</tbody>
|
||||
</table>
|
||||
{{/if}}
|
||||
@@ -91,6 +91,7 @@ const styleMapperByPropName = {
|
||||
opacity: mapRawPropTo('opacity'),
|
||||
textAlign: mapRawPropTo('text-align'),
|
||||
verticalAlign: mapRawPropTo('vertical-align'),
|
||||
textTransform: mapRawPropTo('text-transform'),
|
||||
// Boolean props
|
||||
inline: mapBooleanPropTo('display', 'inline-block'),
|
||||
bold: mapBooleanPropTo('font-weight', 'bold'),
|
||||
@@ -152,6 +153,9 @@ const styleMapperByPropName = {
|
||||
export const computeBoxProps = props => {
|
||||
const computedProps = {};
|
||||
const computedStyles = {};
|
||||
if (props.double) {
|
||||
computedStyles["transform"] = "scale(2);";
|
||||
}
|
||||
// Compute props
|
||||
for (let propName of Object.keys(props)) {
|
||||
if (propName === 'style') {
|
||||
|
||||
@@ -0,0 +1,441 @@
|
||||
import { round, scale, toFixed } from 'common/math';
|
||||
import { Fragment } from 'inferno';
|
||||
import { useBackend } from "../backend";
|
||||
import { Window } from "../layouts";
|
||||
import { AnimatedNumber, Box, Button, Flex, Icon, LabeledList, ProgressBar, Section, Table, Tooltip } from "../components";
|
||||
import { LabeledListItem } from '../components/LabeledList';
|
||||
|
||||
const stats = [
|
||||
['good', 'Alive'],
|
||||
['average', 'Critical'],
|
||||
['bad', 'DEAD'],
|
||||
];
|
||||
|
||||
const abnormalities = [
|
||||
['hasBorer', 'bad', 'Large growth detected in frontal lobe,'
|
||||
+ ' possibly cancerous. Surgical removal is recommended.'],
|
||||
['hasVirus', 'bad', 'Viral pathogen detected in blood stream.'],
|
||||
['blind', 'average', 'Cataracts detected.'],
|
||||
['colourblind', 'average', 'Photoreceptor abnormalities detected.'],
|
||||
['nearsighted', 'average', 'Retinal misalignment detected.'],
|
||||
];
|
||||
|
||||
const damages = [
|
||||
['Respiratory', 'oxyLoss'],
|
||||
['Brain', 'brainLoss'],
|
||||
['Toxin', 'toxLoss'],
|
||||
['Radioactive', 'radLoss'],
|
||||
['Brute', 'bruteLoss'],
|
||||
['Genetic', 'cloneLoss'],
|
||||
['Burn', 'fireLoss'],
|
||||
['Paralysis', 'paralysis'],
|
||||
];
|
||||
|
||||
const damageRange = {
|
||||
average: [0.25, 0.5],
|
||||
bad: [0.5, Infinity],
|
||||
};
|
||||
|
||||
const mapTwoByTwo = (a, c) => {
|
||||
let result = [];
|
||||
for (let i = 0; i < a.length; i += 2) {
|
||||
result.push(c(a[i], a[i + 1], i));
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
const reduceOrganStatus = A => {
|
||||
return A.length > 0
|
||||
? A.reduce((a, s) =>
|
||||
a === null
|
||||
? s : (
|
||||
<Fragment>
|
||||
{a}
|
||||
{!!s && (
|
||||
<Fragment>
|
||||
{s}
|
||||
{s.length > 0 && <br />}
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
))
|
||||
: null;
|
||||
};
|
||||
|
||||
const germStatus = i => {
|
||||
if (i > 100) {
|
||||
if (i < 300) { return "mild infection"; }
|
||||
if (i < 400) { return "mild infection+"; }
|
||||
if (i < 500) { return "mild infection++"; }
|
||||
if (i < 700) { return "acute infection"; }
|
||||
if (i < 800) { return "acute infection+"; }
|
||||
if (i < 900) { return "acute infection++"; }
|
||||
if (i >= 900) { return "septic"; }
|
||||
}
|
||||
|
||||
return "";
|
||||
};
|
||||
|
||||
export const BodyScanner = (props, context) => {
|
||||
const { data } = useBackend(context);
|
||||
const {
|
||||
occupied,
|
||||
occupant = {},
|
||||
} = data;
|
||||
const body = occupied ? (
|
||||
<BodyScannerMain occupant={occupant} />
|
||||
) : (
|
||||
<BodyScannerEmpty />
|
||||
);
|
||||
return (
|
||||
<Window resizable>
|
||||
<Window.Content scrollable className="Layout__content--flexColumn">
|
||||
{body}
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMain = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
return (
|
||||
<Box>
|
||||
<BodyScannerMainOccupant occupant={occupant} />
|
||||
<BodyScannerMainAbnormalities occupant={occupant} />
|
||||
<BodyScannerMainDamage occupant={occupant} />
|
||||
<BodyScannerMainOrgansExternal organs={occupant.extOrgan} />
|
||||
<BodyScannerMainOrgansInternal organs={occupant.intOrgan} />
|
||||
</Box>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOccupant = (props, context) => {
|
||||
const { act, data } = useBackend(context);
|
||||
const {
|
||||
occupant,
|
||||
} = data;
|
||||
return (
|
||||
<Section
|
||||
title="Occupant"
|
||||
buttons={(
|
||||
<Fragment>
|
||||
<Button
|
||||
icon="user-slash"
|
||||
onClick={() => act('ejectify')}>
|
||||
Eject
|
||||
</Button>
|
||||
<Button
|
||||
icon="print"
|
||||
onClick={() => act('print_p')}>
|
||||
Print Report
|
||||
</Button>
|
||||
</Fragment>
|
||||
)}>
|
||||
<LabeledList>
|
||||
<LabeledList.Item label="Name">
|
||||
{occupant.name}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Health">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max="100"
|
||||
value={occupant.health / 100}
|
||||
ranges={{
|
||||
good: [0.5, Infinity],
|
||||
average: [0, 0.5],
|
||||
bad: [-Infinity, 0],
|
||||
}}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Status" color={stats[occupant.stat][0]}>
|
||||
{stats[occupant.stat][1]}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Temperature">
|
||||
<AnimatedNumber
|
||||
value={round(occupant.bodyTempC)}
|
||||
/>°C,
|
||||
<AnimatedNumber
|
||||
value={round(occupant.bodyTempF)}
|
||||
/>°F
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Item label="Implants">
|
||||
{occupant.implant_len ? (
|
||||
<Box>
|
||||
{occupant.implant.map(im => im.name).join(', ')}
|
||||
</Box>
|
||||
) : (
|
||||
<Box color="label">
|
||||
None
|
||||
</Box>
|
||||
)}
|
||||
</LabeledList.Item>
|
||||
</LabeledList>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainAbnormalities = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
if (!(occupant.hasBorer || occupant.blind
|
||||
|| occupant.colourblind || occupant.nearsighted
|
||||
|| occupant.hasVirus)) {
|
||||
return (
|
||||
<Section title="Abnormalities">
|
||||
<Box color="label">
|
||||
No abnormalities found.
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Abnormalities">
|
||||
{abnormalities.map((a, i) => {
|
||||
if (occupant[a[0]]) {
|
||||
return (
|
||||
<Box color={a[1]} bold={a[1] === "bad"}>
|
||||
{a[2]}
|
||||
</Box>
|
||||
);
|
||||
}
|
||||
})}
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainDamage = props => {
|
||||
const {
|
||||
occupant,
|
||||
} = props;
|
||||
return (
|
||||
<Section title="Damage">
|
||||
<Table>
|
||||
{mapTwoByTwo(damages, (d1, d2, i) => (
|
||||
<Fragment>
|
||||
<Table.Row color="label">
|
||||
<Table.Cell>
|
||||
{d1[0]}:
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{!!d2 && d2[0] + ":"}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
<Table.Row>
|
||||
<Table.Cell>
|
||||
<BodyScannerMainDamageBar
|
||||
value={occupant[d1[1]]}
|
||||
marginBottom={i < (damages.length - 2)}
|
||||
/>
|
||||
</Table.Cell>
|
||||
<Table.Cell>
|
||||
{!!d2 && (
|
||||
<BodyScannerMainDamageBar value={occupant[d2[1]]} />
|
||||
)}
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
</Fragment>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainDamageBar = props => {
|
||||
return (
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max="100"
|
||||
value={props.value / 100}
|
||||
mt="0.5rem"
|
||||
mb={!!props.marginBottom && "0.5rem"}
|
||||
ranges={damageRange}>
|
||||
{round(props.value)}
|
||||
</ProgressBar>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOrgansExternal = props => {
|
||||
if (props.organs.length === 0) {
|
||||
return (
|
||||
<Section title="External Organs">
|
||||
<Box color="label">
|
||||
N/A
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="External Organs">
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>
|
||||
Name
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
Damage
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="right">
|
||||
Injuries
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{props.organs.map((o, i) => (
|
||||
<Table.Row key={i} textTransform="capitalize">
|
||||
<Table.Cell width="33%">
|
||||
{o.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center" q>
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={o.maxHealth}
|
||||
mt={i > 0 && "0.5rem"}
|
||||
value={o.totalLoss / 100}
|
||||
ranges={damageRange}>
|
||||
<Box float="left" display="inline">
|
||||
{!!o.bruteLoss && (
|
||||
<Box display="inline" position="relative">
|
||||
<Icon name="bone" />
|
||||
{round(o.bruteLoss)}
|
||||
<Tooltip
|
||||
position="top"
|
||||
content="Brute damage"
|
||||
/>
|
||||
</Box>)}
|
||||
{!!o.fireLoss && (
|
||||
<Box display="inline" position="relative">
|
||||
<Icon name="fire" />
|
||||
{round(o.fireLoss)}
|
||||
<Tooltip
|
||||
position="top"
|
||||
content="Burn damage"
|
||||
/>
|
||||
</Box>)}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{round(o.totalLoss)}
|
||||
</Box>
|
||||
</ProgressBar>
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="right"
|
||||
width="33%">
|
||||
<Box color="average" display="inline">
|
||||
{reduceOrganStatus([
|
||||
o.internalBleeding && "Internal bleeding",
|
||||
o.lungRuptured && "Ruptured lung",
|
||||
!!o.status.broken && o.status.broken,
|
||||
germStatus(o.germ_level),
|
||||
!!o.open && "Open incision",
|
||||
])}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{reduceOrganStatus([
|
||||
!!o.status.splinted && "Splinted",
|
||||
!!o.status.robotic && "Robotic",
|
||||
!!o.status.dead && (
|
||||
<Box color="bad">
|
||||
DEAD
|
||||
</Box>
|
||||
),
|
||||
])}
|
||||
{reduceOrganStatus(o.shrapnel.map(
|
||||
s => s.known
|
||||
? s.name
|
||||
: "Unknown object"
|
||||
))}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerMainOrgansInternal = props => {
|
||||
if (props.organs.length === 0) {
|
||||
return (
|
||||
<Section title="Internal Organs">
|
||||
<Box color="label">
|
||||
N/A
|
||||
</Box>
|
||||
</Section>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Section title="Internal Organs">
|
||||
<Table>
|
||||
<Table.Row header>
|
||||
<Table.Cell>
|
||||
Name
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
Damage
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="right">
|
||||
Injuries
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
{props.organs.map((o, i) => (
|
||||
<Table.Row key={i} textTransform="capitalize">
|
||||
<Table.Cell width="33%">
|
||||
{o.name}
|
||||
</Table.Cell>
|
||||
<Table.Cell textAlign="center">
|
||||
<ProgressBar
|
||||
min="0"
|
||||
max={o.maxHealth}
|
||||
value={o.damage / 100}
|
||||
mt={i > 0 && "0.5rem"}
|
||||
ranges={damageRange}>
|
||||
{round(o.damage)}
|
||||
</ProgressBar>
|
||||
</Table.Cell>
|
||||
<Table.Cell
|
||||
textAlign="right"
|
||||
width="33%">
|
||||
<Box color="average" display="inline">
|
||||
{reduceOrganStatus([
|
||||
germStatus(o.germ_level),
|
||||
])}
|
||||
</Box>
|
||||
<Box display="inline">
|
||||
{reduceOrganStatus([
|
||||
(o.robotic === 1) && "Robotic",
|
||||
(o.robotic === 2) && "Assisted",
|
||||
!!o.dead && (
|
||||
<Box color="bad">
|
||||
DEAD
|
||||
</Box>
|
||||
),
|
||||
])}
|
||||
</Box>
|
||||
</Table.Cell>
|
||||
</Table.Row>
|
||||
))}
|
||||
</Table>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
|
||||
const BodyScannerEmpty = () => {
|
||||
return (
|
||||
<Section textAlign="center" flexGrow="1">
|
||||
<Flex height="100%">
|
||||
<Flex.Item grow="1" align="center" color="label">
|
||||
<Icon
|
||||
name="user-slash"
|
||||
mb="0.5rem"
|
||||
size="5"
|
||||
/><br />
|
||||
No occupant detected.
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
</Section>
|
||||
);
|
||||
};
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user