diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index 0c3d7740fb..2746e23598 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -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
diff --git a/code/modules/mob/living/silicon/robot/inventory.dm b/code/modules/mob/living/silicon/robot/inventory.dm
index 45e5c935f8..30f423ac36 100644
--- a/code/modules/mob/living/silicon/robot/inventory.dm
+++ b/code/modules/mob/living/silicon/robot/inventory.dm
@@ -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
diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm
index a1d73d948c..69dd29784a 100644
--- a/code/modules/mob/living/silicon/robot/robot.dm
+++ b/code/modules/mob/living/silicon/robot/robot.dm
@@ -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 = "
[src.name] Self-Diagnosis Report\n"
- for (var/V in components)
- var/datum/robot_component/C = components[V]
- dat += span_bold("[C.name]") + "
| Brute Damage: | [C.brute_damage] |
| Electronics Damage: | [C.electronics_damage] |
| Powered: | [(!C.idle_usage || C.is_powered()) ? "Yes" : "No"] |
| Toggled: | [ C.toggled ? "Yes" : "No"] |
"
-
- 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 = "Modules\n"
- dat += {"
- Activated Modules
-
- Module 1: [module_state_1 ? "[module_state_1]" : "No Module"]
- Module 2: [module_state_2 ? "[module_state_2]" : "No Module"]
- Module 3: [module_state_3 ? "[module_state_3]" : "No Module"]
-
- Installed Modules
"}
-
-
- for (var/obj in module.modules)
- if (!obj)
- dat += span_bold("Resource depleted") + "
"
- else if(activated(obj))
- dat += text("[obj]: Activated
")
- else
- dat += text("[obj]: Activate
")
- if (emagged || emag_items)
- for (var/obj in module.emag)
- if (!obj)
- dat += span_bold("Resource depleted") + "
"
- else if(activated(obj))
- dat += text("[obj]: Activated
")
- else
- dat += text("[obj]: Activate
")
-
- 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()
+
+ . = ..()
diff --git a/code/modules/mob/living/silicon/robot/robot_ui.dm b/code/modules/mob/living/silicon/robot/robot_ui.dm
new file mode 100644
index 0000000000..f7c0e31079
--- /dev/null
+++ b/code/modules/mob/living/silicon/robot/robot_ui.dm
@@ -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
diff --git a/tgui/packages/tgui/interfaces/Robotact/Diagnostics.tsx b/tgui/packages/tgui/interfaces/Robotact/Diagnostics.tsx
new file mode 100644
index 0000000000..45b00946ea
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Robotact/Diagnostics.tsx
@@ -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();
+
+ const { diag_functional, components } = data;
+
+ if (components.length) {
+ components.sort((a, b) => a.name.localeCompare(b.name));
+
+ return (
+
+ {components.map((mod) => (
+
+
+ {toTitleCase(mod.name)}
+
+ }
+ height={12}
+ mt={1}
+ buttons={
+
+
+ ))}
+
+ );
+ }
+
+ return Diagnosis Module Offline;
+};
diff --git a/tgui/packages/tgui/interfaces/Robotact/Modules.tsx b/tgui/packages/tgui/interfaces/Robotact/Modules.tsx
new file mode 100644
index 0000000000..67cc3e6eed
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Robotact/Modules.tsx
@@ -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();
+
+ return (
+
+
+ Modules Locked
+ ) : null
+ }
+ >
+
+ {data.modules_static.map((mod) => (
+
+
+
+ ))}
+ {data.emag_modules_static.map((mod) => (
+
+
+
+ ))}
+
+
+
+
+ );
+};
+
+const Module = (props: { mod: ModuleData; activated: number }) => {
+ const { act } = useBackend();
+ const { mod, activated } = props;
+ return (
+ 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 && (
+
+ {activated}
+
+ )}
+ {mod.name}
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx b/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx
new file mode 100644
index 0000000000..08ab33efc2
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Robotact/StatusScreen.tsx
@@ -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();
+
+ return (
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {quick_actions
+ .slice(0, quick_actions.length / 2)
+ .map((action) => (
+ act(action.eventName)}
+ fluid
+ >
+ {action.name}
+
+ ))}
+
+
+ {quick_actions.slice(quick_actions.length / 2).map((action) => (
+ act(action.eventName)}
+ fluid
+ >
+ {action.name}
+
+ ))}
+
+
+
+
+
+ );
+};
+
+const Configuration = (props) => {
+ const { data } = useBackend();
+
+ const { name, module_name, ai } = data;
+ return (
+
+
+ {name}
+ {module_name}
+
+ {ai ? {ai} : None}
+
+
+
+ );
+};
+
+const Status = (props) => {
+ const { data } = useBackend();
+
+ const { charge, max_charge, health, max_health } = data;
+
+ return (
+
+
+
+ {charge && max_charge ? (
+
+ {charge} / {max_charge}
+
+ ) : (
+ NO CELL INSTALLED
+ )}
+
+
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Robotact/index.tsx b/tgui/packages/tgui/interfaces/Robotact/index.tsx
new file mode 100644
index 0000000000..94b9725334
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Robotact/index.tsx
@@ -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();
+
+ let content = ;
+
+ if (data.module_name) {
+ content = ;
+ }
+
+ return (
+
+ {content}
+
+ );
+};
+
+const NoModuleWarning = (props) => {
+ const { act } = useBackend();
+
+ return (
+
+
+
+ No Module Activated
+
+
+
+
+
+
+ );
+};
+
+const MainScreen = (props) => {
+ const [screen, setScreen] = useState(0);
+
+ let content;
+ switch (screen) {
+ case 0:
+ content = ;
+ break;
+ case 1:
+ content = ;
+ break;
+ case 2:
+ content = ;
+ break;
+ }
+
+ return (
+ <>
+
+ setScreen(0)}
+ icon="battery-full"
+ >
+ Status
+
+ setScreen(1)}
+ icon="notes-medical"
+ >
+ Diagnostics
+
+ setScreen(2)}
+ icon="wrench"
+ >
+ Modules
+
+
+ {content}
+ >
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/Robotact/types.ts b/tgui/packages/tgui/interfaces/Robotact/types.ts
new file mode 100644
index 0000000000..9fd62f6280
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/Robotact/types.ts
@@ -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;
+ emag_modules: Record;
+
+ // Diagnosis
+ diag_functional: BooleanLike;
+ components: Component[];
+};
diff --git a/vorestation.dme b/vorestation.dme
index cb6678fd68..df662e3d2f 100644
--- a/vorestation.dme
+++ b/vorestation.dme
@@ -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"