[MIRROR] Replace most legacy robot interfaces with a unified interface (#9323)

Co-authored-by: ShadowLarkens <shadowlarkens@gmail.com>
This commit is contained in:
CHOMPStation2StaffMirrorBot
2024-10-26 08:40:26 -07:00
committed by GitHub
parent a1a4071f70
commit c85c19567e
10 changed files with 733 additions and 158 deletions

View File

@@ -158,6 +158,7 @@
return 0
R.emag_items = 1
R.robotact.update_static_data_for_all_viewers()
return 1
/obj/item/borg/upgrade/basic/language

View File

@@ -18,13 +18,11 @@
set hidden = 1
toggle_module(module)
/mob/living/silicon/robot/proc/uneq_active()
if(isnull(module_active))
/mob/living/silicon/robot/proc/uneq_specific(obj/item/I)
if(!istype(I))
return
var/obj/item/I = module_active
for(var/datum/action/A as anything in I.actions)
A.Remove(src)
if(module_state_1 == module_active)
if(module_state_1 == I)
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode &= ~module_state_1:sight_mode
if (client)
@@ -34,30 +32,46 @@
module_state_1:loc = module //So it can be used again later
module_state_1 = null
inv1.icon_state = "inv1"
else if(module_state_2 == module_active)
else if(module_state_2 == I)
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode &= ~module_state_2:sight_mode
if (client)
client.screen -= module_state_2
contents -= module_state_2
module_active = null
module_state_2:loc = module
module_state_2:loc = module //So it can be used again later
module_state_2 = null
inv2.icon_state = "inv2"
else if(module_state_3 == module_active)
else if(module_state_3 == I)
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode &= ~module_state_3:sight_mode
if (client)
client.screen -= module_state_3
contents -= module_state_3
module_active = null
module_state_3:loc = module
module_state_3:loc = module //So it can be used again later
module_state_3 = null
inv3.icon_state = "inv3"
else
return
for(var/datum/action/A as anything in I.actions)
A.Remove(src)
after_equip()
update_icon()
hud_used.update_robot_modules_display()
/mob/living/silicon/robot/proc/uneq_active()
if(isnull(module_active))
return
var/obj/item/I = module_active
for(var/datum/action/A as anything in I.actions)
A.Remove(src)
uneq_specific(I)
/mob/living/silicon/robot/proc/uneq_all()
module_active = null
@@ -100,6 +114,17 @@
after_equip()
update_icon()
// Just used for pretty display in TGUI
/mob/living/silicon/robot/proc/get_slot_from_module(obj/item/I)
if(module_state_1 == I)
return 1
else if(module_state_2 == I)
return 2
else if(module_state_3 == I)
return 3
else
return 0
/mob/living/silicon/robot/proc/activated(obj/item/O)
if(module_state_1 == O)
return 1

View File

@@ -135,6 +135,7 @@
spark_system = new /datum/effect/effect/system/spark_spread()
spark_system.set_up(5, 0, src)
spark_system.attach(src)
robotact = new(src)
add_language("Robot Talk", 1)
add_language(LANGUAGE_GALCOM, 1)
@@ -318,6 +319,7 @@
revert_shell() // To get it out of the GLOB list.
qdel(wires)
wires = null
QDEL_NULL(robotact)
return ..()
// CONTINUE CODING HERE
@@ -379,6 +381,7 @@
updatename()
hud_used.update_robot_modules_display()
notify_ai(ROBOT_NOTIFICATION_NEW_MODULE, module.name)
robotact?.update_static_data_for_all_viewers()
/mob/living/silicon/robot/proc/update_braintype()
if(istype(mmi, /obj/item/mmi/digital/posibrain))
@@ -465,17 +468,6 @@
sprite_datum.handle_extra_customization(src)
/mob/living/silicon/robot/proc/self_diagnosis()
if(!is_component_functioning("diagnosis unit"))
return null
var/dat = "<HEAD><TITLE>[src.name] Self-Diagnosis Report</TITLE></HEAD><BODY>\n"
for (var/V in components)
var/datum/robot_component/C = components[V]
dat += span_bold("[C.name]") + "<br><table><tr><td>Brute Damage:</td><td>[C.brute_damage]</td></tr><tr><td>Electronics Damage:</td><td>[C.electronics_damage]</td></tr><tr><td>Powered:</td><td>[(!C.idle_usage || C.is_powered()) ? "Yes" : "No"]</td></tr><tr><td>Toggled:</td><td>[ C.toggled ? "Yes" : "No"]</td></table><br>"
return dat
/mob/living/silicon/robot/verb/toggle_lights()
set category = "Abilities.Silicon"
set name = "Toggle Lights"
@@ -485,44 +477,6 @@
handle_light()
update_icon()
/mob/living/silicon/robot/verb/self_diagnosis_verb()
set category = "Abilities.Silicon"
set name = "Self Diagnosis"
if(!is_component_functioning("diagnosis unit"))
to_chat(src, span_red("Your self-diagnosis component isn't functioning."))
var/datum/robot_component/CO = get_component("diagnosis unit")
if (!cell_use_power(CO.active_usage))
to_chat(src, span_red("Low Power."))
var/dat = self_diagnosis()
src << browse(dat, "window=robotdiagnosis")
/mob/living/silicon/robot/verb/toggle_component()
set category = "Abilities.Silicon"
set name = "Toggle Component"
set desc = "Toggle a component, conserving power."
var/list/installed_components = list()
for(var/V in components)
if(V == "power cell") continue
var/datum/robot_component/C = components[V]
if(C.installed)
installed_components += V
var/toggle = tgui_input_list(src, "Which component do you want to toggle?", "Toggle Component", installed_components)
if(!toggle)
return
var/datum/robot_component/C = components[toggle]
if(C.toggled)
C.toggled = 0
to_chat(src, span_red("You disable [C.name]."))
else
C.toggled = 1
to_chat(src, span_red("You enable [C.name]."))
/mob/living/silicon/robot/verb/spark_plug() //So you can still sparkle on demand without violence.
set category = "Abilities.Silicon"
set name = "Emit Sparks"
@@ -858,6 +812,7 @@
module = null
updatename("Default")
has_recoloured = FALSE
robotact?.update_static_data_for_all_viewers()
/mob/living/silicon/robot/proc/ColorMate()
set name = "Recolour Module"
@@ -1101,42 +1056,7 @@
add_overlay(open_overlay)
/mob/living/silicon/robot/proc/installed_modules()
if(weapon_lock)
to_chat(src, span_filter_warning("" + span_red("Weapon lock active, unable to use modules! Count:[weaponlock_time]") + ""))
return
if(!module)
pick_module()
return
var/dat = "<HEAD><TITLE>Modules</TITLE></HEAD><BODY>\n"
dat += {"
<B>Activated Modules</B>
<BR>
Module 1: [module_state_1 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_1]>[module_state_1]<A>" : "No Module"]<BR>
Module 2: [module_state_2 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_2]>[module_state_2]<A>" : "No Module"]<BR>
Module 3: [module_state_3 ? "<A HREF=?src=\ref[src];mod=\ref[module_state_3]>[module_state_3]<A>" : "No Module"]<BR>
<BR>
<B>Installed Modules</B><BR><BR>"}
for (var/obj in module.modules)
if (!obj)
dat += span_bold("Resource depleted") + "<BR>"
else if(activated(obj))
dat += text("[obj]: <B>Activated</B><BR>")
else
dat += text("[obj]: <A HREF=?src=\ref[src];act=\ref[obj]>Activate</A><BR>")
if (emagged || emag_items)
for (var/obj in module.emag)
if (!obj)
dat += span_bold("Resource depleted") + "<BR>"
else if(activated(obj))
dat += text("[obj]: <B>Activated</B><BR>")
else
dat += text("[obj]: <A HREF=?src=\ref[src];act=\ref[obj]>Activate</A><BR>")
src << browse(dat, "window=robotmod")
robotact.tgui_interact(src)
/mob/living/silicon/robot/Topic(href, href_list)
if(..())
@@ -1150,69 +1070,6 @@
subsystem_alarm_monitor()
return 1
if (href_list["mod"])
var/obj/item/O = locate(href_list["mod"])
if (istype(O) && (O.loc == src))
O.attack_self(src)
return 1
if (href_list["act"])
var/obj/item/O = locate(href_list["act"])
if (!istype(O))
return 1
if(!((O in src.module.modules) || (O in src.module.emag)))
return 1
if(activated(O))
to_chat(src, span_filter_notice("Already activated."))
return 1
if(!module_state_1)
module_state_1 = O
O.hud_layerise()
O.equipped_robot()
contents += O
if(istype(module_state_1,/obj/item/borg/sight))
sight_mode |= module_state_1:sight_mode
else if(!module_state_2)
module_state_2 = O
O.hud_layerise()
O.equipped_robot()
contents += O
if(istype(module_state_2,/obj/item/borg/sight))
sight_mode |= module_state_2:sight_mode
else if(!module_state_3)
module_state_3 = O
O.hud_layerise()
O.equipped_robot()
contents += O
if(istype(module_state_3,/obj/item/borg/sight))
sight_mode |= module_state_3:sight_mode
else
to_chat(src, span_filter_notice("You need to disable a module first!"))
installed_modules()
return 1
if (href_list["deact"])
var/obj/item/O = locate(href_list["deact"])
if(activated(O))
if(module_state_1 == O)
module_state_1 = null
contents -= O
else if(module_state_2 == O)
module_state_2 = null
contents -= O
else if(module_state_3 == O)
module_state_3 = null
contents -= O
else
to_chat(src, span_filter_notice("Module isn't activated."))
else
to_chat(src, span_filter_notice("Module isn't activated."))
installed_modules()
return 1
return
/mob/living/silicon/robot/proc/radio_menu()
radio.interact(src)//Just use the radio's Topic() instead of bullshit special-snowflake code
@@ -1492,6 +1349,7 @@
sleep(6)
if(prob(50))
emagged = 1
robotact.update_static_data_for_all_viewers()
lawupdate = 0
disconnect_from_ai()
to_chat(user, span_filter_notice("You emag [src]'s interface."))
@@ -1783,3 +1641,12 @@
return (has_basic_upgrade(given_type) || has_advanced_upgrade(given_type) || has_restricted_upgrade(given_type) || has_no_prod_upgrade(given_type))
#undef CYBORG_POWER_USAGE_MULTIPLIER
/mob/living/silicon/robot/vv_edit_var(var_name, var_value)
switch(var_name)
if(NAMEOF(src, emagged))
robotact?.update_static_data_for_all_viewers()
if(NAMEOF(src, emag_items))
robotact?.update_static_data_for_all_viewers()
. = ..()

View File

@@ -0,0 +1,180 @@
/mob/living/silicon/robot
var/datum/tgui_module/robot_ui/robotact
// Major Control UI for all things robots can do.
/datum/tgui_module/robot_ui
name = "Robotact"
tgui_id = "Robotact"
/datum/tgui_module/robot_ui/tgui_state(mob/user)
return GLOB.tgui_self_state
/datum/tgui_module/robot_ui/tgui_static_data()
var/list/data = ..()
var/mob/living/silicon/robot/R = host
if(!R.module)
return data
var/list/modules = list()
for(var/obj/item/I as anything in R.module.modules)
if(!I)
continue
UNTYPED_LIST_ADD(modules, list(
"ref" = REF(I),
"name" = "[I]",
"icon" = "[I.icon]",
"icon_state" = "[I.icon_state]",
))
data["modules_static"] = modules
var/list/emag_modules = list()
if(R.emagged || R.emag_items)
for(var/obj/item/I as anything in R.module.emag)
if(!I)
continue
UNTYPED_LIST_ADD(emag_modules, list(
"ref" = REF(I),
"name" = "[I.name]",
"icon" = "[I.icon]",
"icon_state" = "[I.icon_state]",
))
data["emag_modules_static"] = emag_modules
return data
/datum/tgui_module/robot_ui/tgui_data()
var/list/data = ..()
var/mob/living/silicon/robot/R = host
data["module_name"] = R.module ? "[R.module]" : null
if(!R.module)
return data
data["name"] = R.name
data["ai"] = "[R.connected_ai]"
data["charge"] = R.cell?.charge
data["max_charge"] = R.cell?.maxcharge
data["health"] = R.health
data["max_health"] = R.getMaxHealth()
data["weapon_lock"] = R.weapon_lock
var/list/modules = list()
for(var/obj/item/I as anything in R.module.modules)
if(!I)
continue
LAZYSET(modules, REF(I), R.get_slot_from_module(I))
data["modules"] = modules
var/list/emag_modules = list()
if(R.emagged || R.emag_items)
for(var/obj/item/I as anything in R.module.emag)
if(!I)
continue
LAZYSET(emag_modules, REF(I), R.get_slot_from_module(I))
data["emag_modules"] = emag_modules
var/diagnosis_functional = R.is_component_functioning("diagnosis unit")
data["diag_functional"] = diagnosis_functional
var/list/components = list()
for(var/V in R.components)
var/datum/robot_component/comp = R.components[V]
UNTYPED_LIST_ADD(components, list(
"key" = V,
"name" = "[comp]",
"brute_damage" = comp.brute_damage,
"electronics_damage" = diagnosis_functional ? comp.electronics_damage : -1,
"max_damage" = diagnosis_functional ? comp.max_damage : -1,
"idle_usage" = diagnosis_functional ? comp.idle_usage : -1,
"is_powered" = diagnosis_functional ? comp.is_powered() : 0,
"toggled" = comp.toggled,
))
data["components"] = components
return data
/datum/tgui_module/robot_ui/tgui_act(action, params)
. = ..()
if(.)
return
var/mob/living/silicon/robot/R = host
switch(action)
if("select_module")
R.pick_module()
. = TRUE
if("toggle_component")
var/component = params["component"]
var/datum/robot_component/C = LAZYACCESS(R.components, component)
if(istype(C))
C.toggled = !C.toggled
if(C.toggled)
to_chat(usr, span_notice("You enable [C]."))
else
to_chat(usr, span_warning("You disable [C]."))
. = TRUE
if("toggle_module")
if(R.weapon_lock)
to_chat(usr, span_danger("Error: Modules locked."))
return
var/obj/item/module = locate(params["ref"])
if(istype(module))
if(R.activated(module))
R.uneq_specific(module)
else
R.activate_module(module)
. = TRUE
if("activate_module")
var/obj/item/module = locate(params["ref"])
if(istype(module) && module.loc == R)
module.attack_self(R)
. = TRUE
// Quick actions
if("quick_action_comm")
R.communicator?.attack_self(R)
. = TRUE
if("quick_action_pda")
R.rbPDA?.tgui_interact(R)
. = TRUE
if("quick_action_crew_manifest")
R.subsystem_crew_manifest()
. = TRUE
if("quick_action_law_manager")
R.subsystem_law_manager()
. = TRUE
if("quick_action_alarm_monitoring")
R.subsystem_alarm_monitor()
. = TRUE
if("quick_action_power_monitoring")
R.subsystem_power_monitor()
. = TRUE
if("quick_action_take_image")
R.take_image()
. = TRUE
if("quick_action_view_images")
R.view_images()
. = TRUE
if("quick_action_delete_images")
R.delete_images()
. = TRUE
if("quick_action_flashlight")
R.toggle_lights()
. = TRUE
if("quick_action_sensors")
R.sensor_mode()
. = TRUE
if("quick_action_sparks")
R.spark_plug()
. = TRUE

View File

@@ -0,0 +1,92 @@
import { toTitleCase } from 'common/string';
import { useBackend } from 'tgui/backend';
import {
Box,
Button,
FitText,
LabeledList,
NoticeBox,
ProgressBar,
Section,
Stack,
} from 'tgui-core/components';
import { Data } from './types';
export const ComponentView = (props) => {
const { act, data } = useBackend<Data>();
const { diag_functional, components } = data;
if (components.length) {
components.sort((a, b) => a.name.localeCompare(b.name));
return (
<Stack wrap align="flex-start" justify="space-between">
{components.map((mod) => (
<Stack.Item key={mod.key} basis="24%" grow ml={1}>
<Section
title={
<FitText maxWidth={140} maxFontSize={18}>
{toTitleCase(mod.name)}
</FitText>
}
height={12}
mt={1}
buttons={
<Button
icon="power-off"
disabled={mod.name === 'power cell'}
selected={mod.toggled}
onClick={() =>
act('toggle_component', { component: mod.key })
}
/>
}
>
{!!diag_functional && (
<LabeledList>
<LabeledList.Item label="Health">
<ProgressBar
mb={1}
value={
mod.max_damage -
(mod.brute_damage + mod.electronics_damage)
}
maxValue={mod.max_damage}
>
{mod.max_damage -
(mod.brute_damage + mod.electronics_damage)}{' '}
/ {mod.max_damage}
</ProgressBar>
</LabeledList.Item>
</LabeledList>
)}
{diag_functional ? (
<LabeledList>
<LabeledList.Item label="Brute Damage">
{mod.brute_damage}
</LabeledList.Item>
<LabeledList.Item label="Elect Damage">
{mod.electronics_damage}
</LabeledList.Item>
<LabeledList.Item label="Powered">
{mod.is_powered || !mod.idle_usage ? (
<Box color="good">Yes</Box>
) : (
<Box color="bad">No</Box>
)}
</LabeledList.Item>
</LabeledList>
) : (
<NoticeBox danger>DIAGNOSIS UNAVAILABLE</NoticeBox>
)}
</Section>
</Stack.Item>
))}
</Stack>
);
}
return <NoticeBox danger>Diagnosis Module Offline</NoticeBox>;
};

View File

@@ -0,0 +1,71 @@
import { useBackend } from 'tgui/backend';
import {
Box,
ImageButton,
NoticeBox,
Section,
Stack,
} from 'tgui-core/components';
import { Data, Module as ModuleData } from './types';
export const Modules = (props) => {
const { act, data } = useBackend<Data>();
return (
<Stack fill vertical>
<Stack.Item grow>
<Section
title="Modules"
fill
scrollable
height="93%"
buttons={
data.weapon_lock ? (
<NoticeBox danger>Modules Locked</NoticeBox>
) : null
}
>
<Stack wrap align="space-between" justify="space-between">
{data.modules_static.map((mod) => (
<Stack.Item key={mod.ref} basis="32%" grow mt={1} ml={1}>
<Module mod={mod} activated={data.modules[mod.ref]} />
</Stack.Item>
))}
{data.emag_modules_static.map((mod) => (
<Stack.Item key={mod.ref} basis="32%" grow mt={1} ml={1}>
<Module mod={mod} activated={data.emag_modules[mod.ref]} />
</Stack.Item>
))}
</Stack>
</Section>
</Stack.Item>
</Stack>
);
};
const Module = (props: { mod: ModuleData; activated: number }) => {
const { act } = useBackend();
const { mod, activated } = props;
return (
<ImageButton
dmIcon={mod.icon}
dmIconState={mod.icon_state}
selected={activated}
imageSize={128}
fluid
onClick={() => act('toggle_module', { ref: mod.ref })}
onRightClick={() => act('activate_module', { ref: mod.ref })}
tooltip={activated ? 'Right click to trigger' : ''}
tooltipPosition="bottom-end"
position="relative"
>
{!!activated && (
<Box position="absolute" top={0.5} right={0.5} fontSize={1.5}>
{activated}
</Box>
)}
<Box>{mod.name}</Box>
</ImageButton>
);
};

View File

@@ -0,0 +1,205 @@
import { useBackend } from 'tgui/backend';
import {
Box,
ImageButton,
LabeledList,
NoticeBox,
ProgressBar,
Section,
Stack,
} from 'tgui-core/components';
import { Data } from './types';
const quick_actions: {
name: string;
icon: string;
icon_state: string;
eventName: string;
}[] = [
{
name: 'Communicator',
icon: 'icons/obj/device.dmi',
icon_state: 'communicator',
eventName: 'quick_action_comm',
},
{
name: 'PDA',
icon: 'icons/obj/pda_vr.dmi',
icon_state: 'pda',
eventName: 'quick_action_pda',
},
{
name: 'Crew Manifest',
icon: 'icons/obj/pda_vr.dmi',
icon_state: 'cart',
eventName: 'quick_action_crew_manifest',
},
{
name: 'Law Manager',
icon: 'icons/mob/screen1_robot.dmi',
icon_state: 'harm',
eventName: 'quick_action_law_manager',
},
{
name: 'Alarm Monitor',
icon: 'icons/obj/modular_console.dmi',
icon_state: 'alert-green',
eventName: 'quick_action_alarm_monitoring',
},
{
name: 'Power Monitor',
icon: 'icons/obj/modular_console.dmi',
icon_state: 'power_monitor',
eventName: 'quick_action_power_monitoring',
},
{
name: 'Take Image',
icon: 'icons/obj/items.dmi',
icon_state: 'camera',
eventName: 'quick_action_take_image',
},
{
name: 'View Images',
icon: 'icons/obj/items.dmi',
icon_state: 'film',
eventName: 'quick_action_view_images',
},
{
name: 'Delete Images',
icon: 'icons/obj/items.dmi',
icon_state: 'photo',
eventName: 'quick_action_delete_images',
},
{
name: 'Toggle Lights',
icon: 'icons/obj/lighting.dmi',
icon_state: 'flashlight',
eventName: 'quick_action_flashlight',
},
{
name: 'Toggle Sensor Augmentation',
icon: 'icons/inventory/eyes/item.dmi',
icon_state: 'sec_hud',
eventName: 'quick_action_sensors',
},
{
name: 'Emit Sparks',
icon: 'icons/effects/effects.dmi',
icon_state: 'sparks',
eventName: 'quick_action_sparks',
},
];
export const StatusScreen = (props) => {
const { act } = useBackend<Data>();
return (
<Stack vertical fill height="94%">
<Stack.Item basis="20%">
<Stack fill>
<Stack.Item grow>
<Configuration />
</Stack.Item>
<Stack.Item grow>
<Status />
</Stack.Item>
</Stack>
</Stack.Item>
<Stack.Item grow>
<Section title="Quick Actions" fill scrollable>
<Stack>
<Stack.Item grow>
{quick_actions
.slice(0, quick_actions.length / 2)
.map((action) => (
<ImageButton
key={action.name}
dmIcon={action.icon}
dmIconState={action.icon_state}
imageSize={48}
onClick={() => act(action.eventName)}
fluid
>
{action.name}
</ImageButton>
))}
</Stack.Item>
<Stack.Item grow>
{quick_actions.slice(quick_actions.length / 2).map((action) => (
<ImageButton
key={action.name}
dmIcon={action.icon}
dmIconState={action.icon_state}
imageSize={48}
onClick={() => act(action.eventName)}
fluid
>
{action.name}
</ImageButton>
))}
</Stack.Item>
</Stack>
</Section>
</Stack.Item>
</Stack>
);
};
const Configuration = (props) => {
const { data } = useBackend<Data>();
const { name, module_name, ai } = data;
return (
<Section title="Configuration" fill>
<LabeledList>
<LabeledList.Item label="Unit">{name}</LabeledList.Item>
<LabeledList.Item label="Type">{module_name}</LabeledList.Item>
<LabeledList.Item label="AI">
{ai ? <Box color="good">{ai}</Box> : <Box color="average">None</Box>}
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const Status = (props) => {
const { data } = useBackend<Data>();
const { charge, max_charge, health, max_health } = data;
return (
<Section title="Status" fill>
<LabeledList>
<LabeledList.Item label="Charge">
{charge && max_charge ? (
<ProgressBar
value={charge}
maxValue={max_charge}
ranges={{
good: [max_charge * 0.75, Number.POSITIVE_INFINITY],
average: [max_charge * 0.3, max_charge * 0.75],
bad: [Number.NEGATIVE_INFINITY, max_charge * 0.3],
}}
>
{charge} / {max_charge}
</ProgressBar>
) : (
<NoticeBox danger>NO CELL INSTALLED</NoticeBox>
)}
</LabeledList.Item>
<LabeledList.Item label="Chassis Integrity">
<ProgressBar
value={health}
maxValue={max_health}
ranges={{
good: [max_health * 0.75, Number.POSITIVE_INFINITY],
average: [max_health * 0.3, max_health * 0.75],
bad: [Number.NEGATIVE_INFINITY, max_health * 0.3],
}}
/>
</LabeledList.Item>
</LabeledList>
</Section>
);
};

View File

@@ -0,0 +1,90 @@
import { useState } from 'react';
import { useBackend } from 'tgui/backend';
import { Window } from 'tgui/layouts';
import { Button, NoticeBox, Stack, Tabs } from 'tgui-core/components';
import { ComponentView } from './Diagnostics';
import { Modules } from './Modules';
import { StatusScreen } from './StatusScreen';
import { Data } from './types';
export const Robotact = (props) => {
const { act, data } = useBackend<Data>();
let content = <NoModuleWarning />;
if (data.module_name) {
content = <MainScreen />;
}
return (
<Window width={800} height={600} theme="ntos">
<Window.Content>{content}</Window.Content>
</Window>
);
};
const NoModuleWarning = (props) => {
const { act } = useBackend();
return (
<Stack fill align="center" justify="center" vertical>
<Stack.Item>
<NoticeBox danger fontSize={2} style={{ borderRadius: '6px' }} p={4}>
No Module Activated
</NoticeBox>
</Stack.Item>
<Stack.Item>
<Button icon="eyedropper" onClick={() => act('select_module')}>
Select A Module
</Button>
</Stack.Item>
</Stack>
);
};
const MainScreen = (props) => {
const [screen, setScreen] = useState(0);
let content;
switch (screen) {
case 0:
content = <StatusScreen />;
break;
case 1:
content = <ComponentView />;
break;
case 2:
content = <Modules />;
break;
}
return (
<>
<Tabs>
<Tabs.Tab
selected={screen === 0}
onClick={() => setScreen(0)}
icon="battery-full"
>
Status
</Tabs.Tab>
<Tabs.Tab
selected={screen === 1}
onClick={() => setScreen(1)}
icon="notes-medical"
>
Diagnostics
</Tabs.Tab>
<Tabs.Tab
selected={screen === 2}
onClick={() => setScreen(2)}
icon="wrench"
>
Modules
</Tabs.Tab>
</Tabs>
{content}
</>
);
};

View File

@@ -0,0 +1,43 @@
import { BooleanLike } from 'common/react';
export type Component = {
key: string;
name: string;
brute_damage: number;
electronics_damage: number;
max_damage: number;
idle_usage: number;
is_powered: boolean;
toggled: boolean;
};
export type Module = {
ref: string;
name: string;
activated: number;
icon: string;
icon_state: string;
};
export type Data = {
name: string;
module_name: string | null;
ai: string;
charge: number | null;
max_charge: number | null;
weapon_lock: BooleanLike;
health: number;
max_health: number;
// Modules
modules_static: Module[];
emag_modules_static: Module[];
modules: Record<string, number>;
emag_modules: Record<string, number>;
// Diagnosis
diag_functional: BooleanLike;
components: Component[];
};

View File

@@ -3311,6 +3311,7 @@
#include "code\modules\mob\living\silicon\robot\robot_items.dm"
#include "code\modules\mob\living\silicon\robot\robot_movement.dm"
#include "code\modules\mob\living\silicon\robot\robot_remote_control.dm"
#include "code\modules\mob\living\silicon\robot\robot_ui.dm"
#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules_vr.dm"
#include "code\modules\mob\living\silicon\robot\dogborg\dog_modules_yw.dm"
#include "code\modules\mob\living\silicon\robot\dogborg\dog_sleeper_vr.dm"