From 41785501981f397e9ec2ae8f22f0fdad657dba41 Mon Sep 17 00:00:00 2001 From: Kashargul Date: Sat, 21 Sep 2024 03:46:20 +0200 Subject: [PATCH] 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 c02457152f..429f99805d 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 3632166b60..2b2838c7d0 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 cd48cc8aef..dba66ce648 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 bdf75f31c6..02b840948b 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 +};