Refactor NanoMaps, TGUI Crew Monitor

This commit is contained in:
mochi
2020-09-17 22:18:57 +02:00
parent 36481c3c02
commit 888ac72650
11 changed files with 252 additions and 171 deletions
+10 -1
View File
@@ -1,7 +1,14 @@
GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
/datum/repository/crew
var/static/list/heads
var/static/list/ert_jobs
/datum/repository/crew/New()
cache_data = list()
// These jobs are used to highlight those with a command ID. Stolen from nttc.dm
heads = heads || list("Captain", "Head of Personnel", "Nanotrasen Representative", "Blueshield", "Chief Engineer", "Chief Medical Officer", "Research Director", "Head of Security", "Magistrate", "AI")
ert_jobs = ert_jobs || list("Emergency Response Team Officer", "Emergency Response Team Engineer", "Emergency Response Team Medic", "Emergency Response Team Leader", "Emergency Response Team Member")
..()
/datum/repository/crew/proc/health_data(turf/T)
@@ -32,11 +39,13 @@ GLOBAL_DATUM_INIT(crew_repository, /datum/repository/crew, new())
crewmemberData["name"] = H.get_authentification_name(if_no_id="Unknown")
crewmemberData["rank"] = H.get_authentification_rank(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["assignment"] = H.get_assignment(if_no_id="Unknown", if_no_job="No Job")
crewmemberData["is_command"] = (crewmemberData["assignment"] in ert_jobs) || (crewmemberData["assignment"] in heads)
if(C.sensor_mode >= SUIT_SENSOR_BINARY)
crewmemberData["dead"] = H.stat > UNCONSCIOUS
crewmemberData["dead"] = H.stat == DEAD
if(C.sensor_mode >= SUIT_SENSOR_VITAL)
crewmemberData["stat"] = H.stat
crewmemberData["oxy"] = round(H.getOxyLoss(), 1)
crewmemberData["tox"] = round(H.getToxLoss(), 1)
crewmemberData["fire"] = round(H.getFireLoss(), 1)
+4 -4
View File
@@ -365,10 +365,10 @@ GLOBAL_LIST_EMPTY(asset_datums)
// Nanomaps
/datum/asset/simple/nanomaps
// It REALLY doesnt matter too much if these arent up to date
// They are friggin huge
// They are relatively big
verify = FALSE
assets = list(
"Cyberiad_nanomap_z1.png" = 'icons/_nanomaps/Cyberiad_nanomap_z1.png',
"Delta_nanomap_z1.png" = 'icons/_nanomaps/Delta_nanomap_z1.png',
"MetaStation_nanomap_z1.png" = 'icons/_nanomaps/MetaStation_nanomap_z1.png',
"Cyberiad_nanomap_z1.png" = 'icons/_nanomaps/Cyberiad_nanomap_z1.png',
"Delta_nanomap_z1.png" = 'icons/_nanomaps/Delta_nanomap_z1.png',
"MetaStation_nanomap_z1.png" = 'icons/_nanomaps/MetaStation_nanomap_z1.png',
)
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 MiB

After

Width:  |  Height:  |  Size: 714 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 MiB

After

Width:  |  Height:  |  Size: 929 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.4 MiB

After

Width:  |  Height:  |  Size: 661 KiB

+71 -27
View File
@@ -1,7 +1,16 @@
import { Box, Icon, Tooltip } from '.';
import { Component } from 'inferno';
import { Box, Icon, Tooltip } from '.';
import { useBackend } from "../backend";
import { LabeledList } from './LabeledList';
import { Slider } from './Slider';
const pauseEvent = e => {
if (e.stopPropagation) { e.stopPropagation(); }
if (e.preventDefault) { e.preventDefault(); }
e.cancelBubble = true;
e.returnValue = false;
return false;
};
export class NanoMap extends Component {
constructor(props) {
@@ -9,31 +18,29 @@ export class NanoMap extends Component {
// Auto center based on window size
const Xcenter = (window.innerWidth / 2) - 256;
const Ycenter = (window.innerHeight / 2) - 256;
this.state = {
offsetX: Xcenter,
offsetY: 0,
offsetX: 128,
offsetY: 48,
transform: 'none',
dragging: false,
originX: null,
originY: null,
zoom: 1,
};
// Dragging
this.handleDragStart = e => {
document.body.style['pointer-events'] = 'none';
this.ref = e.target;
this.setState({
dragging: false,
originX: e.screenX,
originY: e.screenY,
});
this.timer = setTimeout(() => {
this.setState({
dragging: true,
});
}, 250);
document.addEventListener('mousemove', this.handleDragMove);
document.addEventListener('mouseup', this.handleDragEnd);
pauseEvent(e);
};
this.handleDragMove = e => {
@@ -51,11 +58,10 @@ export class NanoMap extends Component {
}
return state;
});
pauseEvent(e);
};
this.handleDragEnd = e => {
document.body.style['pointer-events'] = 'auto';
clearTimeout(this.timer);
this.setState({
dragging: false,
originX: null,
@@ -63,28 +69,44 @@ export class NanoMap extends Component {
});
document.removeEventListener('mousemove', this.handleDragMove);
document.removeEventListener('mouseup', this.handleDragEnd);
pauseEvent(e);
};
this.handleZoom = (_e, value) => {
this.setState(state => {
const newZoom = Math.min(Math.max(value, 1), 8);
let zoomDiff = (newZoom - state.zoom) * 1.5;
state.zoom = newZoom;
state.offsetX = state.offsetX - 262 * zoomDiff;
state.offsetY = state.offsetY - 256 * zoomDiff;
if (props.onZoom) {
props.onZoom(state.zoom);
}
return state;
});
};
}
render() {
const { config } = useBackend(this.context);
const { offsetX, offsetY } = this.state;
const { children, zoom } = this.props;
const { dragging, offsetX, offsetY, zoom = 1 } = this.state;
const { children } = this.props;
const mapUrl = config.map + "_nanomap_z1.png?" + Date.now();
const mapSize = (512 * zoom) + 'px';
const newStyle = {
width: '512px',
height: '512px',
"margin-top": offsetY + 'px',
"margin-left": offsetX + 'px',
width: mapSize,
height: mapSize,
"margin-top": offsetY + "px",
"margin-left": offsetX + "px",
"overflow": "hidden",
"position": "relative",
"padding": "0px",
"background-image":
"url(" + config.map + "_nanomap_z1.png)",
"background-image": "url(" + mapUrl + ")",
"background-size": "cover",
"background-repeat": "no-repeat",
"text-align": "center",
"transform-origin": "center center",
"transform": "scale(" + zoom + ")",
"cursor": dragging ? "move" : "auto",
};
return (
@@ -97,6 +119,7 @@ export class NanoMap extends Component {
{children}
</Box>
</Box>
<NanoMapZoomer zoom={zoom} onZoom={this.handleZoom} />
</Box>
);
}
@@ -106,20 +129,20 @@ const NanoMapMarker = (props, context) => {
const {
x,
y,
zoom,
zoom = 1,
icon,
tooltip,
color,
} = props;
const rx = -256 * (zoom - 1) + x * (2 * zoom) - 1.5 * zoom - 3;
const ry = 512 * zoom - (y * 2 * zoom) + zoom - 1.5;
const rx = x * 2 * zoom - 3;
const ry = y * 2 * zoom - 3;
return (
<div style={"transform: scale(" + 1 / zoom + ")"}>
<div>
<Box
position="absolute"
className="NanoMap__marker"
lineHeight="0"
top={ry + "px"}
bottom={ry + "px"}
left={rx + "px"}>
<Icon
name={icon}
@@ -133,3 +156,24 @@ const NanoMapMarker = (props, context) => {
};
NanoMap.Marker = NanoMapMarker;
const NanoMapZoomer = (props, context) => {
return (
<Box className="NanoMap__zoomer">
<LabeledList>
<LabeledList.Item label="Zoom">
<Slider
minValue="1"
maxValue="8"
stepPixelSize="10"
format={v => v + "x"}
value={props.zoom}
onDrag={(e, v) => props.onZoom(e, v)}
/>
</LabeledList.Item>
</LabeledList>
</Box>
);
};
NanoMap.Zoomer = NanoMapZoomer;
+150 -131
View File
@@ -1,148 +1,167 @@
import { sortBy } from 'common/collections';
import { useBackend, useLocalState } from "../backend";
import { Window } from "../layouts";
import { NanoMap, Box, Table, Button, Tabs, Icon, NumberInput } from "../components";
import { Box, Button, Icon, NanoMap, Table, Tabs } from "../components";
import { TableCell } from '../components/Table';
import { COLORS } from '../constants.js';
import { Window } from "../layouts";
const getStatText = cm => {
if (cm.dead) {
return "Deceased";
}
if (parseInt(cm.stat, 10) === 1) { // Unconscious
return "Unconscious";
}
return "Living";
};
const getStatColor = cm => {
if (cm.dead) {
return "red";
}
if (parseInt(cm.stat, 10) === 1) { // Unconscious
return "orange";
}
return "green";
};
export const CrewMonitor = (props, context) => {
const { act, data } = useBackend(context);
const [tabIndex, setTabIndex] = useLocalState(context, 'tabIndex', 0);
const crew = sortBy(
cm => cm.name,
)(data.crewmembers || []);
const [
mapZoom,
setZoom,
] = useLocalState(context, 'number', 1);
let body;
// Data view
if (tabIndex === 0) {
body = (
<Table>
<Table.Row header>
<Table.Cell>
Name
</Table.Cell>
<Table.Cell>
Status
</Table.Cell>
<Table.Cell>
Location
</Table.Cell>
</Table.Row>
{crew.map(cm => (
<Table.Row key={cm.name}>
<TableCell>
{cm.name} ({cm.assignment})
</TableCell>
<TableCell>
<Box inline
color={cm.dead ? 'red' : 'green'}>
{cm.dead ? 'Deceased' : 'Living'}
</Box>
{cm.sensor_type >= 2 ? (
<Box inline>
{'('}
<Box inline
color={COLORS.damageType.oxy}>
{cm.oxy}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.toxin}>
{cm.tox}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.burn}>
{cm.fire}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.brute}>
{cm.brute}
</Box>
{')'}
</Box>
) : null}
</TableCell>
<TableCell>
{cm.sensor_type === 3 ? (
data.isAI ? (
<Button fluid
icon="location-arrow"
content={
cm.area + " (" + cm.x + ", " + cm.y + ")"
}
onClick={() => act('track', {
track: cm.ref,
})} />
) : (
cm.area + " (" + cm.x + ", " + cm.y + ")"
)
) : "Not Available"}
</TableCell>
</Table.Row>
))}
</Table>
);
// Map view
} else if (tabIndex === 1) {
body = (
(
<Box textAlign="center">
Zoom Level:
<NumberInput
animated
width="40px"
step="0.5"
stepPixelSize="10"
value={mapZoom}
minValue="1"
maxValue="8"
onDrag={(e, value) => setZoom(value)} />
<NanoMap zoom={mapZoom}>
{crew.filter(x => x.sensor_type === 3).map(cm => (
<NanoMap.Marker
key={cm.ref}
x={cm.x}
y={cm.y}
zoom={mapZoom}
icon="circle"
tooltip={cm.name}
color={cm.dead ? 'red' : 'green'}
/>
))}
</NanoMap>
</Box>
)
);
} else {
body = "ERROR";
}
const decideTab = index => {
switch (index) {
case 0:
return <CrewMonitorDataView />;
case 1:
return <CrewMonitorMapView />;
default:
return "WE SHOULDN'T BE HERE!";
}
};
return (
<Window resizable>
<Window.Content>
<Tabs>
<Tabs.Tab
key="DataView"
selected={0 === tabIndex}
onClick={() => setTabIndex(0)}>
<Icon name="table" /> Data View
</Tabs.Tab>
<Tabs.Tab
key="MapView"
selected={1 === tabIndex}
onClick={() => setTabIndex(1)}>
<Icon name="map-marked-alt" /> Map View
</Tabs.Tab>
</Tabs>
<Box m={2}>
{body}
<Box fillPositionedParent m="0.5rem">
<Tabs>
<Tabs.Tab
key="DataView"
selected={0 === tabIndex}
onClick={() => setTabIndex(0)}>
<Icon name="table" /> Data View
</Tabs.Tab>
<Tabs.Tab
key="MapView"
selected={1 === tabIndex}
onClick={() => setTabIndex(1)}>
<Icon name="map-marked-alt" /> Map View
</Tabs.Tab>
</Tabs>
{decideTab(tabIndex)}
</Box>
</Window.Content>
</Window>
);
};
const CrewMonitorDataView = (_properties, context) => {
const { act, data } = useBackend(context);
const crew = sortBy(
cm => cm.name,
)(data.crewmembers || []);
const [
search,
setSearch,
] = useLocalState(context, 'search', '');
return (
<Table m="0.5rem">
<Table.Row header>
<Table.Cell>
Name
</Table.Cell>
<Table.Cell>
Status
</Table.Cell>
<Table.Cell>
Location
</Table.Cell>
</Table.Row>
{crew.map(cm => (
<Table.Row key={cm.name} bold={cm.is_command}>
<TableCell>
{cm.name} ({cm.assignment})
</TableCell>
<TableCell>
<Box inline
color={getStatColor(cm)}>
{getStatText(cm)}
</Box>
{cm.sensor_type >= 2 ? (
<Box inline>
{'('}
<Box inline
color={COLORS.damageType.oxy}>
{cm.oxy}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.toxin}>
{cm.tox}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.burn}>
{cm.fire}
</Box>
{'|'}
<Box inline
color={COLORS.damageType.brute}>
{cm.brute}
</Box>
{')'}
</Box>
) : null}
</TableCell>
<TableCell>
{cm.sensor_type === 3 ? (
data.isAI ? (
<Button fluid
icon="location-arrow"
content={
cm.area + " (" + cm.x + ", " + cm.y + ")"
}
onClick={() => act('track', {
track: cm.ref,
})} />
) : (
cm.area + " (" + cm.x + ", " + cm.y + ")"
)
) : "Not Available"}
</TableCell>
</Table.Row>
))}
</Table>
);
};
const CrewMonitorMapView = (_properties, context) => {
const { data } = useBackend(context);
const [zoom, setZoom] = useLocalState(context, 'zoom', 1);
return (
<Box height="526px" mb="0.5rem" overflow="hidden">
<NanoMap onZoom={v => setZoom(v)}>
{data.crewmembers.filter(x => x.sensor_type === 3).map(cm => (
<NanoMap.Marker
key={cm.ref}
x={cm.x}
y={cm.y}
zoom={zoom}
icon="circle"
tooltip={cm.name + " (" + cm.assignment + ")"}
color={getStatColor(cm)}
/>
))}
</NanoMap>
</Box>
);
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,9 +1,8 @@
$color-background: rgba(0, 0, 0, 0.33) !default;
.NanoMap__container {
overflow: hidden;
overflow: hiddden;
width: 100%;
height: 100vh;
z-index: 1;
}
@@ -12,3 +11,13 @@ $color-background: rgba(0, 0, 0, 0.33) !default;
padding: 0px;
margin: 0px;
}
.NanoMap__zoomer {
z-index: 20;
background-color: $color-background;
position: absolute;
top: 30px;
left: 0;
padding: 0.5rem;
width: 20%;
}
@@ -1,8 +1,8 @@
#!/bin/bash
# Generate maps
tools/github-actions/nanomap-renderer minimap "./_maps/map_files/cyberiad/cyberiad.dmm"
tools/github-actions/nanomap-renderer minimap "./_maps/map_files/Delta/delta.dmm"
tools/github-actions/nanomap-renderer minimap "./_maps/map_files/MetaStation/MetaStation.v41A.II.dmm"
tools/github-actions/nanomap-renderer minimap -w 2040 -h 2040 "./_maps/map_files/cyberiad/cyberiad.dmm"
tools/github-actions/nanomap-renderer minimap -w 2040 -h 2040 "./_maps/map_files/Delta/delta.dmm"
tools/github-actions/nanomap-renderer minimap -w 2040 -h 2040 "./_maps/map_files/MetaStation/MetaStation.v41A.II.dmm"
# Move and rename files so the game understands them
cd "data/nanomaps"
mv "cyberiad_nanomap_z1.png" "Cyberiad_nanomap_z1.png"