tgui: AI system integrity restorer (#49828)

* AI fixer UI

* Cleanup

* Polish
This commit is contained in:
Arkatos1
2020-03-09 22:12:13 -07:00
committed by GitHub
parent ff60448f0c
commit e9bc48632c
6 changed files with 148 additions and 167 deletions
+47 -72
View File
@@ -2,12 +2,16 @@
name = "\improper AI system integrity restorer"
desc = "Used with intelliCards containing nonfunctional AIs to restore them to working order."
req_access = list(ACCESS_CAPTAIN, ACCESS_ROBOTICS, ACCESS_HEADS)
var/mob/living/silicon/ai/occupier = null
var/active = 0
circuit = /obj/item/circuitboard/computer/aifixer
icon_keyboard = "tech_key"
icon_screen = "ai-fixer"
light_color = LIGHT_COLOR_PINK
ui_x = 370
ui_y = 360
/// Variable containing transferred AI
var/mob/living/silicon/ai/occupier
/// Variable dictating if we are in the process of restoring the occupier AI
var/restoring = FALSE
/obj/machinery/computer/aifixer/screwdriver_act(mob/living/user, obj/item/I)
if(occupier)
@@ -18,60 +22,45 @@
else
return ..()
/obj/machinery/computer/aifixer/ui_interact(mob/user)
. = ..()
/obj/machinery/computer/aifixer/ui_interact(mob/user, ui_key = "main", datum/tgui/ui = null, force_open = FALSE, \
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)
ui = new(user, src, ui_key, "ai_restorer", name, ui_x, ui_y, master_ui, state)
ui.open()
var/dat = ""
/obj/machinery/computer/aifixer/ui_data(mob/user)
var/list/data = list()
if (src.occupier)
var/laws
dat += "<h3>Stored AI: [src.occupier.name]</h3>"
dat += "<b>System integrity:</b> [(src.occupier.health+100)/2]%<br>"
data["ejectable"] = FALSE
data["AI_present"] = FALSE
data["error"] = null
if(!occupier)
data["error"] = "Please transfer an AI unit."
else
data["AI_present"] = TRUE
data["name"] = occupier.name
data["restoring"] = restoring
data["health"] = (occupier.health + 100) / 2
data["isDead"] = occupier.stat == DEAD
data["laws"] = occupier.laws.get_law_list(include_zeroth = 1)
if (src.occupier.laws.zeroth)
laws += "<b>0:</b> [src.occupier.laws.zeroth]<BR>"
return data
for (var/index = 1, index <= src.occupier.laws.hacked.len, index++)
var/law = src.occupier.laws.hacked[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
/obj/machinery/computer/aifixer/ui_act(action, params)
if(..())
return
if(!occupier)
restoring = FALSE
for (var/index = 1, index <= src.occupier.laws.ion.len, index++)
var/law = src.occupier.laws.ion[index]
if (length(law) > 0)
var/num = ionnum()
laws += "<b>[num]:</b> [law]<BR>"
var/number = 1
for (var/index = 1, index <= src.occupier.laws.inherent.len, index++)
var/law = src.occupier.laws.inherent[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
for (var/index = 1, index <= src.occupier.laws.supplied.len, index++)
var/law = src.occupier.laws.supplied[index]
if (length(law) > 0)
laws += "<b>[number]:</b> [law]<BR>"
number++
dat += "<b>Laws:</b><br>[laws]<br>"
if (src.occupier.stat == DEAD)
dat += "<span class='bad'>AI non-functional</span>"
else
dat += "<span class='good'>AI functional</span>"
if (!src.active)
dat += {"<br><br><A href='byond://?src=[REF(src)];fix=1'>Begin Reconstruction</A>"}
else
dat += "<br><br>Reconstruction in process, please wait.<br>"
dat += {"<br><A href='?src=[REF(user)];mach_close=computer'>Close</A>"}
var/datum/browser/popup = new(user, "computer", "AI System Integrity Restorer", 400, 500)
popup.set_content(dat)
popup.set_title_image(user.browse_rsc_icon(src.icon, src.icon_state))
popup.open()
return
switch(action)
if("PRG_beginReconstruction")
if(occupier?.health < 100)
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
restoring = TRUE
occupier.notify_ghost_cloning("Your core files are being restored!", source = src)
. = TRUE
/obj/machinery/computer/aifixer/proc/Fix()
use_power(1000)
@@ -89,38 +78,24 @@
/obj/machinery/computer/aifixer/process()
if(..())
if(active)
if(restoring)
var/oldstat = occupier.stat
active = Fix()
restoring = Fix()
if(oldstat != occupier.stat)
update_icon()
updateDialog()
/obj/machinery/computer/aifixer/Topic(href, href_list)
if(..())
return
if(href_list["fix"])
to_chat(usr, "<span class='notice'>Reconstruction in progress. This will take several minutes.</span>")
playsound(src, 'sound/machines/terminal_prompt_confirm.ogg', 25, FALSE)
active = TRUE
if(occupier)
var/mob/living/silicon/ai/A = occupier
A.notify_ghost_cloning("Your core files are being restored!", source = src)
add_fingerprint(usr)
updateUsrDialog()
/obj/machinery/computer/aifixer/update_overlays()
. = ..()
if(machine_stat & (NOPOWER|BROKEN))
return
if(active)
if(restoring)
. += "ai-fixer-on"
if (occupier)
switch (occupier.stat)
if (0)
if (CONSCIOUS)
. += "ai-fixer-full"
if (2)
if (UNCONSCIOUS)
. += "ai-fixer-404"
else
. += "ai-fixer-empty"
@@ -143,14 +118,14 @@
update_icon()
else //Uploading AI from terminal to card
if(occupier && !active)
if(occupier && !restoring)
to_chat(occupier, "<span class='notice'>You have been downloaded to a mobile storage device. Still no remote access.</span>")
to_chat(user, "<span class='notice'>Transfer successful</span>: [occupier.name] ([rand(1000,9999)].exe) removed from host terminal and stored within local memory.")
occupier.forceMove(card)
card.AI = occupier
occupier = null
update_icon()
else if (active)
else if (restoring)
to_chat(user, "<span class='alert'>ERROR: Reconstruction in progress.</span>")
else if (!occupier)
to_chat(user, "<span class='alert'>ERROR: Unable to locate artificial intelligence.</span>")
@@ -11,7 +11,7 @@
tgui_id = "ntos_ai_restorer"
ui_x = 370
ui_y = 400
/// Variable dictating if we are in the process of restoring the AI in the inserted intellicard
var/restoring = FALSE
/datum/computer_file/program/aidiag/proc/get_ai(cardcheck)
@@ -95,8 +95,10 @@
var/obj/item/aicard/aicard = get_ai(2)
data["ejectable"] = TRUE
data["AI_present"] = FALSE
data["error"] = null
if(!aicard)
data["nocard"] = TRUE
data["error"] = "Please insert an intelliCard."
else
if(!AI)
@@ -106,12 +108,12 @@
if(cardhold.flush)
data["error"] = "Flush in progress"
else
data["AI_present"] = TRUE
data["name"] = AI.name
data["restoring"] = restoring
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
data["health"] = (AI.health + 100) / 2
data["isDead"] = AI.stat == DEAD
data["ai_laws"] = AI.laws.get_law_list(include_zeroth = 1)
data["laws"] = AI.laws.get_law_list(include_zeroth = 1)
return data
@@ -0,0 +1,87 @@
import { Fragment } from 'inferno';
import { useBackend } from "../backend";
import { Section, Box, Button, NoticeBox, ProgressBar, LabeledList } from "../components";
export const AiRestorer = props => {
const { act, data } = useBackend(props);
const {
AI_present,
error,
name,
laws,
isDead,
restoring,
health,
ejectable,
} = data;
return (
<Fragment>
{error && (
<NoticeBox textAlign="center">
{error}
</NoticeBox>
)}
{!!ejectable && (
<Button
fluid
icon="eject"
content={AI_present ? name : "----------"}
disabled={!AI_present}
onClick={() => act('PRG_eject')}
/>
)}
{!!AI_present && (
<Section
title={ejectable ? "System Status" : name}
buttons={(
<Box
inline
bold
color={isDead ? 'bad' : 'good'}>
{isDead ? "Nonfunctional" : "Functional"}
</Box>
)}>
<LabeledList>
<LabeledList.Item label="Integrity">
<ProgressBar
value={health}
minValue={0}
maxValue={100}
ranges={{
good: [70, Infinity],
average: [50, 70],
bad: [-Infinity, 50],
}} />
</LabeledList.Item>
</LabeledList>
{!!restoring && (
<Box
bold
textAlign="center"
fontSize="20px"
color="good"
mt={1}>
RECONSTRUCTION IN PROGRESS
</Box>
)}
<Button
fluid
icon="plus"
content="Begin Reconstruction"
disabled={restoring}
mt={1}
onClick={() => act('PRG_beginReconstruction')}
/>
<Section title="Laws" level={2}>
{laws.map(law => (
<Box key={law} className="candystripe">
{law}
</Box>
))}
</Section>
</Section>
)}
</Fragment>
);
};
@@ -1,87 +0,0 @@
import { Section, Box, Button, NoticeBox, ProgressBar, LabeledList } from "../components";
import { useBackend } from "../backend";
import { Fragment } from "inferno";
export const NtosAiRestorer = props => {
const { act, data } = useBackend(props);
const {
nocard,
error,
name,
ai_laws,
isDead,
restoring,
} = data;
return (
<Fragment>
{error && (
<NoticeBox>
{error}
</NoticeBox>
)}
<Section>
<Button
fluid
icon="eject"
content={name || "----------"}
disabled={!name}
onClick={() => act('PRG_eject')}
/>
{!nocard && (
<Section
title="System Status"
level={2}
buttons={(
<Box
inline
bold
color={isDead ? 'bad' : 'good'}>
{isDead ? "Nonfunctional" : "Functional"}
</Box>
)}>
<LabeledList>
<LabeledList.Item label="Integrity">
<ProgressBar
value={100}
minValue={0}
maxValue={100}
ranges={{
good: [70, Infinity],
average: [50, 70],
bad: [-Infinity, 50],
}} />
</LabeledList.Item>
</LabeledList>
{!!restoring && (
<Box
bold
textAlign="center"
fontSize="20px"
color="good"
mt={1}>
RECONSTRUCTION IN PROGRESS
</Box>
)}
<Button
fluid
icon="plus"
content="Begin Reconstruction"
disabled={restoring}
mt={1}
onClick={() => act('PRG_beginReconstruction')}
/>
<Section title="laws" level={3}>
{ai_laws.map(law => (
<Box key={law} className="candystripe">
{law}
</Box>
))}
</Section>
</Section>
)}
</Section>
</Fragment>
);
};
File diff suppressed because one or more lines are too long
+7 -3
View File
@@ -1,6 +1,7 @@
import { Achievements } from './interfaces/Achievements';
import { AiAirlock } from './interfaces/AiAirlock';
import { AirAlarm } from './interfaces/AirAlarm';
import { AiRestorer } from './interfaces/AiRestorer';
import { AirlockElectronics } from './interfaces/AirlockElectronics';
import { Apc } from './interfaces/Apc';
import { AtmosAlertConsole } from './interfaces/AtmosAlertConsole';
@@ -68,7 +69,6 @@ import { NaniteProgrammer } from './interfaces/NaniteProgrammer';
import { NaniteRemote } from './interfaces/NaniteRemote';
import { NotificationPreferences } from './interfaces/NotificationPreferences';
import { NtnetRelay } from './interfaces/NtnetRelay';
import { NtosAiRestorer } from './interfaces/NtosAiRestorer';
import { NtosArcade } from './interfaces/NtosArcade';
import { NtosCard } from './interfaces/NtosCard';
import { NtosConfiguration } from './interfaces/NtosConfiguration';
@@ -113,6 +113,7 @@ import { SpaceHeater } from './interfaces/SpaceHeater';
import { SpawnersMenu } from './interfaces/SpawnersMenu';
import { StationAlertConsole } from './interfaces/StationAlertConsole';
import { SuitStorageUnit } from './interfaces/SuitStorageUnit';
import { SyndContractor } from './interfaces/SyndContractor';
import { Tank } from './interfaces/Tank';
import { TankDispenser } from './interfaces/TankDispenser';
import { Teleporter } from './interfaces/Teleporter';
@@ -124,7 +125,6 @@ import { Uplink } from './interfaces/Uplink';
import { VaultController } from './interfaces/VaultController';
import { Vending } from './interfaces/Vending';
import { Wires } from './interfaces/Wires';
import { SyndContractor } from './interfaces/SyndContractor';
const ROUTES = {
achievements: {
@@ -139,6 +139,10 @@ const ROUTES = {
component: () => AirAlarm,
scrollable: true,
},
ai_restorer: {
component: () => AiRestorer,
scrollable: true,
},
airlock_electronics: {
component: () => AirlockElectronics,
scrollable: false,
@@ -419,7 +423,7 @@ const ROUTES = {
scrollable: false,
},
ntos_ai_restorer: {
component: () => NtosAiRestorer,
component: () => AiRestorer,
wrapper: () => NtosWrapper,
scrollable: true,
theme: 'ntos',