From 48e33be67cd284961ea82a759da2a4425dd57097 Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:53:59 +0200 Subject: [PATCH 01/21] Initial --- code/modules/admin/modify_robot.dm | 69 ++++++++ .../tgui/interfaces/ModifyRobot/index.tsx | 152 ++++++++++++++++++ .../tgui/interfaces/ModifyRobot/types.ts | 21 +++ vorestation.dme | 2 +- 4 files changed, 243 insertions(+), 1 deletion(-) create mode 100644 code/modules/admin/modify_robot.dm create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/index.tsx create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/types.ts diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm new file mode 100644 index 00000000000..e2f0e7f8c16 --- /dev/null +++ b/code/modules/admin/modify_robot.dm @@ -0,0 +1,69 @@ +/client/proc/modify_robot(var/mob/living/silicon/robot/target in silicon_mob_list) + set name = "Modify Robot" + set desc = "Allows to add or remove modules to/from robots." + set category = "Admin" + if(!check_rights(R_ADMIN|R_FUN|R_VAREDIT|R_EVENT)) + return + + var/datum/eventkit/modify_robot/modify_robot = new() + modify_robot.target = target + modify_robot.tgui_interact(src.mob) + +/datum/eventkit/modify_robot + var/mob/living/silicon/robot/target + +/datum/eventkit/modify_robot/New() + . = ..() + +/datum/eventkit/modify_robot/tgui_interact(mob/user, datum/tgui/ui) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "ModifyRobot", "Modify Robot") + ui.open() + +/datum/eventkit/modify_robot/Destroy() + . = ..() + +/datum/eventkit/modify_robot/tgui_data() + . = list() + if(target) + .["target"] = list() + .["target"]["name"] = target.name + .["target"]["ckey"] = target.ckey + .["target"]["module"] = target.module + .["target"]["crisis_override"] = target.crisis_override + .["target"]["active_restrictions"] = target.restrict_modules_to + var/list/possible_restrictions = list() + for(var/entry in robot_modules) + if(!target.restrict_modules_to.Find(entry)) + possible_restrictions += entry + .["target"]["possible_restrictions"] = possible_restrictions + if(target.module) + .["target"]["front"] = icon2base64(get_flat_icon(target,dir=SOUTH,no_anim=TRUE)) + .["target"]["side"] = icon2base64(get_flat_icon(target,dir=WEST,no_anim=TRUE)) + .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) + var/list/all_players = list() + for(var/mob/living/silicon/robot/R in silicon_mob_list) + var/list/info = list("displayText" = "[R]", "value" = "\ref[R]") + all_players.Add(list(info)) + .["all_players"] = all_players + + +/datum/eventkit/modify_robot/tgui_state(mob/user) + return GLOB.tgui_admin_state + +/datum/eventkit/modify_robot/tgui_act(action, params) + . = ..() + if(.) + return + switch(action) + if("select_target") + target = locate(params["new_target"]) + return TRUE + if("toggle_crisis") + target.crisis_override = !target.crisis_override + return TRUE + if("add_restriction") + target.restrict_modules_to += robot_modules[params["new_restriction"]] + if("remove_restriction") + target.restrict_modules_to -= robot_modules[params["rem_restriction"]] diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx new file mode 100644 index 00000000000..9afd8278537 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -0,0 +1,152 @@ +import { useState } from 'react'; + +import { useBackend } from '../../backend'; +import { + Box, + Button, + Divider, + Dropdown, + Flex, + NoticeBox, + Section, + Stack, + Tabs, +} from '../../components'; +import { Window } from '../../layouts'; +import { Data } from './types'; + +export const ModifyRobot = (props) => { + const { act, data } = useBackend(); + + const { target, all_players } = data; + + const [tab, setTab] = useState(0); + + const tabs: React.JSX.Element[] = []; + + tabs[0] = ; + tabs[1] = ; + tabs[2] = ; + tabs[3] = ; + tabs[4] = ; + tabs[5] = ; + + return ( + + + {target ? ( + + {target.name} played by {target.ckey}. + + ) : ( + No target selected. Please pick one. + )} + + act('select_target', { + new_target: value, + }) + } + /> + {target && !target.module ? ( + <> + + Target has no active module. Limited options available. + + + + + + +
+ + + {target.active_restrictions.map( + (active_restriction, i) => { + return ( + + ); + }, + )} + + +
+
+ +
+ + + {target.possible_restrictions.map( + (possible_restriction, i) => { + return ( + + ); + }, + )} + + +
+
+ +
+ + ) : ( + <> + + setTab(0)}> + Smites + + setTab(1)}> + Medical + + setTab(2)}> + Abilities + + setTab(3)}> + Inventory + + setTab(4)}> + Admin + + setTab(5)}> + Fixes + + + {tabs[tab]} + + )} +
+
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts new file mode 100644 index 00000000000..e2e4097f109 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -0,0 +1,21 @@ +import { BooleanLike } from 'common/react'; + +export type Data = { + target: { + name: string; + ckey: string; + module: string; + crisis_override: BooleanLike; + active_restrictions: string[]; + possible_restrictions: string[]; + front: string | null; + side: string | null; + back: string | null; + } | null; + all_players: DropdownEntry[]; +}; + +export type DropdownEntry = { + displayText: string; + value: string; +}; diff --git a/vorestation.dme b/vorestation.dme index 11313c0b1d0..9f8a730d4f0 100644 --- a/vorestation.dme +++ b/vorestation.dme @@ -1738,6 +1738,7 @@ #include "code\modules\admin\holder2.dm" #include "code\modules\admin\IsBanned.dm" #include "code\modules\admin\map_capture.dm" +#include "code\modules\admin\modify_robot.dm" #include "code\modules\admin\NewBan.dm" #include "code\modules\admin\news.dm" #include "code\modules\admin\persistence.dm" @@ -1814,7 +1815,6 @@ #include "code\modules\admin\verbs\lightning_strike.dm" #include "code\modules\admin\verbs\map_template_loadverb.dm" #include "code\modules\admin\verbs\mapping.dm" -#include "code\modules\admin\verbs\modify_robot.dm" #include "code\modules\admin\verbs\panicbunker.dm" #include "code\modules\admin\verbs\playsound.dm" #include "code\modules\admin\verbs\possess.dm" From 2855b89828d60413f6e92189f65009cba020a021 Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Tue, 17 Sep 2024 23:57:55 +0200 Subject: [PATCH 02/21] this should be swapped --- tgui/packages/tgui/interfaces/ModifyRobot/index.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 9afd8278537..842191bde3e 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -78,8 +78,8 @@ export const ModifyRobot = (props) => { color="red" key={i} onClick={() => - act('add_restriction', { - new_restriction: active_restriction, + act('remove_restriction', { + rem_restriction: active_restriction, }) } > @@ -104,8 +104,8 @@ export const ModifyRobot = (props) => { color="green" key={i} onClick={() => - act('remove_restriction', { - rem_restriction: possible_restriction, + act('add_restriction', { + new_restriction: possible_restriction, }) } > From 571fc8d7127b10121dd039c4daf289e1a3dc48ab Mon Sep 17 00:00:00 2001 From: Kashargul Date: Wed, 18 Sep 2024 00:36:44 +0200 Subject: [PATCH 03/21] first split --- code/modules/admin/modify_robot.dm | 4 +- .../ModifyRobot/ModifyRobotNoModule.tsx | 84 ++++++++++++++ .../tgui/interfaces/ModifyRobot/index.tsx | 103 ++++-------------- .../tgui/interfaces/ModifyRobot/types.ts | 24 ++-- 4 files changed, 118 insertions(+), 97 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index e2f0e7f8c16..86ae8d0398b 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -64,6 +64,6 @@ target.crisis_override = !target.crisis_override return TRUE if("add_restriction") - target.restrict_modules_to += robot_modules[params["new_restriction"]] + target.restrict_modules_to += params["new_restriction"] if("remove_restriction") - target.restrict_modules_to -= robot_modules[params["rem_restriction"]] + target.restrict_modules_to -= params["rem_restriction"] diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx new file mode 100644 index 00000000000..ad12e842f6e --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx @@ -0,0 +1,84 @@ +import { useBackend } from '../../backend'; +import { + Button, + Divider, + Flex, + NoticeBox, + Section, + Stack, +} from '../../components'; +import { Target } from './types'; + +export const ModifyTobotNoModule = (props: { target: Target }) => { + const { target } = props; + const { act } = useBackend(); + + return ( + <> + + Target has no active module. Limited options available. + + + + + + + +
+ + + {target.active_restrictions.map((active_restriction, i) => { + return ( + + ); + })} + + +
+
+ +
+ + + {target.possible_restrictions.map((possible_restriction, i) => { + return ( + + ); + })} + + +
+
+ +
+ + ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 842191bde3e..94aa2ed9d3c 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -3,16 +3,14 @@ import { useState } from 'react'; import { useBackend } from '../../backend'; import { Box, - Button, Divider, Dropdown, - Flex, + LabeledList, NoticeBox, - Section, - Stack, Tabs, } from '../../components'; import { Window } from '../../layouts'; +import { ModifyTobotNoModule } from './ModifyRobotNoModule'; import { Data } from './types'; export const ModifyRobot = (props) => { @@ -36,91 +34,28 @@ export const ModifyRobot = (props) => { {target ? ( - {target.name} played by {target.ckey}. + {target.name} + {!!target.ckey && ' played by ' + target.ckey}. ) : ( No target selected. Please pick one. )} - - act('select_target', { - new_target: value, - }) - } - /> + + + + act('select_target', { + new_target: value, + }) + } + /> + + + {target && !target.module ? ( - <> - - Target has no active module. Limited options available. - - - - - - -
- - - {target.active_restrictions.map( - (active_restriction, i) => { - return ( - - ); - }, - )} - - -
-
- -
- - - {target.possible_restrictions.map( - (possible_restriction, i) => { - return ( - - ); - }, - )} - - -
-
- -
- + ) : ( <> diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index e2e4097f109..9e4b3d57a37 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -1,17 +1,7 @@ import { BooleanLike } from 'common/react'; export type Data = { - target: { - name: string; - ckey: string; - module: string; - crisis_override: BooleanLike; - active_restrictions: string[]; - possible_restrictions: string[]; - front: string | null; - side: string | null; - back: string | null; - } | null; + target: Target | null; all_players: DropdownEntry[]; }; @@ -19,3 +9,15 @@ export type DropdownEntry = { displayText: string; value: string; }; + +export type Target = { + name: string; + ckey: string; + module: string; + crisis_override: BooleanLike; + active_restrictions: string[]; + possible_restrictions: string[]; + front: string | null; + side: string | null; + back: string | null; +}; From 2d07f4f8ba35a1a7cf3611a76f678482098f7761 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Wed, 18 Sep 2024 00:47:10 +0200 Subject: [PATCH 04/21] name the tabs --- .../packages/tgui/interfaces/ModifyRobot/index.tsx | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 94aa2ed9d3c..5dc7b8397f0 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -30,7 +30,7 @@ export const ModifyRobot = (props) => { tabs[5] = ; return ( - + {target ? ( @@ -60,22 +60,22 @@ export const ModifyRobot = (props) => { <> setTab(0)}> - Smites + Module Manager setTab(1)}> - Medical + Upgrade Manager setTab(2)}> - Abilities + Radio Manager setTab(3)}> - Inventory + Component Manager setTab(4)}> - Admin + Access Manager setTab(5)}> - Fixes + Law Manager {tabs[tab]} From 076a54298aa25e26adc1d46f0c1aa5a5a650a726 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Wed, 18 Sep 2024 01:05:44 +0200 Subject: [PATCH 05/21] prep for the next tab --- .../ModifyRobot/ModifyRobotNoModule.tsx | 7 +- .../ModifyRobotTabs/ModifyRobotModules.tsx | 11 +++ .../tgui/interfaces/ModifyRobot/index.tsx | 68 ++++++++++--------- 3 files changed, 50 insertions(+), 36 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx index ad12e842f6e..ccb262b3d21 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx @@ -1,4 +1,4 @@ -import { useBackend } from '../../backend'; +import { useBackend } from 'tgui/backend'; import { Button, Divider, @@ -6,10 +6,11 @@ import { NoticeBox, Section, Stack, -} from '../../components'; +} from 'tgui/components'; + import { Target } from './types'; -export const ModifyTobotNoModule = (props: { target: Target }) => { +export const ModifyRobotNoModule = (props: { target: Target }) => { const { target } = props; const { act } = useBackend(); diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx new file mode 100644 index 00000000000..89bc913c5aa --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -0,0 +1,11 @@ +import { useBackend } from 'tgui/backend'; + +import { Box } from '../../../components'; +import { Target } from '../types'; + +export const ModifyRobotModules = (props: { target: Target }) => { + const { target } = props; + const { act } = useBackend(); + + return ; +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 5dc7b8397f0..efcd305eb9d 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -1,6 +1,5 @@ import { useState } from 'react'; - -import { useBackend } from '../../backend'; +import { useBackend } from 'tgui/backend'; import { Box, Divider, @@ -8,9 +7,11 @@ import { LabeledList, NoticeBox, Tabs, -} from '../../components'; -import { Window } from '../../layouts'; -import { ModifyTobotNoModule } from './ModifyRobotNoModule'; +} from 'tgui/components'; +import { Window } from 'tgui/layouts'; + +import { ModifyRobotNoModule } from './ModifyRobotNoModule'; +import { ModifyRobotModules } from './ModifyRobotTabs/ModifyRobotModules'; import { Data } from './types'; export const ModifyRobot = (props) => { @@ -22,7 +23,7 @@ export const ModifyRobot = (props) => { const tabs: React.JSX.Element[] = []; - tabs[0] = ; + tabs[0] = ; tabs[1] = ; tabs[2] = ; tabs[3] = ; @@ -54,33 +55,34 @@ export const ModifyRobot = (props) => { - {target && !target.module ? ( - - ) : ( - <> - - setTab(0)}> - Module Manager - - setTab(1)}> - Upgrade Manager - - setTab(2)}> - Radio Manager - - setTab(3)}> - Component Manager - - setTab(4)}> - Access Manager - - setTab(5)}> - Law Manager - - - {tabs[tab]} - - )} + {!!target && + (!target.module ? ( + + ) : ( + <> + + setTab(0)}> + Module Manager + + setTab(1)}> + Upgrade Manager + + setTab(2)}> + Radio Manager + + setTab(3)}> + Component Manager + + setTab(4)}> + Access Manager + + setTab(5)}> + Law Manager + + + {tabs[tab]} + + ))} ); From 5b964e0bf0a0476e8c6b97e2b2be1574e982377d Mon Sep 17 00:00:00 2001 From: Kashargul Date: Thu, 19 Sep 2024 02:02:14 +0200 Subject: [PATCH 06/21] add/remove initial --- code/modules/admin/modify_robot.dm | 121 +++- .../ModifyRobot/ModifyRobotNoModule.tsx | 30 +- .../ModifyRobotTabs/ModifyRobotModules.tsx | 143 +++- .../tgui/interfaces/ModifyRobot/index.tsx | 18 +- .../tgui/interfaces/ModifyRobot/types.ts | 13 +- .../tgui/interfaces/common/RankIcon.tsx | 614 ++++++++++++++++-- 6 files changed, 882 insertions(+), 57 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 86ae8d0398b..9afef619cf1 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -11,10 +11,15 @@ /datum/eventkit/modify_robot var/mob/living/silicon/robot/target + var/mob/living/silicon/robot/source /datum/eventkit/modify_robot/New() . = ..() +/datum/eventkit/modify_robot/tgui_close() + if(source) + qdel(source) + /datum/eventkit/modify_robot/tgui_interact(mob/user, datum/tgui/ui) ui = SStgui.try_update_ui(user, src, ui) if(!ui) @@ -22,9 +27,11 @@ ui.open() /datum/eventkit/modify_robot/Destroy() + if(source) + qdel(source) . = ..() -/datum/eventkit/modify_robot/tgui_data() +/datum/eventkit/modify_robot/tgui_data(mob/user) . = list() if(target) .["target"] = list() @@ -42,11 +49,36 @@ .["target"]["front"] = icon2base64(get_flat_icon(target,dir=SOUTH,no_anim=TRUE)) .["target"]["side"] = icon2base64(get_flat_icon(target,dir=WEST,no_anim=TRUE)) .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) - var/list/all_players = list() + var/list/target_items = list() + for(var/obj/item in target.module.modules) + target_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE))) + .["target"]["modules"] = target_items + var/list/module_options = list() + for(var/module in robot_modules) + module_options += module + .["model_options"] = module_options + if(source) + .["source"] = list() + .["source"]["model"] = source.module + .["source"]["front"] = icon2base64(get_flat_icon(source,dir=SOUTH,no_anim=TRUE)) + var/list/source_items = list() + for(var/obj/item in (source.module.modules | source.module.emag)) + var/exists + for(var/obj/has_item in (target.module.modules + target.module.emag)) + if(has_item.name == item.name) + exists = TRUE + break + if(exists) + continue + source_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE))) + .["source"]["modules"] = source_items + var/list/all_robots = list() for(var/mob/living/silicon/robot/R in silicon_mob_list) + if(!R.loc) + continue var/list/info = list("displayText" = "[R]", "value" = "\ref[R]") - all_players.Add(list(info)) - .["all_players"] = all_players + all_robots.Add(list(info)) + .["all_robots"] = all_robots /datum/eventkit/modify_robot/tgui_state(mob/user) @@ -65,5 +97,86 @@ return TRUE if("add_restriction") target.restrict_modules_to += params["new_restriction"] + return TRUE if("remove_restriction") target.restrict_modules_to -= params["rem_restriction"] + return TRUE + if("select_source") + if(source) + qdel(source) + source = new /mob/living/silicon/robot(null) + var/module_type = robot_modules[params["new_source"]] + source.modtype = params["new_source"] + var/obj/item/weapon/robot_module/robot/robot_type = new module_type(source) + source.sprite_datum = pick(SSrobot_sprites.get_module_sprites(source.modtype, source)) + source.update_icon() + source.emag_items = 1 + if(!istype(robot_type, /obj/item/weapon/robot_module/robot)) + QDEL_NULL(source) + return TRUE + return TRUE + if("reset_module") + target.module_reset(FALSE) + return TRUE + if("add_module") + var/obj/item/add_item = locate(params["new_module"]) + if(!add_item) + return TRUE + source.module.emag.Remove(add_item) + source.module.modules.Remove(add_item) + source.module.contents.Remove(add_item) + target.module.modules.Add(add_item) + target.module.contents.Add(add_item) + spawn(0) + SEND_SIGNAL(add_item, COMSIG_OBSERVER_MOVED) + target.hud_used.update_robot_modules_display() + if(istype(add_item, /obj/item/stack/)) + var/obj/item/stack/item_with_synth = add_item + for(var/synth in item_with_synth.synths) + var/found = target.module.synths.Find(synth) + if(!found) + source.module.synths.Remove(synth) + target.module.synths.Add(synth) + else + item_with_synth.synths = list(target.module.synths[found]) + return TRUE + if(istype(add_item, /obj/item/weapon/matter_decompiler/) || istype(add_item, /obj/item/device/dogborg/sleeper/compactor/decompiler/)) + var/obj/item/weapon/matter_decompiler/item_with_matter = add_item + if(item_with_matter.metal) + var/found = target.module.synths.Find(item_with_matter.metal) + if(!found) + source.module.synths.Remove(item_with_matter.metal) + target.module.synths.Add(item_with_matter.metal) + else + item_with_matter.metal = target.module.synths[found] + if(item_with_matter.glass) + var/found = target.module.synths.Find(item_with_matter.glass) + if(!found) + source.module.synths.Remove(item_with_matter.glass) + target.module.synths.Add(item_with_matter.glass) + else + item_with_matter.glass = target.module.synths[found] + if(item_with_matter.wood) + var/found = target.module.synths.Find(item_with_matter.wood) + if(!found) + source.module.synths.Remove(item_with_matter.wood) + target.module.synths.Add(item_with_matter.wood) + else + item_with_matter.wood = target.module.synths[found] + if(item_with_matter.plastic) + var/found = target.module.synths.Find(item_with_matter.plastic) + if(!found) + source.module.synths.Remove(item_with_matter.plastic) + target.module.synths.Add(item_with_matter.plastic) + else + item_with_matter.plastic = target.module.synths[found] + return TRUE + if("rem_module") + var/obj/item/rem_item = locate(params["old_module"]) + target.uneq_all() + target.hud_used.update_robot_modules_display(TRUE) + target.module.emag.Remove(rem_item) + target.module.modules.Remove(rem_item) + target.module.contents.Remove(rem_item) + qdel(rem_item) + return TRUE diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx index ccb262b3d21..364bd2ff2d6 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotNoModule.tsx @@ -3,11 +3,13 @@ import { Button, Divider, Flex, + Icon, NoticeBox, Section, Stack, } from 'tgui/components'; +import { RankIcon } from '../common/RankIcon'; import { Target } from './types'; export const ModifyRobotNoModule = (props: { target: Target }) => { @@ -24,8 +26,20 @@ export const ModifyRobotNoModule = (props: { target: Target }) => { fluid color={target.crisis_override ? 'red' : 'green'} onClick={() => act('toggle_crisis')} + tooltip={ + (target.crisis_override ? 'Disables' : 'Enables') + + ' combat module option for this unit!' + } > - {(target.crisis_override ? 'Disable' : 'Enable') + ' Crisis Override'} + + + + + + {(target.crisis_override ? 'Disable' : 'Enable') + + ' Crisis Override'} + + @@ -46,7 +60,12 @@ export const ModifyRobotNoModule = (props: { target: Target }) => { }) } > - {active_restriction} + + + {RankIcon({ rank: active_restriction, color: '' })} + + {active_restriction} + ); })} @@ -70,7 +89,12 @@ export const ModifyRobotNoModule = (props: { target: Target }) => { }) } > - {possible_restriction} + + + {RankIcon({ rank: possible_restriction, color: '' })} + + {possible_restriction} + ); })} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 89bc913c5aa..1fd665ae9b3 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -1,11 +1,144 @@ import { useBackend } from 'tgui/backend'; +import { + Box, + Button, + Divider, + Dropdown, + Flex, + Icon, + Image, + Section, + Stack, +} from 'tgui/components'; -import { Box } from '../../../components'; -import { Target } from '../types'; +import { Source, Target } from '../types'; -export const ModifyRobotModules = (props: { target: Target }) => { - const { target } = props; +export const ModifyRobotModules = (props: { + target: Target; + source: Source; + model_options: string[]; +}) => { + const { target, source, model_options } = props; const { act } = useBackend(); - return ; + return ( + + +
+ Robot to salvage + + act('select_source', { + new_source: value, + }) + } + /> + {!!source && ( + <> + + + + + + {source.modules.map((modul_option, i) => { + return ( + + ); + })} + + + + )} +
+
+ + +
+ {target ? target.module : ''} + act('reset_module')} + > + Reset Module + + + + + + + {target.modules.map((modul_option, i) => { + return ( + + ); + })} + + +
+
+
+ ); }; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index efcd305eb9d..438d89f5b71 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -17,21 +17,28 @@ import { Data } from './types'; export const ModifyRobot = (props) => { const { act, data } = useBackend(); - const { target, all_players } = data; + const { target, all_robots, source, model_options } = data; const [tab, setTab] = useState(0); const tabs: React.JSX.Element[] = []; - tabs[0] = ; + tabs[0] = ( + + ); tabs[1] = ; tabs[2] = ; tabs[3] = ; tabs[4] = ; tabs[5] = ; + tabs[6] = ; return ( - + {target ? ( @@ -45,7 +52,7 @@ export const ModifyRobot = (props) => { act('select_target', { new_target: value, @@ -79,6 +86,9 @@ export const ModifyRobot = (props) => { setTab(5)}> Law Manager + setTab(6)}> + Law Sets +
{tabs[tab]} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index 9e4b3d57a37..a90b58e29d3 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -1,8 +1,10 @@ import { BooleanLike } from 'common/react'; export type Data = { + source: Source; target: Target | null; - all_players: DropdownEntry[]; + all_robots: DropdownEntry[]; + model_options: string[] | null; }; export type DropdownEntry = { @@ -20,4 +22,13 @@ export type Target = { front: string | null; side: string | null; back: string | null; + modules: Module[]; }; + +export type Source = { + model: string; + front: string; + modules: Module[]; +} | null; + +export type Module = { item: string; ref: string; icon: string }; diff --git a/tgui/packages/tgui/interfaces/common/RankIcon.tsx b/tgui/packages/tgui/interfaces/common/RankIcon.tsx index 646a4e43ad7..76d5dd46b9f 100644 --- a/tgui/packages/tgui/interfaces/common/RankIcon.tsx +++ b/tgui/packages/tgui/interfaces/common/RankIcon.tsx @@ -1,103 +1,637 @@ import { Icon } from '../../components'; const rank2icon = { - // Command - 'Colony Director': 'user-tie', + // Command Site Manager 'Site Manager': 'user-tie', Overseer: 'user-tie', + 'Facility Director': 'user-tie', + 'Chief Supervisor': 'user-tie', + Captain: 'user-tie', + 'Colony Director': 'user-tie', + // HOP 'Head of Personnel': 'briefcase', 'Crew Resources Officer': 'briefcase', 'Deputy Director': 'briefcase', - 'Command Secretary': 'user-tie', - // Security + 'Staff Manager': 'briefcase', + 'Facility Steward': 'briefcase', + 'First Mate': 'briefcase', + 'Performance Management Supervisor': 'briefcase', + // Secretary + 'Command Secretary': 'address-card', + 'Command Liaison': 'address-card', + 'Command Assistant': 'address-card', + 'Command Intern': 'address-card', + 'Bridge Secretary': 'address-card', + 'Bridge Assistant': 'address-card', + 'Bridge Officer': 'address-card', + // Security HOS 'Head of Security': 'user-shield', 'Security Commander': 'user-shield', 'Chief of Security': 'user-shield', - Warden: ['city', 'shield-alt'], - Detective: 'search', - 'Forensic Technician': 'search', - 'Security Officer': 'user-shield', - 'Junior Officer': 'user-shield', - // Engineering - 'Chief Engineer': 'toolbox', + 'Security Managery': 'user-shield', + // Warden + Warden: ['city', 'shield-halved'], + 'Brig Sentry': ['city', 'shield-halved'], + 'Armory Superintendent': ['city', 'shield-halved'], + 'Master-at-Arms': ['city', 'shield-halved'], + // Detective + Detective: 'magnifying-glass', + Investigator: 'magnifying-glass', + 'Security Inspector': 'magnifying-glass', + 'Forensic Technician': 'magnifying-glass', + // Security Officer + 'Security Officer': 'shield', + 'Patrol Officer': 'shield', + 'Security Guard': 'shield', + 'Security Deputy': 'shield', + 'Junior Officer': 'shield', + 'Security Contractor': 'shield', + // Engineering CE + 'Chief Engineer': 'screwdriver-wrench', + 'Head Engineer': 'screwdriver-wrench', + Foreman: 'screwdriver-wrench', + 'Maintenance Manager': 'screwdriver-wrench', + // Atmospheric Technician 'Atmospheric Technician': 'wind', - 'Station Engineer': 'toolbox', + 'Atmospheric Engineer': 'wind', + 'Atmospheric Maintainer': 'wind', + 'Disposals Technician': 'wind', + 'Fuel Technician': 'wind', + // Engineer + Engineer: 'toolbox', 'Maintenance Technician': 'wrench', 'Engine Technician': 'toolbox', - Electrician: 'toolbox', - // Medical - 'Chief Medical Officer': 'user-md', + Electrician: 'screwdriver', + 'Construction Engineer': 'trowel-bricks', + 'Engineering Contractor': 'ruler', + // Medical CMO + 'Chief Medical Officer': 'user-doctor', + 'Chief Physician': 'user-doctor', + 'Medical Director': 'user-doctor', + 'Healthcare Manager': 'user-doctor', + // Chemist Chemist: 'mortar-pestle', Pharmacist: 'mortar-pestle', - 'Medical Doctor': 'user-md', - Surgeon: 'user-md', - 'Emergency Physician': 'user-md', - Nurse: 'user-md', + Pharmacologist: 'mortar-pestle', + // Medical Doctor + 'Medical Doctor': 'suitcase-medical', + Physician: 'suitcase-medical', + 'Medical Practitioner': 'suitcase-medical', + Surgeon: 'syringe', + 'Emergency Physician': 'suitcase-medical', + Nurse: 'user-nurse', + Orderly: 'book-medical', Virologist: 'disease', - Paramedic: 'ambulance', - 'Emergency Medical Technician': 'ambulance', + 'Medical Contractor': 'notes-medical', + // Paramedic + Paramedic: 'truck-medical', + 'Emergency Medical Technician': 'truck-medical', + 'Medical Responder': 'truck-medical', + 'Search and Rescue': 'truck-droplet', + // Psychiatrist Psychiatrist: 'couch', Psychologist: 'couch', - // Science + Psychoanalyst: 'couch', + Psychotherapist: 'couch', + // Genetecist + Geneticist: 'dna', + // Brig Physician + 'Brig Physician': ['kit-medical', 'shield-halved'], + 'Security Medic': ['kit-medical', 'shield-halved'], + 'Security Medic Care Unit': ['kit-medical', 'shield-halved'], + 'Penitentiary Medical Care Unit': ['kit-medical', 'shield-halved'], + 'Junior Brig Physician': ['kit-medical', 'shield-halved'], + 'Detention Health Officer': ['kit-medical', 'shield-halved'], + // Science RD 'Research Director': 'user-graduate', 'Research Supervisor': 'user-graduate', + 'Research Manager': 'user-graduate', + 'Head of Development': 'user-graduate', + 'Head Scientist': 'user-graduate', + // Roboticist Roboticist: 'robot', + 'Assembly Technician': 'screwdriver', 'Biomechanical Engineer': ['wrench', 'heartbeat'], 'Mechatronic Engineer': 'wrench', + // Scientist Scientist: 'flask', - Xenoarchaeologist: 'flask', - Anomalist: 'flask', - 'Phoron Researcher': 'flask', + Researcher: 'flask-vial', + 'Lab Assistant': 'flask', + Xenoarchaeologist: 'bone', + Xenopaleontologist: 'bone', + Anomalist: 'atom', + 'Phoron Researcher': 'vials', + 'Gas Physicist': 'microscope', 'Circuit Designer': 'car-battery', + 'Circuit Programmer': 'laptop-file', + // Xenobiologist Xenobiologist: 'meteor', + Xenozoologist: 'locust', + Xenoanthropologist: 'bugs', + // Xenobotanist Xenobotanist: ['biohazard', 'seedling'], - // Cargo + Xenohydroponicist: ['biohazard', 'droplet'], + Xenoflorist: ['biohazard', 'clover'], + // Cargo QM Quartermaster: 'box-open', 'Supply Chief': 'warehouse', - 'Cargo Technician': 'box-open', - 'Shaft Miner': 'hard-hat', - 'Drill Technician': 'hard-hat', - // Exploration + 'Logistics Manager': 'warehouse', + 'Cargo Supervisor': 'box-open', + // Cargo Technician + 'Cargo Technician': 'box', + 'Cargo Loader': 'dolly', + 'Cargo Handler': 'boxes-stacked', + 'Supply Courier': 'people-carry-box', + 'Disposals Sorter': 'recycle', + Mailman: 'envelopes-bulk', + // Shaft Miner + 'Shaft Miner': 'helmet-safety', + 'Deep Space Miner': 'bore-hole', + 'Drill Technician': 'oil-well', + Prospector: 'helmet-safety', + Excavator: 'bore-hole', + // Exploration Lead Pathfinder: 'binoculars', + 'Expedition Lead': 'binoculars', + 'Exploration Manager': 'binoculars', + // Explorer Explorer: 'user-astronaut', - 'Field Medic': ['user-md', 'user-astronaut'], - Pilot: 'space-shuttle', - // Civvies + Surveyor: 'user-astronaut', + 'Offsite Scout': 'user-astronaut', + 'Explorer Medic': ['user-astronaut', 'kit-medical'], + 'Explorer Technician': ['user-astronaut', 'screwdriver'], + // Field Medic + 'Field Medic': ['suitcase-medical', 'user-astronaut'], + 'Expedition Medic': ['suitcase-medical', 'user-astronaut'], + 'Offsite Medic': ['suitcase-medical', 'user-astronaut'], + // Pilot + Pilot: 'shuttle-space', + 'Co-Pilot': 'shuttle-space', + Navigator: 'shuttle-space', + Helmsman: 'shuttle-space', + // Barkeeper Bartender: 'glass-martini', + Barkeeper: 'wine-glass', + Barmaid: 'whiskey-glass', Barista: 'coffee', + Mixologist: 'martini-glass-citrus', + // Botanist Botanist: 'leaf', + Hydroponicist: 'droplet', Gardener: 'leaf', - Chaplain: 'place-of-worship', - Counselor: 'couch', + Cultivator: 'spa', + Farmer: 'plant-wilt', + Florist: 'spa', + Rancher: 'leaf', + // Chef Chef: 'utensils', + 'Sous-chef': 'spoon', Cook: 'utensils', + 'Kitchen Worker': 'kitchen-set', + // Chaplain + Chaplain: 'place-of-worship', + Counselor: 'cross', + Preacher: 'cross', + Missionary: 'cross', + Priest: 'cross', + Nun: 'church', + Monk: 'place-of-worship', + Guru: 'place-of-worship', + // Entertainer Entertainer: 'smile-beam', Performer: 'smile-beam', Musician: 'guitar', Stagehand: 'smile-beam', + Actor: 'face-laugh-wink', + Dancer: 'face-smile', + Singer: 'smusic', + Magician: 'wand-magic-sparkles', + Comedian: 'face-laugh-wink', + Tragedian: 'face-sad-tear', + Artist: 'smile-beam', + 'Game Master': 'dice', + // Entrepreneur + Entrepreneur: 'building', + Lawyer: 'gavel', + 'Private Eye': 'user-secret', + Bodyguard: 'person-military-pointing', + 'Personal Physician': 'star-of-life', + Dentist: 'teeth', + 'Fitness Instructor': 'dumbbell', + 'Yoga Teacher': 'person-walking', + Masseuse: 'bottle-droplet', + Tradesperson: 'money-bill-trend-up', + Streamer: 'desktop', + Influencer: 'computer', + 'Paranormal Investigator': 'magnifying-glass-arrow-right', + 'Personal Secretary': 'pen-to-square', + Stylist: 'hat-cowboy-side', + Fisher: 'fish-fins', + 'Fortune Teller': 'golf-ball-tee', + 'Spirit Healer': 'ghost', // All of the interns Intern: 'school', 'Apprentice Engineer': ['school', 'wrench'], - 'Medical Intern': ['school', 'user-md'], - 'Lab Assistant': ['school', 'flask'], - 'Security Cadet': ['school', 'shield-alt'], + 'Research Intern': ['school', 'flask'], + 'Security Cadet': ['school', 'shield-halved'], 'Jr. Cargo Tech': ['school', 'box'], 'Jr. Explorer': ['school', 'user-astronaut'], + Assistant: ['school', 'address-card'], Server: ['school', 'utensils'], - // Back to civvies + 'Technical Assistant': ['school', 'screwdriver'], + 'Medical Intern': ['school', 'user-nurse'], + 'Research Assistant"': ['school', 'flask'], + Visitor: 'user', + Resident: 'user', + // IAA 'Internal Affairs Agent': 'balance-scale', + 'Internal Affairs Liaison': 'balance-scale', + 'Internal Affairs Delegate': 'balance-scale', + 'Internal Affairs Investigator': 'balance-scale', + // Janitor Janitor: 'broom', Custodian: 'broom', 'Sanitation Technician': 'hand-sparkles', Maid: 'broom', + 'Garbage Collector': 'dumpster', + // Librarian Librarian: 'book', Journalist: 'newspaper', + Reporter: 'newspaper', Writer: 'book', Historian: 'chalkboard-teacher', + Archivist: 'book', Professor: 'chalkboard-teacher', - Visitor: 'user', + Academic: 'chalkboard-teacher', + Philosopher: 'book', + Curator: 'book', + // Off duty + 'Off-duty Officer': 'tree-city', + 'Off-duty Engineer': 'tree-city', + 'Off-duty Medic': 'tree-city', + 'Off-duty Scientist': 'tree-city', + 'Off-duty Cargo': 'tree-city', + 'Off-duty Explorer': 'tree-city', + 'Off-duty Worker': 'tree-city', + // AI / Robot + AI: 'display', + Cyborg: 'robot', + Robot: 'robot', + Drone: 'robot', + // Clown / Mime + Clown: 'bullhorn', + Jester: 'bullhorn', + Fool: 'bullhorn', + Mime: 'face-grin-tears', + Poseur: 'face-grin-tears', // Special roles 'Emergency Responder': 'fighter-jet', + // Talon + 'Talon Captain': ['location-arrow', 'user-tie'], + 'Talon Commander': ['location-arrow', 'user-tie'], + 'Talon Doctor': ['location-arrow', 'suitcase-medical'], + 'Talon Medic': ['location-arrow', 'suitcase-medical'], + 'Talon Engineer': ['location-arrow', 'wrench'], + 'Talon Technician': ['location-arrow', 'screwdriver'], + 'Talon Guard': ['location-arrow', 'shield'], + 'Talon Security': ['location-arrow', 'shield'], + 'Talon Marine': ['location-arrow', 'shield'], + 'Talon Pilot': ['location-arrow', 'shuttle-space'], + 'Talon Helmsman': ['location-arrow', 'shuttle-space'], + 'Talon Miner': ['location-arrow', 'helmet-safety'], + 'Talon Excavator': ['location-arrow', 'helmet-safety'], + // Robot Modules + Standard: 'robot', + Service: 'glass-martini', + Clerical: 'pen-to-square', + Research: 'flask', + Miner: 'helmet-safety', + Crisis: 'kit-medical', + Security: 'shield', + Combat: 'gun', + Engineering: 'wrench', + Gravekeeper: 'square-xmark', + Lost: 'location-crosshairs', + Protector: 'building-shield', + Mechanist: 'gears', + 'Combat Medic': 'x-ray', +}; + +const rank2color = { + // Command Site Manager + 'Site Manager': 'blue', + Overseer: 'blue', + 'Facility Director': 'blue', + 'Chief Supervisor': 'blue', + Captain: 'blue', + 'Colony Director': 'blue', + // HOP + 'Head of Personnel': 'blue', + 'Crew Resources Officer': 'blue', + 'Deputy Director': 'blue', + 'Staff Manager': 'blue', + 'Facility Steward': 'blue', + 'First Mate': 'blue', + 'Performance Management Supervisor': 'blue', + // Secretary + 'Command Secretary': 'blue', + 'Command Liaison': 'blue', + 'Command Assistant': 'blue', + 'Command Intern': 'blue', + 'Bridge Secretary': 'blue', + 'Bridge Assistant': 'blue', + 'Bridge Officer': 'blue', + // Security HOS + 'Head of Security': 'blue', + 'Security Commander': 'blue', + 'Chief of Security': 'blue', + 'Security Managery': 'blue', + // Warden + Warden: 'red', + 'Brig Sentry': 'red', + 'Armory Superintendent': 'red', + 'Master-at-Arms': 'red', + // Detective + Detective: 'red', + Investigator: 'red', + 'Security Inspector': 'red', + 'Forensic Technician': 'red', + // Security Officer + 'Security Officer': 'red', + 'Patrol Officer': 'red', + 'Security Guard': 'red', + 'Security Deputy': 'red', + 'Junior Officer': 'red', + 'Security Contractor': 'red', + // Engineering CE + 'Chief Engineer': 'blue', + 'Head Engineer': 'blue', + Foreman: 'blue', + 'Maintenance Manager': 'blue', + // Atmospheric Technician + 'Atmospheric Technician': 'orange', + 'Atmospheric Engineer': 'orange', + 'Atmospheric Maintainer': 'orange', + 'Disposals Technician': 'orange', + 'Fuel Technician': 'orange', + // Engineer + Engineer: 'orange', + 'Maintenance Technician': 'orange', + 'Engine Technician': 'orange', + Electrician: 'orange', + 'Construction Engineer': 'orange', + 'Engineering Contractor': 'orange', + // Medical CMO + 'Chief Medical Officer': 'blue', + 'Chief Physician': 'blue', + 'Medical Director': 'blue', + 'Healthcare Manager': 'blue', + // Chemist + Chemist: 'teal', + Pharmacist: 'teal', + Pharmacologist: 'teal', + // Medical Doctor + 'Medical Doctor': 'teal', + Physician: 'teal', + 'Medical Practitioner': 'teal', + Surgeon: 'teal', + 'Emergency Physician': 'teal', + Nurse: 'teal', + Orderly: 'teal', + Virologist: 'teal', + 'Medical Contractor': 'teal', + // Paramedic + Paramedic: 'teal', + 'Emergency Medical Technician': 'teal', + 'Medical Responder': 'teal', + 'Search and Rescue': 'teal', + // Psychiatrist + Psychiatrist: 'teal', + Psychologist: 'teal', + Psychoanalyst: 'teal', + Psychotherapist: 'teal', + // Genetecist + Geneticist: 'teal', + // Brig Physician + 'Brig Physician': 'teal', + 'Security Medic': 'teal', + 'Security Medic Care Unit': 'teal', + 'Penitentiary Medical Care Unit': 'teal', + 'Junior Brig Physician': 'teal', + 'Detention Health Officer': 'teal', + // Science RD + 'Research Director': 'blue', + 'Research Supervisor': 'blue', + 'Research Manager': 'blue', + 'Head of Development': 'blue', + 'Head Scientist': 'blue', + // Roboticist + Roboticist: 'purple', + 'Assembly Technician': 'purple', + 'Biomechanical Engineer': 'purple', + 'Mechatronic Engineer': 'purple', + // Scientist + Scientist: 'purple', + Researcher: 'purple', + 'Lab Assistant': 'purple', + Xenoarchaeologist: 'purple', + Xenopaleontologist: 'purple', + Anomalist: 'purple', + 'Phoron Researcher': 'purple', + 'Gas Physicist': 'purple', + 'Circuit Designer': 'purple', + 'Circuit Programmer': 'purple', + // Xenobiologist + Xenobiologist: 'purple', + Xenozoologist: 'purple', + Xenoanthropologist: 'purple', + // Xenobotanist + Xenobotanist: 'purple', + Xenohydroponicist: 'purple', + Xenoflorist: 'purple', + // Cargo QM + Quartermaster: 'brown', + 'Supply Chief': 'brown', + 'Logistics Manager': 'brown', + 'Cargo Supervisor': 'brown', + // Cargo Technician + 'Cargo Technician': 'brown', + 'Cargo Loader': 'brown', + 'Cargo Handler': 'brown', + 'Supply Courier': 'brown', + 'Disposals Sorter': 'brown', + Mailman: 'brown', + // Shaft Miner + 'Shaft Miner': 'brown', + 'Deep Space Miner': 'brown', + 'Drill Technician': 'brown', + Prospector: 'brown', + Excavator: 'brown', + // Exploration Lead + Pathfinder: 'blue', + 'Expedition Lead': 'blue', + 'Exploration Manager': 'blue', + // Explorer + Explorer: 'grey', + Surveyor: 'grey', + 'Offsite Scout': 'grey', + 'Explorer Medic': 'grey', + 'Explorer Technician': 'grey', + // Field Medic + 'Field Medic': 'grey', + 'Expedition Medic': 'grey', + 'Offsite Medic': 'grey', + // Pilot + Pilot: 'grey', + 'Co-Pilot': 'grey', + Navigator: 'grey', + Helmsman: 'grey', + // Barkeeper + Bartender: 'green', + Barkeeper: 'green', + Barmaid: 'green', + Barista: 'green', + Mixologist: 'green', + // Botanist + Botanist: 'green', + Hydroponicist: 'green', + Gardener: 'green', + Cultivator: 'green', + Farmer: 'green', + Florist: 'green', + Rancher: 'green', + // Chef + Chef: 'green', + 'Sous-chef': 'green', + Cook: 'green', + 'Kitchen Worker': 'green', + // Chaplain + Chaplain: 'green', + Counselor: 'green', + Preacher: 'green', + Missionary: 'green', + Priest: 'green', + Nun: 'green', + Monk: 'green', + Guru: 'green', + // Entertainer + Entertainer: 'green', + Performer: 'green', + Musician: 'green', + Stagehand: 'green', + Actor: 'green', + Dancer: 'green', + Singer: 'green', + Magician: 'green', + Comedian: 'green', + Tragedian: 'green', + Artist: 'green', + 'Game Master': 'green', + // Entrepreneur + Entrepreneur: 'green', + Lawyer: 'green', + 'Private Eye': 'green', + Bodyguard: 'green', + 'Personal Physician': 'green', + Dentist: 'green', + 'Fitness Instructor': 'green', + 'Yoga Teacher': 'green', + Masseuse: 'green', + Tradesperson: 'green', + Streamer: 'green', + Influencer: 'green', + 'Paranormal Investigator': 'green', + 'Personal Secretary': 'green', + Stylist: 'green', + Fisher: 'green', + 'Fortune Teller': 'green', + 'Spirit Healer': 'green', + // All of the interns + Intern: 'green', + 'Apprentice Engineer': 'green', + 'Research Intern': 'green', + 'Security Cadet': 'green', + 'Jr. Cargo Tech': 'green', + 'Jr. Explorer': 'green', + Assistant: 'green', + Server: 'green', + 'Technical Assistant': 'green', + 'Medical Intern': 'green', + 'Research Assistant"': 'green', + Visitor: 'green', + Resident: 'green', + // IAA + 'Internal Affairs Agent': 'blue', + 'Internal Affairs Liaison': 'blue', + 'Internal Affairs Delegate': 'blue', + 'Internal Affairs Investigator': 'blue', + // Janitor + Janitor: 'green', + Custodian: 'green', + 'Sanitation Technician': 'green', + Maid: 'green', + 'Garbage Collector': 'green', + // Librarian + Librarian: 'green', + Journalist: 'green', + Reporter: 'green', + Writer: 'green', + Historian: 'green', + Archivist: 'green', + Professor: 'green', + Academic: 'green', + Philosopher: 'green', + Curator: 'green', + // Off duty + 'Off-duty Officer': 'white', + 'Off-duty Engineer': 'white', + 'Off-duty Medic': 'white', + 'Off-duty Scientist': 'white', + 'Off-duty Cargo': 'white', + 'Off-duty Explorer': 'white', + 'Off-duty Worker': 'white', + // AI / Robot + AI: 'darkgrey', + Cyborg: 'darkgrey', + Robot: 'darkgrey', + Drone: 'darkgrey', + // Clown / Mime + Clown: 'green', + Jester: 'green', + Fool: 'green', + Mime: 'green', + Poseur: 'green', + // Special roles + 'Emergency Responder': 'yellow', + // Talon + 'Talon Captain': 'grey', + 'Talon Commander': 'grey', + 'Talon Doctor': 'grey', + 'Talon Medic': 'grey', + 'Talon Engineer': 'grey', + 'Talon Technician': 'grey', + 'Talon Guard': 'grey', + 'Talon Security': 'grey', + 'Talon Marine': 'grey', + 'Talon Pilot': 'grey', + 'Talon Helmsman': 'grey', + 'Talon Miner': 'grey', + 'Talon Excavator': 'grey', + // Robot Modules + Standard: 'grey', + Service: 'green', + Clerical: 'blue', + Research: 'purple', + Miner: 'brown', + Crisis: 'teal', + Security: 'red', + Combat: 'yellow', + Engineering: 'orange', + Gravekeeper: 'dark-grey', + Lost: 'grey', + Protector: 'darkred', + Mechanist: 'darkred', + 'Combat Medic': 'darkred', }; type rank_icon = { rank: string; color: string }; From d1f28eb1cd455dbdcd960030e88842a1b770e5ea Mon Sep 17 00:00:00 2001 From: Kashargul Date: Thu, 19 Sep 2024 02:23:42 +0200 Subject: [PATCH 07/21] some searching --- code/modules/admin/modify_robot.dm | 4 +- .../ModifyRobotTabs/ModifyRobotModules.tsx | 151 ++++++++++++------ .../tgui/interfaces/ModifyRobot/types.ts | 2 +- 3 files changed, 101 insertions(+), 56 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 9afef619cf1..2cd6dc80e28 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -51,7 +51,7 @@ .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) var/list/target_items = list() for(var/obj/item in target.module.modules) - target_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE))) + target_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) .["target"]["modules"] = target_items var/list/module_options = list() for(var/module in robot_modules) @@ -70,7 +70,7 @@ break if(exists) continue - source_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE))) + source_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) .["source"]["modules"] = source_items var/list/all_robots = list() for(var/mob/living/silicon/robot/R in silicon_mob_list) diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 1fd665ae9b3..72f7dceb1f2 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -1,3 +1,7 @@ +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; +import { createSearch } from 'common/string'; +import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { Box, @@ -7,11 +11,12 @@ import { Flex, Icon, Image, + Input, Section, Stack, } from 'tgui/components'; -import { Source, Target } from '../types'; +import { Module, Source, Target } from '../types'; export const ModifyRobotModules = (props: { target: Target; @@ -20,6 +25,8 @@ export const ModifyRobotModules = (props: { }) => { const { target, source, model_options } = props; const { act } = useBackend(); + const [searchSourceText, setSearchSourceText] = useState(''); + const [searchModuleText, setSearchModulText] = useState(''); return ( @@ -49,36 +56,46 @@ export const ModifyRobotModules = (props: { }} /> + setSearchSourceText(value)} + /> + - {source.modules.map((modul_option, i) => { - return ( - - ); - })} + {prepareSearch(source.modules, searchSourceText).map( + (modul_option, i) => { + return ( + + ); + }, + )} @@ -95,6 +112,7 @@ export const ModifyRobotModules = (props: { confirmColor="red" confirmIcon="triangle-exclamation" onClick={() => act('reset_module')} + tooltip="Allows to reset the module back to default." > Reset Module @@ -109,32 +127,42 @@ export const ModifyRobotModules = (props: { }} /> + setSearchModulText(value)} + /> + - {target.modules.map((modul_option, i) => { - return ( - - ); - })} + {prepareSearch(target.modules, searchModuleText).map( + (modul_option, i) => { + return ( + + ); + }, + )} @@ -142,3 +170,20 @@ export const ModifyRobotModules = (props: { ); }; + +const prepareSearch = ( + modules: Module[], + searchText: string = '', +): Module[] => { + const testSearch = createSearch(searchText, (module: Module) => module.item); + return flow([ + (modules: Module[]) => { + // Optional search term + if (!searchText) { + return modules; + } else { + return filter(modules, testSearch); + } + }, + ])(modules); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index a90b58e29d3..b0e6bf2a462 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -31,4 +31,4 @@ export type Source = { modules: Module[]; } | null; -export type Module = { item: string; ref: string; icon: string }; +export type Module = { item: string; ref: string; icon: string; desc: string }; From b285d5be684fc7b74840a8350371170021a06cc6 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Thu, 19 Sep 2024 02:33:05 +0200 Subject: [PATCH 08/21] function --- .../ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 72f7dceb1f2..9e0ebb34d50 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -171,10 +171,7 @@ export const ModifyRobotModules = (props: { ); }; -const prepareSearch = ( - modules: Module[], - searchText: string = '', -): Module[] => { +function prepareSearch(modules: Module[], searchText: string = ''): Module[] { const testSearch = createSearch(searchText, (module: Module) => module.item); return flow([ (modules: Module[]) => { @@ -186,4 +183,4 @@ const prepareSearch = ( } }, ])(modules); -}; +} From 35f8fe4a2b5a53111ae8b3f6e67a13af0ac0f4ed Mon Sep 17 00:00:00 2001 From: Kashargul Date: Thu, 19 Sep 2024 20:51:49 +0200 Subject: [PATCH 09/21] upgrade and PKA tab --- code/modules/admin/modify_robot.dm | 144 ++++++++- .../ModifyRobotTabs/ModifyRobotModules.tsx | 280 +++++++++--------- .../ModifyRobotTabs/ModifyRobotPKA.tsx | 69 +++++ .../ModifyRobotTabs/ModifyRobotUpgrades.tsx | 110 +++++++ .../interfaces/ModifyRobot/components.tsx | 12 + .../tgui/interfaces/ModifyRobot/constants.ts | 6 + .../tgui/interfaces/ModifyRobot/index.tsx | 73 +++-- .../tgui/interfaces/ModifyRobot/types.ts | 27 ++ 8 files changed, 564 insertions(+), 157 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotPKA.tsx create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/components.tsx create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/constants.ts diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 2cd6dc80e28..62f812ff22b 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -33,6 +33,7 @@ /datum/eventkit/modify_robot/tgui_data(mob/user) . = list() + // Target section for general data if(target) .["target"] = list() .["target"]["name"] = target.name @@ -45,7 +46,9 @@ if(!target.restrict_modules_to.Find(entry)) possible_restrictions += entry .["target"]["possible_restrictions"] = possible_restrictions + // Target section for options once a module has been selected if(target.module) + .["target"]["active"] = target.icon_selected .["target"]["front"] = icon2base64(get_flat_icon(target,dir=SOUTH,no_anim=TRUE)) .["target"]["side"] = icon2base64(get_flat_icon(target,dir=WEST,no_anim=TRUE)) .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) @@ -57,6 +60,78 @@ for(var/module in robot_modules) module_options += module .["model_options"] = module_options + // Data for the upgrade options + var/list/whitelisted_upgrades = list() + var/list/blacklisted_upgrades = list() + for(var/datum/design/item/prosfab/robot_upgrade/restricted/upgrade) + if(!(initial(upgrade.build_path) in target.module.supported_upgrades)) + whitelisted_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]")) + else + blacklisted_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]")) + .["target"]["whitelisted_upgrades"] = whitelisted_upgrades + .["target"]["blacklisted_upgrades"] = blacklisted_upgrades + var/list/utility_upgrades = list() + for(var/datum/design/item/prosfab/robot_upgrade/utility/upgrade) + if(!(target.has_upgrade(initial(upgrade.build_path)))) + utility_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]")) + .["target"]["utility_upgrades"] = utility_upgrades + var/list/basic_upgrades = list() + for(var/datum/design/item/prosfab/robot_upgrade/basic/upgrade) + if(!(target.has_upgrade(initial(upgrade.build_path)))) + basic_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 0)) + else + basic_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 1)) + .["target"]["basic_upgrades"] = basic_upgrades + var/list/advanced_upgrades = list() + for(var/datum/design/item/prosfab/robot_upgrade/advanced/upgrade) + if(!(target.has_upgrade(initial(upgrade.build_path)))) + advanced_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 0)) + else + advanced_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 1)) + .["target"]["advanced_upgrades"] = advanced_upgrades + var/list/restricted_upgrades = list() + for(var/datum/design/item/prosfab/robot_upgrade/restricted/upgrade) + if(!(target.has_upgrade(initial(upgrade.build_path)))) + if(!(initial(upgrade.build_path) in target.module.supported_upgrades)) + restricted_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 2)) + continue + restricted_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 0)) + else + restricted_upgrades += list(list("name" = initial(upgrade.name), "path" = "[initial(upgrade.build_path)]", "installed" = 1)) + .["target"]["restricted_upgrades"] = restricted_upgrades + var/obj/item/weapon/gun/energy/kinetic_accelerator/kin = locate() in target.module.modules + if(kin) + .["target"]["pka"] = list() + var/list/installed_modkits = list() + for(var/obj/item/borg/upgrade/modkit/modkit in kin.modkits) + installed_modkits += list(list("name" = modkit.name, "ref" = "\ref[modkit]", "costs" = modkit.cost)) + .["target"]["pka"]["installed_modkits"] = installed_modkits + var/list/modkits = list() + for(var/modkit in typesof(/obj/item/borg/upgrade/modkit)) + var/obj/item/borg/upgrade/modkit/single_modkit = modkit + if(single_modkit == /obj/item/borg/upgrade/modkit) + continue + if(kin.get_remaining_mod_capacity() < initial(single_modkit.cost)) + modkits += list(list("name" = initial(single_modkit.name), "path" = single_modkit, "costs" = initial(single_modkit.cost), "denied" = TRUE, "denied_by" = "Insufficient capacity!")) + continue + if(initial(single_modkit.denied_type)) + var/number_of_denied = 0 + var/denied = FALSE + for(var/A in kin.get_modkits()) + var/obj/item/borg/upgrade/modkit/M = A + if(istype(M, initial(single_modkit.denied_type))) + number_of_denied++ + if(number_of_denied >= initial(single_modkit.maximum_of_type)) + modkits += list(list("name" = initial(single_modkit.name), "path" = single_modkit, "costs" = initial(single_modkit.cost), "denied" = TRUE, "denied_by" = "[initial(initial(single_modkit.denied_type).name)]")) + denied = TRUE + break + if(denied) + continue + modkits += list(list("name" = initial(single_modkit.name), "path" = single_modkit, "costs" = initial(single_modkit.cost))) + .["target"]["pka"]["modkits"] = modkits + .["target"]["pka"]["capacity"] = kin.get_remaining_mod_capacity() + .["target"]["pka"]["max_capacity"] = kin.max_mod_capacity + // Section for source data for the module we might want to salvage if(source) .["source"] = list() .["source"]["model"] = source.module @@ -89,6 +164,11 @@ if(.) return switch(action) + if("rename") + target.name = params["new_name"] + target.custom_name = params["new_name"] + target.real_name = params["new_name"] + return TRUE if("select_target") target = locate(params["new_target"]) return TRUE @@ -119,7 +199,7 @@ target.module_reset(FALSE) return TRUE if("add_module") - var/obj/item/add_item = locate(params["new_module"]) + var/obj/item/add_item = locate(params["module"]) if(!add_item) return TRUE source.module.emag.Remove(add_item) @@ -172,7 +252,7 @@ item_with_matter.plastic = target.module.synths[found] return TRUE if("rem_module") - var/obj/item/rem_item = locate(params["old_module"]) + var/obj/item/rem_item = locate(params["module"]) target.uneq_all() target.hud_used.update_robot_modules_display(TRUE) target.module.emag.Remove(rem_item) @@ -180,3 +260,63 @@ target.module.contents.Remove(rem_item) qdel(rem_item) return TRUE + if("swap_module") + if(!source) + return FALSE + var/mod_type = source.modtype + qdel(source.module) + var/module_type = robot_modules[target.modtype] + source.modtype = target.modtype + new module_type(source) + source.sprite_datum = target.sprite_datum + source.update_icon() + source.emag_items = 1 + // Target + target.uneq_all() + target.hud_used.update_robot_modules_display(TRUE) + qdel(target.module) + target.modtype = mod_type + module_type = robot_modules[mod_type] + target.transform_with_anim() + new module_type(target) + target.hands.icon_state = target.get_hud_module_icon() + target.hud_used.update_robot_modules_display() + return TRUE + if("add_compatibility") + target.module.supported_upgrades |= text2path(params["upgrade"]) + return TRUE + if("rem_compatibility") + target.module.supported_upgrades.Remove(text2path(params["upgrade"])) + return TRUE + if("add_upgrade") + var/new_upgrade = text2path(params["upgrade"]) + if(new_upgrade == /obj/item/borg/upgrade/utility/reset) + var/obj/item/borg/upgrade/utility/reset/rmodul = new_upgrade + if(tgui_alert(usr, "Are you sure that you want to install [initial(rmodul.name)] and reset the robot's module?","Confirm",list("Yes","No"))!="Yes") + return FALSE + var/obj/item/borg/upgrade/U = new new_upgrade(null) + if(new_upgrade == /obj/item/borg/upgrade/utility/rename) + var/obj/item/borg/upgrade/utility/rename/UN = U + var/new_name = sanitizeSafe(tgui_input_text(usr, "Enter new robot name", "Robot Reclassification", UN.heldname, MAX_NAME_LEN), MAX_NAME_LEN) + if(new_name) + UN.heldname = new_name + U = UN + if(istype(U, /obj/item/borg/upgrade/restricted)) + target.module.supported_upgrades |= new_upgrade + if(!U.action(target)) + return FALSE + U.loc = target + target.hud_used.update_robot_modules_display() + return TRUE + if("install_modkit") + var/new_modkit = text2path(params["modkit"]) + var/obj/item/weapon/gun/energy/kinetic_accelerator/kin = locate() in target.module.modules + var/obj/item/borg/upgrade/modkit/M = new new_modkit(null) + M.install(kin, target) + return TRUE + if("remove_modkit") + var/obj/item/weapon/gun/energy/kinetic_accelerator/kin = locate() in target.module.modules + var/obj/item/rem_kit = locate(params["modkit"]) + kin.modkits.Remove(rem_kit) + qdel(rem_kit) + return TRUE diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 9e0ebb34d50..606d8bc65e5 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -16,6 +16,7 @@ import { Stack, } from 'tgui/components'; +import { NoSpriteWarning } from '../components'; import { Module, Source, Target } from '../types'; export const ModifyRobotModules = (props: { @@ -29,145 +30,73 @@ export const ModifyRobotModules = (props: { const [searchModuleText, setSearchModulText] = useState(''); return ( - - -
- Robot to salvage - - act('select_source', { - new_source: value, - }) - } - /> - {!!source && ( - <> - - + {!target.active && } + + +
+ Robot to salvage + + act('select_source', { + new_source: value, + }) + } + /> + {!!source && ( + - - setSearchSourceText(value)} - /> - - - - {prepareSearch(source.modules, searchSourceText).map( - (modul_option, i) => { - return ( - - ); - }, - )} - - - - )} -
-
- - -
- {target ? target.module : ''} - act('reset_module')} - tooltip="Allows to reset the module back to default." - > - Reset Module - - - + + + + - ); - }, - )} - - -
-
-
+ + + +
+ {target ? target.module : ''} + act('reset_module')} + tooltip="Allows to reset the module back to default." + > + Reset Module + + + +
+
+ + ); }; @@ -184,3 +113,80 @@ function prepareSearch(modules: Module[], searchText: string = ''): Module[] { }, ])(modules); } + +const SelectionField = (props: { + previewImage: string | null; + searchText: string; + onSearchText: Function; + action: string; + buttonIcon: string; + buttonColor: string; + modules: Module[]; +}) => { + const { act } = useBackend(); + const { + previewImage, + searchText, + onSearchText, + action, + modules, + buttonIcon, + buttonColor, + } = props; + + return ( + <> + + + + onSearchText(value)} + /> + + + + {prepareSearch(modules, searchText).map((modul_option, i) => { + return ( + + ); + })} + + + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotPKA.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotPKA.tsx new file mode 100644 index 00000000000..8df540316e6 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotPKA.tsx @@ -0,0 +1,69 @@ +import { useBackend } from 'tgui/backend'; +import { Box, Button, Flex, NoticeBox } from 'tgui/components'; + +import { NoSpriteWarning } from '../components'; +import { Target } from '../types'; + +export const ModifyRobotPKA = (props: { target: Target }) => { + const { act } = useBackend(); + const { target } = props; + + return ( + <> + {!target.active && } + {!target.pka ? ( + {target.name} has no PKA installed. + ) : ( + + + Remaining Capacity: {target.pka.capacity} + {target.pka.modkits.map((modkit, i) => { + return ( + + ); + })} + + + + + Used Capacity: {target.pka.max_capacity - target.pka.capacity} + + {target.pka.installed_modkits.map((modkit, i) => { + return ( + + ); + })} + + + )} + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx new file mode 100644 index 00000000000..e2ee0026408 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx @@ -0,0 +1,110 @@ +import { useBackend } from 'tgui/backend'; +import { Button, Flex, Image, Section, Stack } from 'tgui/components'; + +import { NoSpriteWarning } from '../components'; +import { install2col } from '../constants'; +import { Target, Upgrade } from '../types'; + +export const ModifyRobotUpgrades = (props: { target: Target }) => { + const { target } = props; + + return ( + <> + {!target.active && } + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const UpgradeSection = (props: { + title: string; + upgrades: Upgrade[]; + action: string; +}) => { + const { act } = useBackend(); + const { title, upgrades, action } = props; + return ( +
+ + + {upgrades.map((upgrade, i) => { + return ( + + ); + })} + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/components.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/components.tsx new file mode 100644 index 00000000000..60d3219e4db --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/components.tsx @@ -0,0 +1,12 @@ +import { NoticeBox } from 'tgui/components'; + +export const NoSpriteWarning = (props: { name: string }) => { + const { name } = props; + + return ( + + Warning, {name} has not yet chosen a sprite. Functionality might be + limited. + + ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts b/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts new file mode 100644 index 00000000000..ab554eb3c3e --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/constants.ts @@ -0,0 +1,6 @@ +export const install2col = { + undefined: '', + 0: 'red', + 1: 'green', + 2: 'grey', +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index 438d89f5b71..330bdb2b1a5 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -2,16 +2,21 @@ import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { Box, + Button, Divider, Dropdown, + Input, LabeledList, NoticeBox, + Stack, Tabs, } from 'tgui/components'; import { Window } from 'tgui/layouts'; import { ModifyRobotNoModule } from './ModifyRobotNoModule'; import { ModifyRobotModules } from './ModifyRobotTabs/ModifyRobotModules'; +import { ModifyRobotPKA } from './ModifyRobotTabs/ModifyRobotPKA'; +import { ModifyRobotUpgrades } from './ModifyRobotTabs/ModifyRobotUpgrades'; import { Data } from './types'; export const ModifyRobot = (props) => { @@ -19,7 +24,8 @@ export const ModifyRobot = (props) => { const { target, all_robots, source, model_options } = data; - const [tab, setTab] = useState(0); + const [tab, setTab] = useState(0); + const [robotName, setRobotName] = useState(target ? target.name : ''); const tabs: React.JSX.Element[] = []; @@ -30,16 +36,17 @@ export const ModifyRobot = (props) => { model_options={model_options!} /> ); - tabs[1] = ; - tabs[2] = ; + tabs[1] = ; + tabs[2] = ; tabs[3] = ; tabs[4] = ; tabs[5] = ; tabs[6] = ; + tabs[7] = ; return ( - - + + {target ? ( {target.name} @@ -50,15 +57,42 @@ export const ModifyRobot = (props) => { )} - - act('select_target', { - new_target: value, - }) - } - /> + + + + act('select_target', { + new_target: value, + }) + } + /> + + {!!target && ( + <> + + setRobotName(value)} + /> + + + + + + )} + @@ -75,18 +109,21 @@ export const ModifyRobot = (props) => { Upgrade Manager setTab(2)}> - Radio Manager + PKA setTab(3)}> - Component Manager + Radio Manager setTab(4)}> - Access Manager + Component Manager setTab(5)}> - Law Manager + Access Manager setTab(6)}> + Law Manager + + setTab(7)}> Law Sets diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index b0e6bf2a462..599fb4fb5e3 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -16,6 +16,7 @@ export type Target = { name: string; ckey: string; module: string; + active: BooleanLike; crisis_override: BooleanLike; active_restrictions: string[]; possible_restrictions: string[]; @@ -23,6 +24,32 @@ export type Target = { side: string | null; back: string | null; modules: Module[]; + whitelisted_upgrades: Upgrade[]; + blacklisted_upgrades: Upgrade[]; + utility_upgrades: Upgrade[]; + basic_upgrades: Upgrade[]; + advanced_upgrades: Upgrade[]; + restricted_upgrades: Upgrade[]; + pka: + | { + modkits: { + name: string; + path: string; + costs: number; + denied: BooleanLike; + denied_by: string; + }[]; + installed_modkits: { name: string; ref: string; costs: number }[]; + capacity: number; + max_capacity: number; + } + | undefined; +}; + +export type Upgrade = { + name: string; + path: string; + installed: number; }; export type Source = { From 4145064a0586d183e8d7dbbd5f56f96b04232cfe Mon Sep 17 00:00:00 2001 From: Kashargul Date: Thu, 19 Sep 2024 20:55:37 +0200 Subject: [PATCH 10/21] static --- code/modules/admin/modify_robot.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 62f812ff22b..216367e07a8 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -122,7 +122,8 @@ if(istype(M, initial(single_modkit.denied_type))) number_of_denied++ if(number_of_denied >= initial(single_modkit.maximum_of_type)) - modkits += list(list("name" = initial(single_modkit.name), "path" = single_modkit, "costs" = initial(single_modkit.cost), "denied" = TRUE, "denied_by" = "[initial(initial(single_modkit.denied_type).name)]")) + var/obj/item/denied_type = initial(single_modkit.denied_type) + modkits += list(list("name" = initial(single_modkit.name), "path" = single_modkit, "costs" = initial(single_modkit.cost), "denied" = TRUE, "denied_by" = "[initial(denied_type.name)]")) denied = TRUE break if(denied) From da707c15f7cf1d07eaf91aeeed8151b1b1a04232 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Fri, 20 Sep 2024 00:50:05 +0200 Subject: [PATCH 11/21] searches, thanks Shadow for helpting with the function generalization --- code/modules/admin/modify_robot.dm | 51 ++++++- .../ModifyRobotTabs/ModifyRobotModules.tsx | 57 ++++---- .../ModifyRobotTabs/ModifyRobotPKA.tsx | 108 +++++++++++---- .../ModifyRobotTabs/ModifyRobotRadio.tsx | 125 ++++++++++++++++++ .../ModifyRobotTabs/ModifyRobotUpgrades.tsx | 49 ++++++- .../tgui/interfaces/ModifyRobot/functions.ts | 28 ++++ .../tgui/interfaces/ModifyRobot/index.tsx | 13 +- .../tgui/interfaces/ModifyRobot/types.ts | 14 +- 8 files changed, 378 insertions(+), 67 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/functions.ts diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 216367e07a8..59da4550be3 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -51,10 +51,11 @@ .["target"]["active"] = target.icon_selected .["target"]["front"] = icon2base64(get_flat_icon(target,dir=SOUTH,no_anim=TRUE)) .["target"]["side"] = icon2base64(get_flat_icon(target,dir=WEST,no_anim=TRUE)) + .["target"]["side_alt"] = icon2base64(get_flat_icon(target,dir=EAST,no_anim=TRUE)) .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) var/list/target_items = list() for(var/obj/item in target.module.modules) - target_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) + target_items += list(list("name" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) .["target"]["modules"] = target_items var/list/module_options = list() for(var/module in robot_modules) @@ -102,6 +103,7 @@ var/obj/item/weapon/gun/energy/kinetic_accelerator/kin = locate() in target.module.modules if(kin) .["target"]["pka"] = list() + .["target"]["pka"]["name"] = kin.name var/list/installed_modkits = list() for(var/obj/item/borg/upgrade/modkit/modkit in kin.modkits) installed_modkits += list(list("name" = modkit.name, "ref" = "\ref[modkit]", "costs" = modkit.cost)) @@ -132,6 +134,16 @@ .["target"]["pka"]["modkits"] = modkits .["target"]["pka"]["capacity"] = kin.get_remaining_mod_capacity() .["target"]["pka"]["max_capacity"] = kin.max_mod_capacity + // Radio section + var/list/radio_channels = list() + for(var/channel in target.radio.channels) + radio_channels += channel + var/list/availalbe_channels = list() + for(var/channel in (radiochannels - target.radio.channels)) + availalbe_channels += channel + .["target"]["radio_channels"] = radio_channels + .["target"]["availalbe_channels"] = availalbe_channels + // Section for source data for the module we might want to salvage if(source) .["source"] = list() @@ -146,7 +158,7 @@ break if(exists) continue - source_items += list(list("item" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) + source_items += list(list("name" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) .["source"]["modules"] = source_items var/list/all_robots = list() for(var/mob/living/silicon/robot/R in silicon_mob_list) @@ -283,6 +295,10 @@ target.hands.icon_state = target.get_hud_module_icon() target.hud_used.update_robot_modules_display() return TRUE + if("ert_toggle") + target.crisis_override = !target.crisis_override + target.module_reset(FALSE) + return TRUE if("add_compatibility") target.module.supported_upgrades |= text2path(params["upgrade"]) return TRUE @@ -321,3 +337,34 @@ kin.modkits.Remove(rem_kit) qdel(rem_kit) return TRUE + if("add_channel") + var/selected_radio_channel = params["channel"] + if(selected_radio_channel == CHANNEL_SPECIAL_OPS) + target.radio.centComm = 1 + if(selected_radio_channel == CHANNEL_RAIDER) + qdel(target.radio.keyslot) + target.radio.keyslot = new /obj/item/device/encryptionkey/raider(target) + target.radio.syndie = 1 + if(selected_radio_channel == CHANNEL_MERCENARY) + qdel(target.radio.keyslot) + target.radio.keyslot = new /obj/item/device/encryptionkey/syndicate(target) + target.radio.syndie = 1 + target.module.channels += list("[selected_radio_channel]" = 1) + target.radio.channels[selected_radio_channel] += target.module.channels[selected_radio_channel] + target.radio.secure_radio_connections[selected_radio_channel] += radio_controller.add_object(target.radio, radiochannels[selected_radio_channel], RADIO_CHAT) + return TRUE + if("rem_channel") + var/selected_radio_channel = params["channel"] + if(selected_radio_channel == CHANNEL_SPECIAL_OPS) + target.radio.centComm = 0 + target.module.channels -= selected_radio_channel + if((selected_radio_channel == CHANNEL_MERCENARY || selected_radio_channel == CHANNEL_RAIDER) && !(target.module.channels[CHANNEL_RAIDER] || target.module.channels[CHANNEL_MERCENARY])) + qdel(target.radio.keyslot) + target.radio.keyslot = null + target.radio.syndie = 0 + target.radio.channels = list() + for(var/n_chan in target.module.channels) + target.radio.channels[n_chan] -= target.module.channels[n_chan] + radio_controller.remove_object(target.radio, radiochannels[selected_radio_channel]) + target.radio.secure_radio_connections -= selected_radio_channel + return TRUE diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 606d8bc65e5..460865679f4 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -1,6 +1,3 @@ -import { filter } from 'common/collections'; -import { flow } from 'common/fp'; -import { createSearch } from 'common/string'; import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { @@ -17,6 +14,7 @@ import { } from 'tgui/components'; import { NoSpriteWarning } from '../components'; +import { prepareSearch } from '../functions'; import { Module, Source, Target } from '../types'; export const ModifyRobotModules = (props: { @@ -61,13 +59,34 @@ export const ModifyRobotModules = (props: {
- - ); - })} + + setSearchModkitText(value)} + /> + + {prepareSearch(target.pka.modkits, searchModkitText).map( + (modkit, i) => { + return ( + + ); + }, + )} - - + + + + + + + Used Capacity: {target.pka.max_capacity - target.pka.capacity} - {target.pka.installed_modkits.map((modkit, i) => { + + setSearchInstalledtext(value)} + /> + + {prepareSearch( + target.pka.installed_modkits, + searchInstalledtext, + ).map((modkit, i) => { return ( + ); + })} + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx index e2ee0026408..6bdd9a7eae7 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotUpgrades.tsx @@ -1,12 +1,34 @@ +import { useState } from 'react'; import { useBackend } from 'tgui/backend'; -import { Button, Flex, Image, Section, Stack } from 'tgui/components'; +import { + Button, + Divider, + Flex, + Image, + Input, + Section, + Stack, +} from 'tgui/components'; import { NoSpriteWarning } from '../components'; import { install2col } from '../constants'; +import { prepareSearch } from '../functions'; import { Target, Upgrade } from '../types'; export const ModifyRobotUpgrades = (props: { target: Target }) => { const { target } = props; + const [searchAddCompatibilityText, setSearchAddCompatibilityText] = + useState(''); + const [searchRemoveCompatibilityText, setSearchRemoveCompatibilityText] = + useState(''); + const [searchUtilityUpgradeText, setsearchUtilityUpgradeText] = + useState(''); + const [searchBasicUpgradeText, setSearchBasicUpgradeText] = + useState(''); + const [searchAdvancedUpgradeText, setSearchAdvancedUpgradeText] = + useState(''); + const [searchRestrictedUpgradeText, setSearchRestrictedUpgradeText] = + useState(''); return ( <> @@ -15,6 +37,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -33,6 +57,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -42,6 +68,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -49,6 +77,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -56,6 +86,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -63,6 +95,8 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { @@ -74,16 +108,25 @@ export const ModifyRobotUpgrades = (props: { target: Target }) => { const UpgradeSection = (props: { title: string; + searchText: string; + onSearchText: Function; upgrades: Upgrade[]; action: string; }) => { const { act } = useBackend(); - const { title, upgrades, action } = props; + const { title, searchText, onSearchText, upgrades, action } = props; return (
+ onSearchText(value)} + /> + - {upgrades.map((upgrade, i) => { + {prepareSearch(upgrades, searchText).map((upgrade, i) => { return ( + ); + })} + + +
+ ); +}; + +function checkDisabled( + component: Component, + action: string, + selected_cell: string | undefined, + cell: string | undefined, +): boolean { + switch (action) { + case 'rem_component': + return !component.exists; + case 'add_component': + if ( + selected_cell && + cell && + component.name === 'power cell' && + selected_cell !== cell + ) { + return false; + } + return ( + component.installed === 1 && + !!component.exists && + component.brute_damage === 0 && + component.electronics_damage === 0 + ); + } + return false; +} + +function getComponentTooltip( + component: Component, + action: string, + selected_cell: string | undefined, + cell: string | undefined, +): string { + switch (action) { + case 'add_component': + if (component.installed === 0 || !component.exists) { + return 'Component missing!'; + } + if ( + component.installed === -1 || + component.brute_damage + component.electronics_damage >= + component.max_damage + ) { + return 'Component destroyed!'; + } + if (checkDisabled(component, action, selected_cell, cell)) { + return 'Disabled due to fully intact component!'; + } + return ''; + case 'rem_component': + return component.exists ? '' : 'Disabled due to missing component!'; + } + return ''; +} + +function getComponentColor( + component: Component, + action: string, +): string | undefined { + switch (action) { + case 'add_component': + if ( + component.brute_damage + component.electronics_damage >= + component.max_damage || + component.installed !== 1 || + !component.exists + ) { + return 'black'; + } + if ( + (component.brute_damage + component.electronics_damage) / + component.max_damage > + 0.66 + ) { + return 'red'; + } + if ( + (component.brute_damage + component.electronics_damage) / + component.max_damage > + 0.33 + ) { + return 'orange'; + } + if ( + (component.brute_damage + component.electronics_damage) / + component.max_damage > + 0 + ) { + return 'yellow'; + } + return undefined; + case 'rem_component': + return undefined; + } + return ''; +} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx index 460865679f4..1e6280675c7 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotModules.tsx @@ -1,3 +1,4 @@ +import { capitalize } from 'common/string'; import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { @@ -177,7 +178,9 @@ const SelectionField = (props: { - {modul_option.name} + + {capitalize(modul_option.name)} + { const { act } = useBackend(); @@ -57,7 +58,7 @@ export const ModifyRobotPKA = (props: { target: Target }) => { }) } > - {modkit.name} {modkit.costs} + {capitalize(modkit.name)} {modkit.costs} ); }, @@ -66,7 +67,7 @@ export const ModifyRobotPKA = (props: { target: Target }) => { @@ -99,7 +100,7 @@ export const ModifyRobotPKA = (props: { target: Target }) => { }) } > - {modkit.name} {modkit.costs} + {capitalize(modkit.name)} {modkit.costs} ); })} @@ -109,13 +110,3 @@ export const ModifyRobotPKA = (props: { target: Target }) => { ); }; - -function getPKAIcon(modules: Module[], name: string) { - if (modules) { - const module = modules.filter((module) => module.name === name); - if (module.length > 0) { - return module[0].icon; - } - } - return ''; -} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx index 1c72109e382..5af3a8cd063 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotRadio.tsx @@ -1,3 +1,4 @@ +import { capitalize } from 'common/string'; import { useState } from 'react'; import { useBackend } from 'tgui/backend'; import { @@ -105,7 +106,7 @@ const RadioSection = (props: { } > - {channel} + {capitalize(channel)} - {upgrade.name} + {capitalize(upgrade.name)} ); })} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/functions.ts b/tgui/packages/tgui/interfaces/ModifyRobot/functions.ts index 8c0b1656515..81386eb291f 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/functions.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/functions.ts @@ -2,6 +2,8 @@ import { filter } from 'common/collections'; import { flow } from 'common/fp'; import { createSearch } from 'common/string'; +import { Module } from './types'; + type SearchObject = string | { name: string }; export function prepareSearch( @@ -26,3 +28,13 @@ export function prepareSearch( }, ])(objects); } + +export function getModuleIcon(modules: Module[], name: string) { + if (modules) { + const module = modules.filter((module) => module.name === name); + if (module.length > 0) { + return module[0].icon; + } + } + return ''; +} diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index c1f3a854e47..fb077a2cbbe 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -14,6 +14,7 @@ import { import { Window } from 'tgui/layouts'; import { ModifyRobotNoModule } from './ModifyRobotNoModule'; +import { ModifyRobotComponent } from './ModifyRobotTabs/ModifyRobotComponent'; import { ModifyRobotModules } from './ModifyRobotTabs/ModifyRobotModules'; import { ModifyRobotPKA } from './ModifyRobotTabs/ModifyRobotPKA'; import { ModifyRobotRadio } from './ModifyRobotTabs/ModifyRobotRadio'; @@ -23,7 +24,8 @@ import { Data } from './types'; export const ModifyRobot = (props) => { const { act, data } = useBackend(); - const { target, all_robots, source, model_options } = data; + const { target, all_robots, source, model_options, cell, cell_options } = + data; const [tab, setTab] = useState(0); const [robotName, setRobotName] = useState(target ? target.name : ''); @@ -46,7 +48,9 @@ export const ModifyRobot = (props) => { tabs[1] = ; tabs[2] = ; tabs[3] = ; - tabs[4] = ; + tabs[4] = ( + + ); tabs[5] = ; tabs[6] = ; tabs[7] = ; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index 068cf7d2ca4..cd20ea649d5 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -5,6 +5,8 @@ export type Data = { target: Target | null; all_robots: DropdownEntry[]; model_options: string[] | null; + cell: string | null; + cell_options: Record; }; export type DropdownEntry = { @@ -33,21 +35,8 @@ export type Target = { restricted_upgrades: Upgrade[]; radio_channels: string[]; availalbe_channels: string[]; - pka: - | { - name: string; - modkits: { - name: string; - path: string; - costs: number; - denied: BooleanLike; - denied_by: string; - }[]; - installed_modkits: { name: string; ref: string; costs: number }[]; - capacity: number; - max_capacity: number; - } - | undefined; + pka: PKA | undefined; + components: Component[]; }; export type Upgrade = { @@ -63,3 +52,35 @@ export type Source = { } | null; export type Module = { name: string; ref: string; icon: string; desc: string }; + +export type Component = { + name: string; + ref: string; + brute_damage: number; + electronics_damage: number; + max_damage: number; + installed: number; + exists: BooleanLike; +}; + +export type PKA = { + name: string; + modkits: { + name: string; + path: string; + costs: number; + denied: BooleanLike; + denied_by: string; + }[]; + installed_modkits: { name: string; ref: string; costs: number }[]; + capacity: number; + max_capacity: number; +}; + +export type Cell = { + path: string; + charge: number; + max_charge: number; + charge_amount: number; + self_charge: BooleanLike; +}; From d2b061a9c52f9049cc9290cf5a4b9ecc92141c23 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 00:24:54 +0200 Subject: [PATCH 13/21] should be 0 when we delete --- code/modules/admin/modify_robot.dm | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 98fd0fdcd1b..69bce786798 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -330,6 +330,8 @@ C.wrapped = new /obj/item/robot_parts/robot_component/binary_communication_device(target) else if(istype(C, /datum/robot_component/armour)) C.wrapped = new /obj/item/robot_parts/robot_component/armour(target) + C.brute_damage = 0 + C.electronics_damage = 0 C.install() C.installed = 1 return TRUE @@ -338,6 +340,8 @@ if(!C.wrapped) return FALSE C.uninstall() + C.brute_damage = 0 + C.electronics_damage = 0 C.installed = 0 qdel(C.wrapped) C.wrapped = null From 7500b4882cfbef00018e51122a6ff312665cd3a5 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 02:13:14 +0200 Subject: [PATCH 14/21] Access Tab --- code/game/jobs/access_datum.dm | 3 + code/modules/admin/modify_robot.dm | 90 ++++++--- .../ModifyRobotTabs/ModifyRobotAccess.tsx | 180 ++++++++++++++++++ .../ModifyRobotTabs/ModifyRobotComponent.tsx | 4 +- .../ModifyRobotTabs/ModifyRobotModules.tsx | 5 +- .../tgui/interfaces/ModifyRobot/index.tsx | 21 +- .../tgui/interfaces/ModifyRobot/types.ts | 5 + 7 files changed, 275 insertions(+), 33 deletions(-) create mode 100644 tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx diff --git a/code/game/jobs/access_datum.dm b/code/game/jobs/access_datum.dm index 32773362a01..d5d9e201392 100644 --- a/code/game/jobs/access_datum.dm +++ b/code/game/jobs/access_datum.dm @@ -493,6 +493,7 @@ var/const/access_pilot = 67 /var/const/access_syndicate = 150//General Syndicate Access /datum/access/syndicate id = access_syndicate + desc = "Syndicate" access_type = ACCESS_TYPE_SYNDICATE /******* @@ -507,11 +508,13 @@ var/const/access_pilot = 67 /var/const/access_crate_cash = 200 /datum/access/crate_cash id = access_crate_cash + desc = "Crate cash" access_type = ACCESS_TYPE_NONE /var/const/access_trader = 160//General Beruang Trader Access /datum/access/trader id = access_trader + desc = "Trader" access_type = ACCESS_TYPE_PRIVATE /var/const/access_alien = 300 // For things like crashed ships. diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 69bce786798..c02457152f6 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -53,17 +53,13 @@ .["target"]["side"] = icon2base64(get_flat_icon(target,dir=WEST,no_anim=TRUE)) .["target"]["side_alt"] = icon2base64(get_flat_icon(target,dir=EAST,no_anim=TRUE)) .["target"]["back"] = icon2base64(get_flat_icon(target,dir=NORTH,no_anim=TRUE)) - var/list/target_items = list() - for(var/obj/item in target.module.modules) - target_items += list(list("name" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) - .["target"]["modules"] = target_items + .["target"]["modules"] = get_target_items(user) var/list/module_options = list() for(var/module in robot_modules) module_options += module .["model_options"] = module_options // Data for the upgrade options .["target"] += get_upgrades() - var/obj/item/weapon/gun/energy/kinetic_accelerator/kin = locate() in target.module.modules if(kin) .["target"]["pka"] += get_pka(kin) @@ -77,29 +73,21 @@ .["target"]["radio_channels"] = radio_channels .["target"]["availalbe_channels"] = availalbe_channels // Components - var/list/components = list() - for(var/entry in target.components) - var/datum/robot_component/C = target.components[entry] - components += list(list("name" = C.name, "ref" = "\ref[C]", "brute_damage" = C.brute_damage, "electronics_damage" = C.electronics_damage, "max_damage" = C.max_damage, "installed" = C.installed, "exists" = (C.wrapped ? TRUE : FALSE))) - .["target"]["components"] = components + .["target"]["components"] = get_components() .["cell"] = target.cell?.name - var/list/cell_options = list() - for(var/cell in typesof(/obj/item/weapon/cell)) - var/obj/item/weapon/cell/C = cell - if(initial(C.name) == "power cell") - continue - if(ispath(C, /obj/item/weapon/cell/standin)) - continue - if(ispath(C, /obj/item/weapon/cell/device)) - continue - if(ispath(C, /obj/item/weapon/cell/mech)) - continue - if(cell_options[initial(C.name)]) // empty cells are defined after normal cells! - continue - cell_options += list(initial(C.name) = list("path" = "[C]", "charge" = initial(C.maxcharge), "max_charge" = initial(C.maxcharge), "charge_amount" = initial(C.charge_amount) , "self_charge" = initial(C.self_recharge))) // our cells do not have their charge predefined, they do it on init, so both maaxcharge for now - .["cell_options"] = cell_options + .["cell_options"] = get_cells() // Access - //.["target"]["id_icon"] = icon2html(target.idcard, user, sourceonly=TRUE) + .["id_icon"] = icon2html(target.idcard, user, sourceonly=TRUE) + var/list/active_access = list() + for(var/access in target.idcard?.GetAccess()) + active_access += list(list("id" = access, "name" = get_access_desc(access))) + .["target"]["active_access"] = active_access + var/list/access_options = list() + for(var/datum/access/acc) + if(acc.id in target.idcard?.GetAccess()) + continue + access_options += list(list("id" = acc.id, "name" = acc.desc)) + .["access_options"] = access_options // Section for source data for the module we might want to salvage if(source) .["source"] += get_module_source(user) @@ -348,6 +336,32 @@ if(istype(C, /datum/robot_component/cell)) target.cell = null return TRUE + if("add_access") + target.idcard.access += text2num(params["access"]) + return TRUE + if("rem_access") + target.idcard.access -= text2num(params["access"]) + return TRUE + if("add_centcom") + target.idcard.access |= get_all_centcom_access() + return TRUE + if("rem_centcom") + target.idcard.access -= get_all_centcom_access() + return TRUE + if("add_station") + target.idcard.access |= get_all_station_access() + target.idcard.access |= access_synth + return TRUE + if("rem_station") + target.idcard.access -= get_all_station_access() + target.idcard.access -= access_synth + return TRUE + +/datum/eventkit/modify_robot/proc/get_target_items(var/mob/user) + var/list/target_items = list() + for(var/obj/item in target.module.modules) + target_items += list(list("name" = item.name, "ref" = "\ref[item]", "icon" = icon2html(item, user, sourceonly=TRUE), "desc" = item.desc)) + return target_items /datum/eventkit/modify_robot/proc/get_module_source(var/mob/user) var/list/source_list = list() @@ -452,3 +466,27 @@ pka["capacity"] = kin.get_remaining_mod_capacity() pka["max_capacity"] = kin.max_mod_capacity return pka + +/datum/eventkit/modify_robot/proc/get_cells() + var/list/cell_options = list() + for(var/cell in typesof(/obj/item/weapon/cell)) + var/obj/item/weapon/cell/C = cell + if(initial(C.name) == "power cell") + continue + if(ispath(C, /obj/item/weapon/cell/standin)) + continue + if(ispath(C, /obj/item/weapon/cell/device)) + continue + if(ispath(C, /obj/item/weapon/cell/mech)) + continue + if(cell_options[initial(C.name)]) // empty cells are defined after normal cells! + continue + cell_options += list(initial(C.name) = list("path" = "[C]", "charge" = initial(C.maxcharge), "max_charge" = initial(C.maxcharge), "charge_amount" = initial(C.charge_amount) , "self_charge" = initial(C.self_recharge))) // our cells do not have their charge predefined, they do it on init, so both maaxcharge for now + return cell_options + +/datum/eventkit/modify_robot/proc/get_components() + var/list/components = list() + for(var/entry in target.components) + var/datum/robot_component/C = target.components[entry] + components += list(list("name" = C.name, "ref" = "\ref[C]", "brute_damage" = C.brute_damage, "electronics_damage" = C.electronics_damage, "max_damage" = C.max_damage, "installed" = C.installed, "exists" = (C.wrapped ? TRUE : FALSE))) + return components diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx new file mode 100644 index 00000000000..4c61e67f0d3 --- /dev/null +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotAccess.tsx @@ -0,0 +1,180 @@ +import { capitalize } from 'common/string'; +import { useState } from 'react'; +import { useBackend } from 'tgui/backend'; +import { + Button, + Divider, + Flex, + Icon, + Image, + Input, + Section, + Stack, +} from 'tgui/components'; + +import { NoSpriteWarning } from '../components'; +import { prepareSearch } from '../functions'; +import { Access, Target } from '../types'; + +export const ModifyRobotAccess = (props: { + target: Target; + tab_icon: string; + all_access: Access[]; +}) => { + const { act } = useBackend(); + const { target, tab_icon, all_access } = props; + const [searchAccessAll, setSearchAccessAll] = useState(''); + const [searchAccessActive, setSearchAccessActive] = useState(''); + + return ( + <> + {!target.active && } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ); +}; + +const AccessSection = (props: { + title: string; + searchText: string; + onSearchText: Function; + access: Access[]; + action: string; + buttonColor: string; + buttonIcon: string; +}) => { + const { act } = useBackend(); + const { + title, + searchText, + onSearchText, + access, + action, + buttonColor, + buttonIcon, + } = props; + return ( +
+ onSearchText(value)} + /> + + + + {prepareSearch(access, searchText).map((acc, i) => { + return ( + + ); + })} + + +
+ ); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx index 109854f090d..fd644c429c1 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx @@ -35,7 +35,7 @@ export const ModifyRobotComponent = (props: { <> {!target.active && } - + - + - @@ -72,7 +72,7 @@ export const ModifyRobotAccess = (props: { icon="satellite" onClick={() => act('rem_station')} > - Remove all station access + Remove station access @@ -86,7 +86,7 @@ export const ModifyRobotAccess = (props: { icon="building" onClick={() => act('add_centcom')} > - Add all centcom access + Add centcom access
From 41785501981f397e9ec2ae8f22f0fdad657dba41 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 03:46:20 +0200 Subject: [PATCH 16/21] integrate law manager --- code/modules/admin/modify_robot.dm | 139 +++++++++++ tgui/packages/tgui/interfaces/LawManager.tsx | 217 +++++++++++++++--- .../tgui/interfaces/ModifyRobot/index.tsx | 61 ++++- .../tgui/interfaces/ModifyRobot/types.ts | 42 ++++ 4 files changed, 422 insertions(+), 37 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index c02457152f6..429f99805d4 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -12,9 +12,18 @@ /datum/eventkit/modify_robot var/mob/living/silicon/robot/target var/mob/living/silicon/robot/source + var/ion_law = "IonLaw" + var/zeroth_law = "ZerothLaw" + var/inherent_law = "InherentLaw" + var/supplied_law = "SuppliedLaw" + var/supplied_law_position = MIN_SUPPLIED_LAW_NUMBER + var/list/datum/ai_laws/law_list /datum/eventkit/modify_robot/New() . = ..() + law_list = new() + init_subtypes(/datum/ai_laws, law_list) + law_list = dd_sortedObjectList(law_list) /datum/eventkit/modify_robot/tgui_close() if(source) @@ -97,6 +106,27 @@ continue all_robots += list(list("displayText" = "[R]", "value" = "\ref[R]")) .["all_robots"] = all_robots + // Law data + .["ion_law_nr"] = ionnum() + .["ion_law"] = ion_law + .["zeroth_law"] = zeroth_law + .["inherent_law"] = inherent_law + .["supplied_law"] = supplied_law + .["supplied_law_position"] = supplied_law_position + + package_laws(., "zeroth_laws", list(target.laws.zeroth_law)) + package_laws(., "ion_laws", target.laws.ion_laws) + package_laws(., "inherent_laws", target.laws.inherent_laws) + package_laws(., "supplied_laws", target.laws.supplied_laws) + + .["isAI"] = isAI(target) + + var/list/channels = list() + for(var/ch_name in target.law_channels()) + channels[++channels.len] = list("channel" = ch_name) + .["channel"] = target.lawchannel + .["channels"] = channels + .["law_sets"] = package_multiple_laws(law_list) /datum/eventkit/modify_robot/tgui_state(mob/user) @@ -356,6 +386,96 @@ target.idcard.access -= get_all_station_access() target.idcard.access -= access_synth return TRUE + if("law_channel") + if(params["law_channel"] in target.law_channels()) + target.lawchannel = params["law_channel"] + return TRUE + if("state_law") + var/datum/ai_law/AL = locate(params["ref"]) in target.laws.all_laws() + if(AL) + var/state_law = text2num(params["state_law"]) + target.laws.set_state_law(AL, state_law) + return TRUE + if("add_zeroth_law") + if(zeroth_law && !target.laws.zeroth_law) + target.set_zeroth_law(zeroth_law) + return TRUE + if("add_ion_law") + if(ion_law) + target.add_ion_law(ion_law) + return TRUE + if("add_inherent_law") + if(inherent_law) + target.add_inherent_law(inherent_law) + return TRUE + if("add_supplied_law") + if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER) + target.add_supplied_law(supplied_law_position, supplied_law) + return TRUE + if("change_zeroth_law") + var/new_law = sanitize(params["val"]) + if(new_law && new_law != zeroth_law) + zeroth_law = new_law + return TRUE + if("change_ion_law") + var/new_law = sanitize(params["val"]) + if(new_law && new_law != ion_law) + ion_law = new_law + return TRUE + if("change_inherent_law") + var/new_law = sanitize(params["val"]) + if(new_law && new_law != inherent_law) + inherent_law = new_law + return TRUE + if("change_supplied_law") + var/new_law = sanitize(params["val"]) + if(new_law && new_law != supplied_law) + supplied_law = new_law + return TRUE + if("change_supplied_law_position") + var/new_position = tgui_input_number(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position, MAX_SUPPLIED_LAW_NUMBER, 1) + if(isnum(new_position)) + supplied_law_position = CLAMP(new_position, 1, MAX_SUPPLIED_LAW_NUMBER) + return TRUE + if("edit_law") + var/datum/ai_law/AL = locate(params["edit_law"]) in target.laws.all_laws() + if(AL) + var/new_law = sanitize(tgui_input_text(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", AL.law)) + if(new_law && new_law != AL.law) + log_and_message_admins("has changed a law of [target] from '[AL.law]' to '[new_law]'") + AL.law = new_law + return TRUE + if("delete_law") + var/datum/ai_law/AL = locate(params["delete_law"]) in target.laws.all_laws() + if(AL) + target.delete_law(AL) + return TRUE + if("state_laws") + target.statelaws(target.laws) + return TRUE + if("state_law_set") + var/datum/ai_laws/ALs = locate(params["state_law_set"]) in law_list + if(ALs) + target.statelaws(ALs) + return TRUE + if("transfer_laws") + var/datum/ai_laws/ALs = locate(params["transfer_laws"]) in law_list + if(ALs) + log_and_message_admins("has transfered the [ALs.name] laws to [target].") + ALs.sync(target, 0) + return TRUE + + if("notify_laws") + to_chat(target, "Law Notice") + target.laws.show_laws(target) + if(isAI(target)) + var/mob/living/silicon/ai/AI = target + for(var/mob/living/silicon/robot/R in AI.connected_robots) + to_chat(R, "Law Notice") + R.laws.show_laws(R) + if(usr != target) + to_chat(usr, "Laws displayed.") + return TRUE /datum/eventkit/modify_robot/proc/get_target_items(var/mob/user) var/list/target_items = list() @@ -490,3 +610,22 @@ var/datum/robot_component/C = target.components[entry] components += list(list("name" = C.name, "ref" = "\ref[C]", "brute_damage" = C.brute_damage, "electronics_damage" = C.electronics_damage, "max_damage" = C.max_damage, "installed" = C.installed, "exists" = (C.wrapped ? TRUE : FALSE))) return components + +/datum/eventkit/modify_robot/proc/package_laws(var/list/data, var/field, var/list/datum/ai_law/laws) + var/list/packaged_laws = list() + for(var/datum/ai_law/AL in laws) + packaged_laws[++packaged_laws.len] = list("law" = AL.law, "index" = AL.get_index(), "state" = target.laws.get_state_law(AL), "ref" = "\ref[AL]") + data[field] = packaged_laws + data["has_[field]"] = packaged_laws.len + +/datum/eventkit/modify_robot/proc/package_multiple_laws(var/list/datum/ai_laws/laws) + var/list/law_sets = list() + for(var/datum/ai_laws/ALs in laws) + var/list/packaged_laws = list() + package_laws(packaged_laws, "zeroth_laws", list(ALs.zeroth_law, ALs.zeroth_law_borg)) + package_laws(packaged_laws, "ion_laws", ALs.ion_laws) + package_laws(packaged_laws, "inherent_laws", ALs.inherent_laws) + package_laws(packaged_laws, "supplied_laws", ALs.supplied_laws) + law_sets[++law_sets.len] = list("name" = ALs.name, "header" = ALs.law_header, "ref" = "\ref[ALs]","laws" = packaged_laws) + + return law_sets diff --git a/tgui/packages/tgui/interfaces/LawManager.tsx b/tgui/packages/tgui/interfaces/LawManager.tsx index 3632166b60f..2b2838c7d00 100644 --- a/tgui/packages/tgui/interfaces/LawManager.tsx +++ b/tgui/packages/tgui/interfaces/LawManager.tsx @@ -1,4 +1,7 @@ +import { filter } from 'common/collections'; +import { flow } from 'common/fp'; import { BooleanLike } from 'common/react'; +import { createSearch } from 'common/string'; import { useBackend, useSharedState } from '../backend'; import { @@ -76,30 +79,12 @@ export const LawManager = (props) => { }; const LawManagerContent = (props) => { + const { data } = useBackend(); const [tabIndex, setTabIndex] = useSharedState('lawsTabIndex', 0); - - const tab: React.JSX.Element[] = []; - - tab[0] = ; - tab[1] = ; - - return ( - <> - - setTabIndex(0)}> - Law Management - - setTabIndex(1)}> - Law Sets - - - {tab[tabIndex]} - + const [searchLawName, setSearchLawName] = useSharedState( + 'searchLawName', + '', ); -}; - -const LawManagerLaws = (props) => { - const { act, data } = useBackend(); const { ion_law_nr, @@ -121,8 +106,108 @@ const LawManagerLaws = (props) => { isAdmin, channel, channels, + law_sets, } = data; + const tab: React.JSX.Element[] = []; + + tab[0] = ( + + ); + tab[1] = ( + + ); + + return ( + <> + + setTabIndex(0)}> + Law Management + + setTabIndex(1)}> + Law Sets + + + {tab[tabIndex]} + + ); +}; + +export const LawManagerLaws = (props: { + ion_law_nr: string; + ion_law: string; + zeroth_law: string; + inherent_law: string; + supplied_law: string; + supplied_law_position: number; + zeroth_laws: law[]; + ion_laws: law[]; + inherent_laws: law[]; + supplied_laws: law[]; + has_zeroth_laws: number; + has_ion_laws: number; + has_inherent_laws: number; + has_supplied_laws: number; + isAI: BooleanLike; + isMalf: BooleanLike; + isAdmin: BooleanLike; + channel: string; + channels: { channel: string }[]; + hasScroll?: boolean; + sectionHeight?: string; +}) => { + const { act } = useBackend(); + const { + ion_law_nr, + ion_law, + zeroth_law, + inherent_law, + supplied_law, + supplied_law_position, + zeroth_laws, + has_zeroth_laws, + ion_laws, + has_ion_laws, + inherent_laws, + has_inherent_laws, + supplied_laws, + has_supplied_laws, + isAI, + isMalf, + isAdmin, + channel, + channels, + hasScroll, + sectionHeight, + } = props; + let allLaws = zeroth_laws .map((law) => { law.zero = true; @@ -131,19 +216,37 @@ const LawManagerLaws = (props) => { .concat(inherent_laws); return ( -
+
{has_ion_laws ? ( - + ) : ( '' )} {has_zeroth_laws || has_inherent_laws ? ( - + ) : ( '' )} {has_supplied_laws ? ( - + ) : ( '' )} @@ -283,12 +386,12 @@ const LawsTable = (props: { title: string; noButtons?: BooleanLike; [rest: string]: any; + isMalf: BooleanLike; + isAdmin: BooleanLike; }) => { - const { act, data } = useBackend(); + const { act } = useBackend(); - const { isMalf, isAdmin } = data; - - const { laws, title, noButtons, ...rest } = props; + const { laws, title, noButtons, isMalf, isAdmin, ...rest } = props; return (
@@ -360,10 +463,24 @@ const LawsTable = (props: { ); }; -const LawManagerLawSets = (props) => { - const { act, data } = useBackend(); +export const LawManagerLawSets = (props: { + law_sets: law_pack[]; + ion_law_nr: string; + searchLawName: string; + onSearchLawName: Function; + isAdmin: BooleanLike; + isMalf: BooleanLike; +}) => { + const { act } = useBackend(); - const { isMalf, law_sets, ion_law_nr } = data; + const { + law_sets, + ion_law_nr, + searchLawName, + onSearchLawName, + isMalf, + isAdmin, + } = props; return ( <> @@ -371,8 +488,14 @@ const LawManagerLawSets = (props) => { Remember: Stating laws other than those currently loaded may be grounds for decommissioning! - NanoTrasen + onSearchLawName(value)} + /> {law_sets.length - ? law_sets.map((laws) => ( + ? prepareSearch(law_sets, searchLawName).map((laws) => (
{ noButtons laws={laws.laws.ion_laws} title={ion_law_nr + ' Laws:'} + isAdmin={isAdmin} + isMalf={isMalf} /> ) : ( '' @@ -412,6 +537,8 @@ const LawManagerLawSets = (props) => { noButtons laws={laws.laws.zeroth_laws.concat(laws.laws.inherent_laws)} title={laws.header} + isAdmin={isAdmin} + isMalf={isMalf} /> ) : ( '' @@ -421,6 +548,8 @@ const LawManagerLawSets = (props) => { noButtons laws={laws.laws.supplied_laws} title="Supplied Laws" + isAdmin={isAdmin} + isMalf={isMalf} /> ) : ( '' @@ -431,3 +560,23 @@ const LawManagerLawSets = (props) => { ); }; + +const prepareSearch = ( + laws: law_pack[], + searchText: string = '', +): law_pack[] => { + const testSearch = createSearch( + searchText, + (law: law_pack) => law.name + law.header, + ); + return flow([ + (laws: law_pack[]) => { + // Optional search term + if (!searchText) { + return laws; + } else { + return filter(laws, testSearch); + } + }, + ])(laws); +}; diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx index cd48cc8aef6..dba66ce648a 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/index.tsx @@ -1,18 +1,19 @@ import { useEffect, useState } from 'react'; import { useBackend } from 'tgui/backend'; import { - Box, Button, Divider, Dropdown, Input, LabeledList, NoticeBox, + Section, Stack, Tabs, } from 'tgui/components'; import { Window } from 'tgui/layouts'; +import { LawManagerLaws, LawManagerLawSets } from '../LawManager'; import { ModifyRobotNoModule } from './ModifyRobotNoModule'; import { ModifyRobotAccess } from './ModifyRobotTabs/ModifyRobotAccess'; import { ModifyRobotComponent } from './ModifyRobotTabs/ModifyRobotComponent'; @@ -34,10 +35,29 @@ export const ModifyRobot = (props) => { cell_options, id_icon, access_options, + ion_law_nr, + ion_law, + zeroth_law, + inherent_law, + supplied_law, + supplied_law_position, + zeroth_laws, + ion_laws, + inherent_laws, + supplied_laws, + has_zeroth_laws, + has_ion_laws, + has_inherent_laws, + has_supplied_laws, + isAI, + channel, + channels, + law_sets, } = data; const [tab, setTab] = useState(0); const [robotName, setRobotName] = useState(target ? target.name : ''); + const [searchLawName, setSearchLawName] = useState(''); useEffect(() => { if (target?.name) { @@ -67,8 +87,43 @@ export const ModifyRobot = (props) => { all_access={access_options!} /> ); - tabs[6] = ; - tabs[7] = ; + tabs[6] = ( + + ); + tabs[7] = ( +
+ +
+ ); return ( diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts index bdf75f31c68..02b840948ba 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/types.ts +++ b/tgui/packages/tgui/interfaces/ModifyRobot/types.ts @@ -9,6 +9,24 @@ export type Data = { cell_options: Record; id_icon: string; access_options: Access[] | undefined; + ion_law_nr: string; + ion_law: string; + zeroth_law: string; + inherent_law: string; + supplied_law: string; + supplied_law_position: number; + zeroth_laws: law[]; + ion_laws: law[]; + inherent_laws: law[]; + supplied_laws: law[]; + has_zeroth_laws: number; + has_ion_laws: number; + has_inherent_laws: number; + has_supplied_laws: number; + isAI: BooleanLike; + channel: string; + channels: { channel: string }[]; + law_sets: law_pack[]; }; export type DropdownEntry = { @@ -89,3 +107,27 @@ export type Cell = { }; export type Access = { id: number; name: string }; + +type law_pack = { + name: string; + header: string; + ref: string; + laws: { + zeroth_laws: law[]; + has_zeroth_laws: number; + ion_laws: law[]; + has_ion_laws: number; + inherent_laws: law[]; + has_inherent_laws: number; + supplied_laws: law[]; + has_supplied_laws: number; + }; +}; + +type law = { + law: string; + index: number; + state: number; + ref: string; + zero: boolean; // Local UI var +}; From adf5138ac2c7bbd87e4610f1e08385bf6922dba5 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 04:20:34 +0200 Subject: [PATCH 17/21] don't forget to sync --- code/modules/admin/modify_robot.dm | 2 +- tgui/packages/tgui/interfaces/LawManager.tsx | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 429f99805d4..343ded441e1 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -463,8 +463,8 @@ if(ALs) log_and_message_admins("has transfered the [ALs.name] laws to [target].") ALs.sync(target, 0) + target.lawsync() return TRUE - if("notify_laws") to_chat(target, "Law Notice") target.laws.show_laws(target) diff --git a/tgui/packages/tgui/interfaces/LawManager.tsx b/tgui/packages/tgui/interfaces/LawManager.tsx index 2b2838c7d00..305e6a81a4e 100644 --- a/tgui/packages/tgui/interfaces/LawManager.tsx +++ b/tgui/packages/tgui/interfaces/LawManager.tsx @@ -208,7 +208,7 @@ export const LawManagerLaws = (props: { sectionHeight, } = props; - let allLaws = zeroth_laws + const allLaws = zeroth_laws .map((law) => { law.zero = true; return law; @@ -383,6 +383,7 @@ export const LawManagerLaws = (props: { }; const LawsTable = (props: { + laws: law[]; title: string; noButtons?: BooleanLike; [rest: string]: any; From eebfc2ab83896700ac7017fa9c7ed1c8b0ba46d7 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 04:23:27 +0200 Subject: [PATCH 18/21] on all law edits --- code/modules/admin/modify_robot.dm | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 343ded441e1..0ebd074cf8e 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -399,43 +399,52 @@ if("add_zeroth_law") if(zeroth_law && !target.laws.zeroth_law) target.set_zeroth_law(zeroth_law) + target.lawsync() return TRUE if("add_ion_law") if(ion_law) target.add_ion_law(ion_law) + target.lawsync() return TRUE if("add_inherent_law") if(inherent_law) target.add_inherent_law(inherent_law) + target.lawsync() return TRUE if("add_supplied_law") if(supplied_law && supplied_law_position >= 1 && MIN_SUPPLIED_LAW_NUMBER <= MAX_SUPPLIED_LAW_NUMBER) target.add_supplied_law(supplied_law_position, supplied_law) + target.lawsync() return TRUE if("change_zeroth_law") var/new_law = sanitize(params["val"]) if(new_law && new_law != zeroth_law) zeroth_law = new_law + target.lawsync() return TRUE if("change_ion_law") var/new_law = sanitize(params["val"]) if(new_law && new_law != ion_law) ion_law = new_law + target.lawsync() return TRUE if("change_inherent_law") var/new_law = sanitize(params["val"]) if(new_law && new_law != inherent_law) inherent_law = new_law + target.lawsync() return TRUE if("change_supplied_law") var/new_law = sanitize(params["val"]) if(new_law && new_law != supplied_law) supplied_law = new_law + target.lawsync() return TRUE if("change_supplied_law_position") var/new_position = tgui_input_number(usr, "Enter new supplied law position between 1 and [MAX_SUPPLIED_LAW_NUMBER], inclusive. Inherent laws at the same index as a supplied law will not be stated.", "Law Position", supplied_law_position, MAX_SUPPLIED_LAW_NUMBER, 1) if(isnum(new_position)) supplied_law_position = CLAMP(new_position, 1, MAX_SUPPLIED_LAW_NUMBER) + target.lawsync() return TRUE if("edit_law") var/datum/ai_law/AL = locate(params["edit_law"]) in target.laws.all_laws() @@ -444,11 +453,13 @@ if(new_law && new_law != AL.law) log_and_message_admins("has changed a law of [target] from '[AL.law]' to '[new_law]'") AL.law = new_law + target.lawsync() return TRUE if("delete_law") var/datum/ai_law/AL = locate(params["delete_law"]) in target.laws.all_laws() if(AL) target.delete_law(AL) + target.lawsync() return TRUE if("state_laws") target.statelaws(target.laws) From 130cac32731edaed212588ba57b762bf4a4eef11 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 04:28:56 +0200 Subject: [PATCH 19/21] less spam, only notify on edit or target change --- code/modules/admin/modify_robot.dm | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index 0ebd074cf8e..f8af32228f4 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -21,6 +21,7 @@ /datum/eventkit/modify_robot/New() . = ..() + log_and_message_admins("is modifying [target]") law_list = new() init_subtypes(/datum/ai_laws, law_list) law_list = dd_sortedObjectList(law_list) @@ -144,6 +145,7 @@ return TRUE if("select_target") target = locate(params["new_target"]) + log_and_message_admins("changed modifictation target to [target]") return TRUE if("toggle_crisis") target.crisis_override = !target.crisis_override @@ -451,7 +453,6 @@ if(AL) var/new_law = sanitize(tgui_input_text(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", AL.law)) if(new_law && new_law != AL.law) - log_and_message_admins("has changed a law of [target] from '[AL.law]' to '[new_law]'") AL.law = new_law target.lawsync() return TRUE @@ -472,7 +473,6 @@ if("transfer_laws") var/datum/ai_laws/ALs = locate(params["transfer_laws"]) in law_list if(ALs) - log_and_message_admins("has transfered the [ALs.name] laws to [target].") ALs.sync(target, 0) target.lawsync() return TRUE @@ -638,5 +638,4 @@ package_laws(packaged_laws, "inherent_laws", ALs.inherent_laws) package_laws(packaged_laws, "supplied_laws", ALs.supplied_laws) law_sets[++law_sets.len] = list("name" = ALs.name, "header" = ALs.law_header, "ref" = "\ref[ALs]","laws" = packaged_laws) - return law_sets From 7e5d52fdf915453b13ef57f0bae188a171a4b91c Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 04:30:13 +0200 Subject: [PATCH 20/21] wording --- code/modules/admin/modify_robot.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/admin/modify_robot.dm b/code/modules/admin/modify_robot.dm index f8af32228f4..3c1682f40ee 100644 --- a/code/modules/admin/modify_robot.dm +++ b/code/modules/admin/modify_robot.dm @@ -21,7 +21,7 @@ /datum/eventkit/modify_robot/New() . = ..() - log_and_message_admins("is modifying [target]") + log_and_message_admins("has used modify robot and is modifying [target]") law_list = new() init_subtypes(/datum/ai_laws, law_list) law_list = dd_sortedObjectList(law_list) @@ -145,7 +145,7 @@ return TRUE if("select_target") target = locate(params["new_target"]) - log_and_message_admins("changed modifictation target to [target]") + log_and_message_admins("changed robot modifictation target to [target]") return TRUE if("toggle_crisis") target.crisis_override = !target.crisis_override From 3943c059db55e82c9b2490a6732e8a47e9f38764 Mon Sep 17 00:00:00 2001 From: Kashargul <144968721+Kashargul@users.noreply.github.com> Date: Sat, 21 Sep 2024 13:27:56 +0200 Subject: [PATCH 21/21] . --- .../ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx index fd644c429c1..4450c6009cd 100644 --- a/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx +++ b/tgui/packages/tgui/interfaces/ModifyRobot/ModifyRobotTabs/ModifyRobotComponent.tsx @@ -63,7 +63,7 @@ export const ModifyRobotComponent = (props: { /> -
+
Current cell:{' '} {cell ? ( capitalize(cell)