I spent a ridiculous amount of time on this.

Arm order now works like:
input disk
input nuke code, press E
input time, press E
press ARM to activate
press ARM again to deactivate (with disk)
press C to clear code input while ready but not armed
This commit is contained in:
Rob Bailey
2019-11-25 11:50:52 +02:00
committed by Aleksej Komarov
parent e2a3b9dbd9
commit b4ded1ad00
13 changed files with 386 additions and 68 deletions
+7
View File
@@ -94,6 +94,13 @@
#define NUKESTATE_CORE_EXPOSED 1
#define NUKESTATE_CORE_REMOVED 0
#define NUKEUI_AWAIT_DISK 0
#define NUKEUI_AWAIT_CODE 1
#define NUKEUI_AWAIT_TIMER 2
#define NUKEUI_AWAIT_ARM 3
#define NUKEUI_TIMING 4
#define NUKEUI_EXPLODED 5
#define NUKE_OFF_LOCKED 0
#define NUKE_OFF_UNLOCKED 1
#define NUKE_ON_TIMING 2
@@ -8,15 +8,16 @@
resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF
ui_style = "nanotrasen"
ui_x = 500
ui_y = 600
ui_x = 350
ui_y = 442
var/timer_set = 90
var/default_timer_set = 90
var/minimum_timer_set = 90
var/maximum_timer_set = 3600
var/numeric_input = ""
var/ui_mode = NUKEUI_AWAIT_DISK
var/timing = FALSE
var/exploding = FALSE
var/exploded = FALSE
@@ -100,6 +101,8 @@
if(!user.transferItemToLoc(I, src))
return
auth = I
update_ui_mode()
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
add_fingerprint(user)
return
@@ -235,6 +238,29 @@
var/volume = (get_time_left() <= 20 ? 30 : 5)
playsound(loc, 'sound/items/timer.ogg', volume, FALSE)
/obj/machinery/nuclearbomb/proc/update_ui_mode()
if(exploded)
ui_mode = NUKEUI_EXPLODED
return
if(!auth)
ui_mode = NUKEUI_AWAIT_DISK
return
if(timing)
ui_mode = NUKEUI_TIMING
return
if(!safety)
ui_mode = NUKEUI_AWAIT_ARM
return
if(!yes_code)
ui_mode = NUKEUI_AWAIT_CODE
return
ui_mode = NUKEUI_AWAIT_TIMER
/obj/machinery/nuclearbomb/ui_interact(mob/user, ui_key="main", datum/tgui/ui=null, force_open=0, datum/tgui/master_ui=null, datum/ui_state/state=GLOB.default_state)
ui = SStgui.try_update_ui(user, src, ui_key, ui, force_open)
if(!ui)
@@ -245,104 +271,127 @@
/obj/machinery/nuclearbomb/ui_data(mob/user)
var/list/data = list()
data["disk_present"] = auth
data["code_approved"] = yes_code
var/first_status
if(auth)
if(yes_code)
first_status = timing ? "Func/Set" : "Functional"
else
first_status = "Auth S2."
var/hidden_code = (ui_mode == NUKEUI_AWAIT_CODE && numeric_input != "ERROR")
var/current_code = ""
if(hidden_code)
while(length(current_code) < length(numeric_input))
current_code = "[current_code]*"
else
if(timing)
first_status = "Set"
else
first_status = "Auth S1."
var/second_status = exploded ? "Warhead triggered, thanks for flying Nanotrasen" : (safety ? "Safe" : "Engaged")
current_code = numeric_input
while(length(current_code) < 5)
current_code = "[current_code]-"
var/first_status
var/second_status
switch(ui_mode)
if(NUKEUI_AWAIT_DISK)
first_status = "DEVICE LOCKED"
if(timing)
second_status = "TIME: [get_time_left()]"
else
second_status = "AWAIT DISK"
if(NUKEUI_AWAIT_CODE)
first_status = "INPUT CODE"
second_status = "CODE: [current_code]"
if(NUKEUI_AWAIT_TIMER)
first_status = "INPUT TIME"
second_status = "TIME: [current_code]"
if(NUKEUI_AWAIT_ARM)
first_status = "DEVICE READY"
second_status = "TIME: [get_time_left()]"
if(NUKEUI_TIMING)
first_status = "DEVICE ARMED"
second_status = "TIME: [get_time_left()]"
if(NUKEUI_EXPLODED)
first_status = "DEVICE DEPLOYED"
second_status = "THANK YOU"
data["status1"] = first_status
data["status2"] = second_status
data["anchored"] = anchored
data["safety"] = safety
data["timing"] = timing
data["time_left"] = get_time_left()
data["timer_set"] = timer_set
data["timer_is_not_default"] = timer_set != default_timer_set
data["timer_is_not_min"] = timer_set != minimum_timer_set
data["timer_is_not_max"] = timer_set != maximum_timer_set
var/message = "AUTH"
if(auth)
message = "[numeric_input]"
if(yes_code)
message = "*****"
data["message"] = message
return data
/obj/machinery/nuclearbomb/ui_act(action, params)
if(..())
return
playsound(src, "terminal_type", 20, FALSE)
switch(action)
if("eject_disk")
if(auth && auth.loc == src)
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
auth.forceMove(get_turf(src))
auth = null
. = TRUE
if("insert_disk")
if(!auth)
else
var/obj/item/I = usr.is_holding_item_of_type(/obj/item/disk/nuclear)
if(I && disk_check(I) && usr.transferItemToLoc(I, src))
playsound(src, 'sound/machines/terminal_insert_disc.ogg', 50, FALSE)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
auth = I
. = TRUE
update_ui_mode()
if("keypad")
if(auth)
var/digit = params["digit"]
switch(digit)
if("R")
if("C")
if(auth && ui_mode == NUKEUI_AWAIT_ARM)
set_safety()
yes_code = FALSE
playsound(src, 'sound/machines/nuke/confirm_beep.ogg', 50, FALSE)
update_ui_mode()
else
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
numeric_input = ""
yes_code = FALSE
. = TRUE
if("E")
if(numeric_input == r_code)
numeric_input = ""
yes_code = TRUE
. = TRUE
else
numeric_input = "ERROR"
switch(ui_mode)
if(NUKEUI_AWAIT_CODE)
if(numeric_input == r_code)
numeric_input = ""
yes_code = TRUE
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
. = TRUE
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
numeric_input = "ERROR"
if(NUKEUI_AWAIT_TIMER)
var/number_value = text2num(numeric_input)
if(number_value)
timer_set = CLAMP(number_value, minimum_timer_set, maximum_timer_set)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
set_safety()
. = TRUE
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
update_ui_mode()
if("0","1","2","3","4","5","6","7","8","9")
if(numeric_input != "ERROR")
numeric_input += digit
if(length(numeric_input) > 5)
numeric_input = "ERROR"
else
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
. = TRUE
if("timer")
if(auth && yes_code)
var/change = params["change"]
if(change == "reset")
timer_set = default_timer_set
else if(change == "decrease")
timer_set = max(minimum_timer_set, timer_set - 10)
else if(change == "increase")
timer_set = min(maximum_timer_set, timer_set + 10)
else if(change == "input")
var/user_input = input(usr, "Set time to detonation.", name) as null|num
if(!user_input)
return
var/N = text2num(user_input)
if(!N)
return
timer_set = CLAMP(N,minimum_timer_set,maximum_timer_set)
. = TRUE
if("safety")
if(auth && yes_code && !exploded)
set_safety()
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
if("arm")
if(auth && yes_code && !safety && !exploded)
playsound(src, 'sound/machines/nuke/confirm_beep.ogg', 50, FALSE)
set_active()
update_ui_mode()
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
if("anchor")
if(auth && yes_code)
playsound(src, 'sound/machines/nuke/general_beep.ogg', 50, FALSE)
set_anchor()
if("toggle_timer")
if(auth && yes_code && !safety && !exploded)
set_active()
else
playsound(src, 'sound/machines/nuke/angry_beep.ogg', 50, FALSE)
/obj/machinery/nuclearbomb/proc/set_anchor()
if(isinspace() && !anchored)
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,147 @@
import { act } from '../byond';
import { Box, Button, Grid, Flex, Icon } from '../components';
import { classes } from 'common/react';
// This ui is so many manual overrides and !important tags
// and hand made width sets that changing pretty much anything
// is going to require a lot of tweaking it get it looking correct again
// I'm sorry, but it looks bangin
const NukeKeypad = props => {
const { state } = props;
const { config, data } = state;
const { ref } = config;
const keypadKeys = [
["1", "4", "7", "C"],
["2", "5", "8", "0"],
["3", "6", "9", "E"],
];
return (
<Box
width="185px"
>
<Grid width="1px">
{keypadKeys.map(keyColumn => (
<Grid.Column key={keyColumn[0]}>
{keyColumn.map(key => (
<Button
fluid
bold
key={key}
mb={1}
content={key}
textAlign="center"
fontSize="40px"
lineHeight="50px"
width="55px"
className={classes([
"NuclearBomb__Button",
"NuclearBomb__Button--keypad",
"NuclearBomb__Button--" + key,
])}
onClick={() => act(ref, "keypad", {digit: key})}
/>
))}
</Grid.Column>
))}
</Grid>
</Box>
);
};
export const NuclearStatusPanel = props => {
const { state } = props;
const { config, data } = state;
const { ref } = config;
};
export const NuclearBomb = props => {
const { state } = props;
const { config, data } = state;
const { ref } = config;
const {
anchored,
disk_present,
status1,
status2,
} = data;
return (
<Box
m={1}
>
<Box
mb={1}
className="NuclearBomb__displayBox"
>
{status1}
</Box>
<Flex mb={1.5}>
<Flex.Item grow={1}>
<Box
className="NuclearBomb__displayBox"
>
{status2}
</Box>
</Flex.Item>
<Flex.Item>
<Button
icon="eject"
fontSize="24px"
lineHeight="23px"
textAlign="center"
width="43px"
ml={1}
mr="3px"
mt="3px"
className="NuclearBomb__Button NuclearBomb__Button--keypad"
onClick={() => act(ref, "eject_disk")}
/>
</Flex.Item>
</Flex>
<Flex ml="3px">
<Flex.Item>
<NukeKeypad state={state} />
</Flex.Item>
<Flex.Item ml={1} width="129px">
<Box>
<Button
fluid
bold
content="ARM"
textAlign="center"
fontSize="28px"
lineHeight="32px"
mb={1}
className="NuclearBomb__Button NuclearBomb__Button--C"
onClick={() => act(ref, "arm")}
/>
<Button
fluid
bold
content="ANCHOR"
textAlign="center"
fontSize="28px"
lineHeight="32px"
className="NuclearBomb__Button NuclearBomb__Button--E"
onClick={() => act(ref, "anchor")}
/>
<Box
width="100%"
textAlign="center"
color="#9C9987"
fontSize="80px"
>
<Icon
name="radiation"
/>
</Box>
<Box
width="100%"
height="80px"
className="NuclearBomb__NTIcon"
/>
</Box>
</Flex.Item>
</Flex>
</Box>
);
};
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+6
View File
@@ -44,6 +44,7 @@ import { NtosMain } from './interfaces/NtosMain';
import { NtosNetDownloader } from './interfaces/NtosNetDownloader';
import { NtosSupermatterMonitor } from './interfaces/NtosSupermatterMonitor';
import { NtosWrapper } from './interfaces/NtosWrapper';
import { NuclearBomb } from './interfaces/NuclearBomb';
import { OperatingComputer } from './interfaces/OperatingComputer';
import { OreRedemptionMachine } from './interfaces/OreRedemptionMachine';
import { PersonalCrafting } from './interfaces/PersonalCrafting';
@@ -264,6 +265,11 @@ const ROUTES = {
scrollable: true,
theme: 'ntos',
},
nuclear_bomb: {
component: () => NuclearBomb,
scrollable: false,
theme: 'retro',
},
ore_redemption_machine: {
component: () => OreRedemptionMachine,
scrollable: true,
@@ -0,0 +1,57 @@
@use '../base.scss';
@use '../colors.scss';
@use '../functions.scss' as *;
$color-danger: colors.bg(colors.$red) !default;
$color-caution: colors.bg(colors.$yellow) !default;
$background-beige: #E8E4C9;
.NuclearBomb__displayBox {
background-color: #002003;
border: 4px inset $background-beige;
color: #03e017;
font-size: 24px;
font-family: monospace;
padding: 6px;
}
.NuclearBomb__Button--keypad {
background-color: $background-beige;
border-color: $background-beige;
&:hover {
background-color: lighten($background-beige, 15%) !important;
border-color: lighten($background-beige, 15%) !important;
}
}
.NuclearBomb__Button--1 {
background-color: #D3CFB7 !important;
border-color:#D3CFB7 !important;
color: #A9A692 !important;
}
.NuclearBomb__Button--E {
background-color: $color-caution !important;
border-color: $color-caution !important;
&:hover {
background-color: lighten($color-caution, 15%) !important;
border-color: lighten($color-caution, 15%) !important;
}
}
.NuclearBomb__Button--C {
background-color: $color-danger !important;
border-color: $color-danger !important;
&:hover {
background-color: lighten($color-danger, 15%) !important;
border-color: lighten($color-danger, 15%) !important;
}
}
.NuclearBomb__NTIcon {
background-image: url('../assets/bg-nanotrasen.svg');
background-size: 70%;
background-position: center;
background-repeat: no-repeat;
}
+1
View File
@@ -23,6 +23,7 @@
@include meta.load-css('./components/NoticeBox.scss');
@include meta.load-css('./components/NtosHeader.scss');
@include meta.load-css('./components/NtosWrapper.scss');
@include meta.load-css('./components/NuclearBomb.scss');
@include meta.load-css('./components/NumberInput.scss');
@include meta.load-css('./components/ProgressBar.scss');
@include meta.load-css('./components/Section.scss');
@@ -0,0 +1,50 @@
@use 'sass:color';
@use 'sass:meta';
@use '../colors.scss' with (
$primary: #000000,
$fg-map-keys: (),
$bg-map-keys: (),
);
@use '../base.scss' with (
$color-bg: #E8E4C9,
$color-bg-grad-spread: 0%,
$border-radius: 0px,
);
// A fat warning to anyone who wants to use this: this only half works.
// It was made almost purely for the nuke ui, and requires a good amount of manual hacks to get it working as intended.
.theme-retro {
// Atomic classes
@include meta.load-css('../atomic/color.scss');
// Components
@include meta.load-css('../components/Button.scss', $with: (
'color-default': #E8E4C9,
'color-disabled': #363636,
'color-selected': #9d0808,
'color-caution': #be6209,
'color-danger': #9a9d00,
));
@include meta.load-css('../components/Layout.scss');
@include meta.load-css('../components/ProgressBar.scss', $with: (
'color-background': rgba(0, 0, 0, 0.5),
));
@include meta.load-css('../components/Section.scss');
@include meta.load-css('../components/TitleBar.scss', $with: (
'color-background': #585337,
));
.Button {
font-family: monospace;
color: #161613;
border-width: 8px;
border-style: outset;
border-color: #E8E4C9;
outline: 3px solid #161613;
}
.Layout__content {
background-image: none;
}
}
@@ -22,6 +22,7 @@ module.exports = (env = {}, argv) => {
path.resolve(__dirname, './styles/main.scss'),
path.resolve(__dirname, './styles/themes/ntos.scss'),
path.resolve(__dirname, './styles/themes/syndicate.scss'),
path.resolve(__dirname, './styles/themes/retro.scss'),
path.resolve(__dirname, './index.js'),
],
},