no thoughts, head segfaulted

This commit is contained in:
Letter N
2020-08-15 16:48:10 +08:00
parent 15e659fc9c
commit a327e7d33f
15 changed files with 628 additions and 71 deletions

View File

@@ -39,6 +39,10 @@ export const loadSourceMaps = async bundleDir => {
};
export const retrace = stack => {
if (typeof stack !== 'string') {
logger.log('ERROR: Stack is not a string!', stack);
return stack;
}
const header = stack.split(/\n\s.*at/)[0];
const mappedStack = StackTraceParser.parse(stack)
.map(frame => {

View File

@@ -0,0 +1,127 @@
import { map, sortBy } from 'common/collections';
import { flow } from 'common/fp';
import { useBackend } from '../backend';
import { Box, Button, Flex, Section, Table } from '../components';
import { Window } from '../layouts';
export const AtmosControlPanel = (props, context) => {
const { act, data } = useBackend(context);
const groups = flow([
map((group, i) => ({
...group,
// Generate a unique id
id: group.area + i,
})),
sortBy(group => group.id),
])(data.excited_groups);
return (
<Window
title="SSAir Control Panel"
width={900}
height={500}
resizable>
<Section m={1}>
<Flex
justify="space-between"
align="baseline">
<Flex.Item>
<Button
onClick={() => act('toggle-freeze')}
color={data.frozen === 1 ? 'good' : 'bad'}>
{data.frozen === 1
? 'Freeze Subsystem'
: 'Unfreeze Subsystem'}
</Button>
</Flex.Item>
<Flex.Item>
Fire Cnt: {data.fire_count}
</Flex.Item>
<Flex.Item>
Active Turfs: {data.active_size}
</Flex.Item>
<Flex.Item>
Excited Groups: {data.excited_size}
</Flex.Item>
<Flex.Item>
Hotspots: {data.hotspots_size}
</Flex.Item>
<Flex.Item>
Superconductors: {data.conducting_size}
</Flex.Item>
<Flex.Item>
<Button.Checkbox
checked={data.showing_user}
onClick={() => act('toggle_user_display')}>
Personal View
</Button.Checkbox>
</Flex.Item>
<Flex.Item>
<Button.Checkbox
checked={data.show_all}
onClick={() => act('toggle_show_all')}>
Display all
</Button.Checkbox>
</Flex.Item>
</Flex>
</Section>
<Box fillPositionedParent top="45px">
<Window.Content scrollable>
<Section>
<Table>
<Table.Row header>
<Table.Cell>
Area Name
</Table.Cell>
<Table.Cell collapsing>
Breakdown
</Table.Cell>
<Table.Cell collapsing>
Dismantle
</Table.Cell>
<Table.Cell collapsing>
Turfs
</Table.Cell>
<Table.Cell collapsing>
{data.display_max === 1 && "Max Share"}
</Table.Cell>
<Table.Cell collapsing>
Display
</Table.Cell>
</Table.Row>
{groups.map(group => (
<tr key={group.id}>
<td>
<Button
content={group.area}
onClick={() => act('move-to-target', {
spot: group.jump_to,
})} />
</td>
<td>
{group.breakdown}
</td>
<td>
{group.dismantle}
</td>
<td>
{group.size}
</td>
<td>
{data.display_max === 1 && group.max_share}
</td>
<td>
<Button.Checkbox
checked={group.should_show}
onClick={() => act('toggle_show_group', {
group: group.group,
})} />
</td>
</tr>
))}
</Table>
</Section>
</Window.Content>
</Box>
</Window>
);
};

View File

@@ -5,7 +5,7 @@ import { createSearch } from 'common/string';
import { Fragment } from 'inferno';
import { useBackend, useLocalState } from '../backend';
import { Button, ByondUi, Input, Section } from '../components';
import { refocusLayout, Window } from '../layouts';
import { Window } from '../layouts';
/**
* Returns previous and next camera names relative to the currently
@@ -123,12 +123,9 @@ export const CameraConsoleContent = (props, context) => {
&& camera.name === activeCamera.name
&& 'Button--selected',
])}
onClick={() => {
refocusLayout();
act('switch_camera', {
name: camera.name,
});
}}>
onClick={() => act('switch_camera', {
name: camera.name,
})}>
{camera.name}
</div>
))}

View File

@@ -20,34 +20,36 @@ export const Cargo = (props, context) => {
resizable>
<Window.Content scrollable>
<CargoStatus />
<Tabs>
<Tabs.Tab
icon="list"
selected={tab === 'catalog'}
onClick={() => setTab('catalog')}>
Catalog
</Tabs.Tab>
<Tabs.Tab
icon="envelope"
textColor={tab !== 'requests'
&& requests.length > 0
&& 'yellow'}
selected={tab === 'requests'}
onClick={() => setTab('requests')}>
Requests ({requests.length})
</Tabs.Tab>
{!requestonly && (
<Section fitted>
<Tabs>
<Tabs.Tab
icon="shopping-cart"
textColor={tab !== 'cart'
&& cart.length > 0
&& 'yellow'}
selected={tab === 'cart'}
onClick={() => setTab('cart')}>
Checkout ({cart.length})
icon="list"
selected={tab === 'catalog'}
onClick={() => setTab('catalog')}>
Catalog
</Tabs.Tab>
)}
</Tabs>
<Tabs.Tab
icon="envelope"
textColor={tab !== 'requests'
&& requests.length > 0
&& 'yellow'}
selected={tab === 'requests'}
onClick={() => setTab('requests')}>
Requests ({requests.length})
</Tabs.Tab>
{!requestonly && (
<Tabs.Tab
icon="shopping-cart"
textColor={tab !== 'cart'
&& cart.length > 0
&& 'yellow'}
selected={tab === 'cart'}
onClick={() => setTab('cart')}>
Checkout ({cart.length})
</Tabs.Tab>
)}
</Tabs>
</Section>
{tab === 'catalog' && (
<CargoCatalog />
)}
@@ -143,7 +145,7 @@ export const CargoCatalog = (props, context) => {
</Fragment>
)}>
<Flex>
<Flex.Item>
<Flex.Item ml={-1} mr={1}>
<Tabs vertical>
{supplies.map(supply => (
<Tabs.Tab

View File

@@ -242,13 +242,14 @@ const CfStep2 = (props, context) => {
</Table.Row>
<Table.Row>
<Table.Cell bold position="relative">
Card Reader:
Secondary Card Reader:
<Tooltip
content={multiline`
Adds a slot that allows you to manipulate RFID cards.
Please note that this is not necessary to allow the device
to read your identification, it is just necessary to
manipulate other cards.
Adds a secondary RFID card reader, for manipulating or
reading from a second standard RFID card.
Please note that a primary card reader is necessary to
allow the device to read your identification, but one
is included in the base price.
`}
position="right" />
</Table.Cell>

View File

@@ -0,0 +1,102 @@
import { useBackend } from '../backend';
import { Button, Flex, Fragment, Section, NoticeBox } from '../components';
import { Window } from '../layouts';
export const GhostPoolProtection = (props, context) => {
const { act, data } = useBackend(context);
const {
events_or_midrounds,
spawners,
station_sentience,
silicons,
minigames,
} = data;
return (
<Window
title="Ghost Pool Protection"
width={400}
height={270}>
<Window.Content>
<Flex grow={1} height="100%">
<Section
title="Options"
buttons={
<Fragment>
<Button
color="good"
icon="plus-circle"
content="Enable Everything"
onClick={() => act("all_roles")} />
<Button
color="bad"
icon="minus-circle"
content="Disable Everything"
onClick={() => act("no_roles")} />
</Fragment>
}>
<NoticeBox danger>
For people creating a sneaky event: If you
toggle Station Created Sentience, people may
catch on that admins have disabled roles for
your event...
</NoticeBox>
<Flex.Item>
<Button
fluid
textAlign="center"
color={events_or_midrounds ? "good" : "bad"}
icon="meteor"
content="Events and Midround Rulesets"
onClick={() => act("toggle_events_or_midrounds")} />
</Flex.Item>
<Flex.Item>
<Button
fluid
textAlign="center"
color={spawners ? "good" : "bad"}
icon="pastafarianism"
content="Ghost Role Spawners"
onClick={() => act("toggle_spawners")} />
</Flex.Item>
<Flex.Item>
<Button
fluid
textAlign="center"
color={station_sentience ? "good" : "bad"}
icon="user-astronaut"
content="Station Created Sentience"
onClick={() => act("toggle_station_sentience")} />
</Flex.Item>
<Flex.Item>
<Button
fluid
textAlign="center"
color={silicons ? "good" : "bad"}
icon="robot"
content="Silicons"
onClick={() => act("toggle_silicons")} />
</Flex.Item>
<Flex.Item>
<Button
fluid
textAlign="center"
color={minigames ? "good" : "bad"}
icon="gamepad"
content="Minigames"
onClick={() => act("toggle_minigames")} />
</Flex.Item>
<Flex.Item>
<Button
fluid
textAlign="center"
color="orange"
icon="check"
content="Apply Changes"
onClick={() => act("apply_settings")} />
</Flex.Item>
</Section>
</Flex>
</Window.Content>
</Window>
);
};

View File

@@ -0,0 +1,97 @@
import { useBackend } from '../backend';
import { Box, Button, Divider, Flex, Grid, Input, NoticeBox, NumberInput, Section } from '../components';
import { Window } from '../layouts';
export const MechpadControl = (props, context) => {
const { topLevel } = props;
const { act, data } = useBackend(context);
const {
pad_name,
connected_mechpad,
} = data;
return (
<Section
title={(
<Input
value={pad_name}
width="170px"
onChange={(e, value) => act('rename', {
name: value,
})} />
)}
level={topLevel ? 1 : 2}
buttons={(
<Button
icon="times"
content="Remove"
color="bad"
onClick={() => act('remove')} />
)}>
{!connected_mechpad && (
<Box color="bad" textAlign="center">
No Pad Connected.
</Box>
) || (
<Button
fluid
icon="upload"
content="Launch"
textAlign="center"
onClick={() => act('launch')} />
)}
</Section>
);
};
export const MechpadConsole = (props, context) => {
const { act, data } = useBackend(context);
const {
mechpads = [],
selected_id,
} = data;
return (
<Window
width={475}
height={130}
resizable>
<Window.Content>
{mechpads.length === 0 && (
<NoticeBox>
No Pads Connected
</NoticeBox>
) || (
<Section>
<Flex minHeight="70px">
<Flex.Item width="140px" minHeight="70px">
{mechpads.map(mechpad => (
<Button
fluid
ellipsis
key={mechpad.name}
content={mechpad.name}
selected={selected_id === mechpad.id}
color="transparent"
onClick={() => act('select_pad', {
id: mechpad.id,
})} />
))}
</Flex.Item>
<Flex.Item minHeight="100%">
<Divider vertical />
</Flex.Item>
<Flex.Item grow={1} basis={0} minHeight="100%">
{selected_id && (
<MechpadControl />
) || (
<Box>
Please select a pad
</Box>
)}
</Flex.Item>
</Flex>
</Section>
)}
</Window.Content>
</Window>
);
};

View File

@@ -28,6 +28,8 @@ export const NtosMain = (props, context) => {
has_light,
light_on,
comp_light_color,
removable_media = [],
login = [],
} = data;
return (
<NtosWindow
@@ -56,6 +58,44 @@ export const NtosMain = (props, context) => {
</Button>
</Section>
)}
<Section
title="User Login"
buttons={(
<Button
icon="eject"
content="Eject ID"
disabled={!login.IDName}
onClick={() => act('PC_Eject_Disk', { name: "ID" })}
/>
)}>
<Table>
<Table.Row>
ID Name: {login.IDName}
</Table.Row>
<Table.Row>
Assignment: {login.IDJob}
</Table.Row>
</Table>
</Section>
{!!removable_media.length && (
<Section title="Media Eject">
<Table>
{removable_media.map(device => (
<Table.Row key={device}>
<Table.Cell>
<Button
fluid
color="transparent"
icon="eject"
content={device}
onClick={() => act('PC_Eject_Disk', { name: device })}
/>
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
)}
<Section title="Programs">
<Table>
{programs.map(program => (

View File

@@ -10,7 +10,7 @@ export const NtosRadar = (props, context) => {
width={800}
height={600}
theme="ntos">
<NtosRadarContent />
<NtosRadarContent sig_err={"Signal Lost"} />
</NtosWindow>
);
};
@@ -23,6 +23,7 @@ export const NtosRadarContent = (props, context) => {
target = [],
scanning,
} = data;
const { sig_err } = props;
return (
<Flex
direction={"row"}
@@ -89,7 +90,7 @@ export const NtosRadarContent = (props, context) => {
width={42}
fontSize="30px"
textAlign="center">
Signal Lost
{sig_err}
</NoticeBox>
)
: !!target.userot && (

View File

@@ -7,7 +7,7 @@ export const NtosRadarSyndicate = (props, context) => {
width={800}
height={600}
theme="syndicate">
<NtosRadarContent />
<NtosRadarContent sig_err={"Out of Range"} />
</NtosWindow>
);
};

View File

@@ -6,7 +6,7 @@
* @license MIT
*/
import { classes, isFalsy } from "common/react";
import { classes } from 'common/react';
import { vecScale, vecSubtract } from 'common/vector';
import DOMPurify from 'dompurify';
import { Component } from 'inferno';
@@ -241,13 +241,11 @@ const PaperSheetView = (props, context) => {
stamps,
backgroundColor,
readOnly,
...rest
} = props;
const readonly = !isFalsy(readOnly);
const stamp_list = stamps || [];
const text_html = {
__html: '<span class="paper-text">'
+ setInputReadonly(value, readonly)
+ setInputReadonly(value, readOnly)
+ '</span>',
};
return (
@@ -323,7 +321,12 @@ class PaperSheetStamper extends Component {
handleMouseClick(e) {
const pos = this.findStampPosition(e);
const { act, data } = useBackend(this.context);
act("stamp", { x: pos[0], y: pos[1], r: this.state.rotate });
const stamp_obj = {
x: pos[0], y: pos[1], r: this.state.rotate,
stamp_class: this.props.stamp_class,
stamp_icon_state: data.stamp_icon_state,
};
act("stamp", stamp_obj);
this.setState({ x: pos[0], y: pos[1] });
}
@@ -360,7 +363,7 @@ class PaperSheetStamper extends Component {
onMouseMove={this.handleMouseMove.bind(this)}
onwheel={this.handleWheel.bind(this)} {...rest}>
<PaperSheetView
readOnly={1}
readOnly
value={value}
stamps={stamp_list} />
<Stamp
@@ -593,7 +596,7 @@ export const PaperSheet = (props, context) => {
<PaperSheetView
value={text}
stamps={stamp_list}
readOnly={1} />
readOnly />
);
case 1:
return (

View File

@@ -0,0 +1,182 @@
import { ProgressBar, NumberInput, Button, Section, Box, Flex } from '../components';
import { useBackend } from '../backend';
import { Window } from '../layouts';
export const Photocopier = (props, context) => {
const { data } = useBackend(context);
const {
isAI,
has_toner,
has_item,
} = data;
return (
<Window
title="Photocopier"
width={240}
height={isAI ? 309 : 234}>
<Window.Content>
{has_toner ? (
<Toner />
) : (
<Section title="Toner">
<Box color="average">
No inserted toner cartridge.
</Box>
</Section>
)}
{has_item ? (
<Options />
) : (
<Section title="Options">
<Box color="average">
No inserted item.
</Box>
</Section>
)}
{!!isAI && (
<AIOptions />
)}
</Window.Content>
</Window>
);
};
const Toner = (props, context) => {
const { act, data } = useBackend(context);
const {
max_toner,
current_toner,
} = data;
const average_toner = max_toner * 0.66;
const bad_toner = max_toner * 0.33;
return (
<Section
title="Toner"
buttons={
<Button
disabled={!current_toner}
onClick={() => act('remove_toner')}
icon="eject">
Eject
</Button>
}>
<ProgressBar
ranges={{
good: [average_toner, max_toner],
average: [bad_toner, average_toner],
bad: [0, bad_toner],
}}
value={current_toner}
minValue={0}
maxValue={max_toner} />
</Section>
);
};
const Options = (props, context) => {
const { act, data } = useBackend(context);
const {
color_mode,
is_photo,
num_copies,
has_enough_toner,
} = data;
return (
<Section title="Options">
<Flex>
<Flex.Item
mt={0.4}
width={11}
color="label">
Make copies:
</Flex.Item>
<Flex.Item>
<NumberInput
animate
width={2.6}
height={1.65}
step={1}
stepPixelSize={8}
minValue={1}
maxValue={10}
value={num_copies}
onDrag={(e, value) => act('set_copies', {
num_copies: value,
})} />
</Flex.Item>
<Flex.Item>
<Button
ml={0.2}
icon="copy"
textAlign="center"
disabled={!has_enough_toner}
onClick={() => act('make_copy')}>
Copy
</Button>
</Flex.Item>
</Flex>
{!!is_photo && (
<Flex mt={0.5}>
<Flex.Item
mr={0.4}
width="50%">
<Button
fluid
textAlign="center"
selected={color_mode === "Greyscale"}
onClick={() => act('color_mode', {
mode: "Greyscale",
})}>
Greyscale
</Button>
</Flex.Item>
<Flex.Item
ml={0.4}
width="50%">
<Button
fluid
textAlign="center"
selected={color_mode === "Color"}
onClick={() => act('color_mode', {
mode: "Color",
})}>
Color
</Button>
</Flex.Item>
</Flex>
)}
<Button
mt={0.5}
textAlign="center"
icon="reply"
fluid
onClick={() => act('remove')}>
Remove item
</Button>
</Section>
);
};
const AIOptions = (props, context) => {
const { act, data } = useBackend(context);
const { can_AI_print } = data;
return (
<Section title="AI Options">
<Box>
<Button
fluid
icon="images"
textAlign="center"
disabled={!can_AI_print}
onClick={() => act('ai_photo')}>
Print photo from database
</Button>
</Box>
</Section>
);
};

View File

@@ -1,17 +1,25 @@
import { Fragment } from 'inferno';
import { useBackend } from '../backend';
import { Box, Button, LabeledList, Section } from '../components';
import { Box, Button, LabeledList, Section, NoticeBox } from '../components';
import { Window } from '../layouts';
export const Wires = (props, context) => {
const { act, data } = useBackend(context);
const { proper_name } = data;
const wires = data.wires || [];
const statuses = data.status || [];
return (
<Window
width={350}
height={150 + wires.length * 30}>
height={150
+ (wires.length * 30)
+ (!!proper_name && 30)}>
<Window.Content>
{(!!proper_name && (
<NoticeBox textAlign="center">
{proper_name} Wire Configuration
</NoticeBox>
))}
<Section>
<LabeledList>
{wires.map(wire => (

View File

@@ -5,29 +5,15 @@
*/
import { classes } from 'common/react';
import { computeBoxProps, computeBoxClassName } from '../components/Box';
/**
* Brings Layout__content DOM element back to focus.
*
* Commonly used to keep the content scrollable in IE.
*/
export const refocusLayout = () => {
// IE8: Focus method is seemingly fucked.
if (Byond.IS_LTE_IE8) {
return;
}
const element = document.getElementById('Layout__content');
if (element) {
element.focus();
}
};
import { computeBoxClassName, computeBoxProps } from '../components/Box';
import { addScrollableNode, removeScrollableNode } from '../events';
export const Layout = props => {
const {
className,
theme = 'nanotrasen',
children,
...rest
} = props;
return (
<div className={'theme-' + theme}>
@@ -35,7 +21,9 @@ export const Layout = props => {
className={classes([
'Layout',
className,
])}>
...computeBoxClassName(rest),
])}
{...computeBoxProps(rest)}>
{children}
</div>
</div>
@@ -51,7 +39,6 @@ const LayoutContent = props => {
} = props;
return (
<div
id="Layout__content"
className={classes([
'Layout__content',
scrollable && 'Layout__content--scrollable',
@@ -64,4 +51,9 @@ const LayoutContent = props => {
);
};
LayoutContent.defaultHooks = {
onComponentDidMount: node => addScrollableNode(node),
onComponentWillUnmount: node => removeScrollableNode(node),
};
Layout.Content = LayoutContent;

View File

@@ -4,6 +4,7 @@
* @license MIT
*/
export { Layout, refocusLayout } from './Layout';
export { Layout } from './Layout';
export { NtosWindow } from './NtosWindow';
export { Pane } from './Pane';
export { Window } from './Window';