[MIRROR] Adds the "Law panel", a control center for admins interacting with silicon laws [MDB IGNORE] (#19655)

* Adds the "Law panel", a control center for admins interacting with silicon laws

* Update admin_verbs.dm

---------

Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Co-authored-by: Gandalf <9026500+Gandalf2k15@users.noreply.github.com>
This commit is contained in:
SkyratBot
2023-03-10 07:10:46 +01:00
committed by GitHub
parent 5b003cd594
commit fa7538b5dc
15 changed files with 841 additions and 112 deletions
+1 -1
View File
@@ -95,7 +95,7 @@ GLOBAL_PROTECT(admin_verbs_admin)
/client/proc/toggle_AI_interact, /*toggle admin ability to interact with machines as an AI*/
/client/proc/toggle_combo_hud, /* toggle display of the combination pizza antag and taco sci/med/eng hud */
/client/proc/toggle_view_range, /*changes how far we can see*/
/client/proc/cmd_admin_law_panel,
/datum/admins/proc/toggleaooc, /*Toggle Antag OOC - SKYRAT EDIT ADDITION*/
/datum/admins/proc/toggledchat, /*SKYRAT EDIT ADDITION*/
/datum/admins/proc/togglesooc, /*Toggle Security OOC - SKYRAT EDIT ADDITION*/
+311
View File
@@ -0,0 +1,311 @@
/client/proc/cmd_admin_law_panel()
set category = "Admin.Events"
set name = "Law Panel"
if(!check_rights(R_ADMIN))
return
SSblackbox.record_feedback("tally", "admin_verb", 1, "Law Panel") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
var/datum/law_panel/tgui = new()
tgui.ui_interact(usr)
/datum/law_panel
/datum/law_panel/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Lawpanel")
ui.open()
/datum/law_panel/ui_state(mob/user)
return GLOB.admin_state
/datum/law_panel/ui_close(mob/user)
qdel(src)
/datum/law_panel/proc/add_law_helper(mob/living/user, mob/living/silicon/borgo)
var/list/lawtypes = list(LAW_ZEROTH, LAW_HACKED, LAW_ION, LAW_INHERENT, LAW_SUPPLIED) // in order of priority
var/lawtype = tgui_input_list(user, "Select law type", "Law type", lawtypes)
if(isnull(lawtype))
return FALSE
var/lawtext = tgui_input_text(user, "Input law text", "Law text")
if(!lawtext)
return FALSE
if(QDELETED(src) || QDELETED(borgo))
return
switch(lawtype)
if(LAW_ZEROTH)
if(borgo.laws.zeroth || borgo.laws.zeroth_borg)
var/zero_override_alert = tgui_alert(user, "This silicon already has a zeroth law, \
this will override their existing one. Are you sure?", "Zeroth law override", list("Yes", "No"))
if(zero_override_alert != "Yes" || QDELETED(src) || QDELETED(borgo))
return FALSE
borgo.laws.set_zeroth_law(lawtext)
borgo.laws.protected_zeroth = TRUE
if(LAW_ION)
borgo.laws.add_ion_law(lawtext)
if(LAW_HACKED)
borgo.laws.add_hacked_law(lawtext)
if(LAW_INHERENT)
borgo.laws.add_inherent_law(lawtext)
if(LAW_SUPPLIED)
borgo.laws.add_supplied_law(length(borgo.laws.supplied), lawtext) // Just goes to the end of the list
return TRUE
/datum/law_panel/proc/move_law_helper(mob/living/user, mob/living/silicon/borgo, direction, law)
var/list/relevant_laws = borgo.laws.inherent
var/lawindex = relevant_laws.Find(law)
if(!lawindex)
to_chat(user, span_danger("Something went wrong, we couldn't move that law."))
return FALSE
switch(direction)
if("up")
if(lawindex == length(relevant_laws)) // Already at the top? Sanity
to_chat(user, span_danger("Something went wrong, we couldn't move that law."))
return FALSE
relevant_laws.Swap(lawindex + 1, lawindex)
if("down")
if(lawindex == 1) // Already at the bottom? Sanity
to_chat(user, span_danger("Something went wrong, we couldn't move that law."))
return FALSE
relevant_laws.Swap(lawindex - 1, lawindex)
else
CRASH("Invalid direction ([direction]) passed to move_law_helper.")
return TRUE
/datum/law_panel/proc/edit_law_text_helper(mob/living/user, mob/living/silicon/borgo, lawtype, oldlaw)
var/newlaw = tgui_input_text(user, "Edit this law's text.", "Edit law", oldlaw)
if(!newlaw || QDELETED(src) || QDELETED(borgo))
return FALSE
var/list/relevant_laws
switch(lawtype)
if(LAW_INHERENT)
relevant_laws = borgo.laws.inherent
if(LAW_SUPPLIED)
relevant_laws = borgo.laws.supplied
if(LAW_HACKED)
relevant_laws = borgo.laws.hacked
if(LAW_ION)
relevant_laws = borgo.laws.ion
if(LAW_ZEROTH)
borgo.set_zeroth_law(newlaw, announce = FALSE)
borgo.laws.protected_zeroth = TRUE
return TRUE
else
return FALSE
var/lawindex = relevant_laws.Find(oldlaw)
if(!lawindex)
to_chat(user, span_danger("Something went wrong, we couldn't edit that law."))
return FALSE
relevant_laws[lawindex] = newlaw
return TRUE
/datum/law_panel/proc/edit_law_priority_helper(mob/living/user, mob/living/silicon/borgo, law)
var/old_prio = borgo.laws.supplied.Find(law)
if(!old_prio)
to_chat(user, span_danger("Something went wrong, we couldn't edit that law."))
return FALSE
var/new_prio = tgui_input_number(user, "Enter a new priority.", "Edit priority", old_prio, 50, 0)
if(!new_prio || QDELETED(src) || QDELETED(borgo))
return FALSE
// Sanity
if(old_prio != borgo.laws.supplied.Find(law))
to_chat(user, span_danger("[borgo]'s laws may have changed since you have edited priority, please re-try."))
return FALSE
// If it's far beyond any existing values, just re-add it normally
if(new_prio > length(borgo.laws.supplied))
borgo.laws.remove_supplied_law_by_num(old_prio)
borgo.laws.add_supplied_law(new_prio, law)
return TRUE
// Handle collisions
var/existing_law = borgo.laws.supplied[new_prio]
if(existing_law)
var/list/options = list("Swap", "Move up", "Move down", "Replace", "Cancel")
if(new_prio == 1)
// Nowhere to go from here
options -= "Move down"
var/swap_or_remove = tgui_alert(user, "There's already a law at that priority level. What should be done to it?", "Existing law", options)
if(swap_or_remove == "Cancel" || !swap_or_remove || QDELETED(src) || QDELETED(borgo))
return FALSE
// Sanity
if(law != borgo.laws.supplied[old_prio] || existing_law != borgo.laws.supplied[new_prio])
to_chat(user, span_danger("[borgo]'s laws have changed since you have edited priority, please re-try."))
return FALSE
if(swap_or_remove == "Swap")
borgo.laws.supplied.Swap(old_prio, new_prio)
return TRUE
if(swap_or_remove == "Replace")
borgo.laws.remove_supplied_law_by_num(new_prio, law)
borgo.laws.add_supplied_law(new_prio, law)
return TRUE
var/new_prio_for_old_law = new_prio + (swap_or_remove == "Move up" ? 1 : -1)
borgo.laws.remove_supplied_law_by_num(old_prio)
borgo.laws.remove_supplied_law_by_num(new_prio)
borgo.laws.add_supplied_law(new_prio, law)
borgo.laws.add_supplied_law(new_prio_for_old_law, existing_law)
return TRUE
// Sanity
if(old_prio != borgo.laws.supplied.Find(law))
to_chat(user, span_danger("[borgo]'s may laws have changed since you have edited priority, please re-try."))
return FALSE
// At this point the slot is free, insert it as normal
borgo.laws.remove_supplied_law_by_num(old_prio)
borgo.laws.add_supplied_law(new_prio, law)
return TRUE
/datum/law_panel/proc/remove_law_helper(mob/living/user, mob/living/silicon/borgo, lawtype, law)
switch(lawtype)
if(LAW_INHERENT)
borgo.laws.remove_inherent_law(law)
if(LAW_SUPPLIED)
borgo.laws.remove_supplied_law_by_law(law)
if(LAW_HACKED)
borgo.laws.remove_hacked_law(law)
if(LAW_ION)
borgo.laws.remove_ion_law(law)
if(LAW_ZEROTH)
borgo.laws.clear_zeroth_law(force = TRUE)
borgo.laws.protected_zeroth = FALSE
else
return FALSE
return TRUE
/datum/law_panel/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
if(!check_rights(R_ADMIN))
qdel(src)
return FALSE
var/mob/living/silicon/borgo
if(params["ref"])
borgo = locate(params["ref"]) in GLOB.silicon_mobs
if(QDELETED(borgo))
to_chat(usr, span_danger("That cyborg is invalid."))
return TRUE
switch(action)
if("lawchange_logs")
usr.client?.list_law_changes()
return FALSE
if("force_state_laws")
borgo.statelaws()
return FALSE
if("announce_law_changes")
borgo.show_laws()
return FALSE
if("laws_updated_alert")
borgo.post_lawchange()
return FALSE
if("give_law_datum")
borgo.make_laws()
return TRUE
if("add_law")
. = add_law_helper(usr, borgo)
if("remove_law")
. = remove_law_helper(usr, borgo, params["lawtype"], params["law"])
if("move_law")
. = move_law_helper(usr, borgo, params["direction"], params["law"])
if("edit_law_text")
. = edit_law_text_helper(usr, borgo, params["lawtype"], params["law"])
if("edit_law_prio")
. = edit_law_priority_helper(usr, borgo, params["law"])
if(. && !QDELETED(borgo))
// One of our functions successfully changed a law
// If it was an AI with connected borgs, we should sync
borgo.try_sync_laws()
/datum/law_panel/ui_data(mob/user)
// Iterating over all silicons in existence every UI update is not exactly ideal,
// but considering this is an admin only UI, I'm considering it okay purely for better UX.
// If someone's copying this for player user or this becomes too laggy,
// change this to static data and just add a refresh button.
// You'll have to update static data every time the user changes a law though.
var/list/data = list()
var/list/all_silicons = list()
for(var/mob/living/silicon/borgo as anything in GLOB.silicon_mobs)
var/list/borg_information = list()
if(iscyborg(borgo))
var/mob/living/silicon/robot/cyborg = borgo
if(cyborg.shell)
continue
borg_information["master_ai"] = cyborg.connected_ai?.real_name
borg_information["borg_synced"] = cyborg.lawupdate
borg_information["borg_type"] = "Cyborg"
else if(isAI(borgo))
borg_information["borg_type"] = "AI"
else if(ispAI(borgo))
borg_information["borg_type"] = "PAI"
else
borg_information["borg_type"] = "Unknown"
borg_information["borg_name"] = borgo.real_name
borg_information["ref"] = REF(borgo)
var/datum/ai_laws/lawset = borgo.laws
if(!isnull(lawset))
var/list/borg_laws = list()
// zeroth law on top
if(lawset.zeroth || lawset.zeroth_borg)
UNTYPED_LIST_ADD(borg_laws, list("lawtype" = LAW_ZEROTH, "law" = lawset.zeroth || lawset.zeroth_borg, "num" = 0))
// then goes ion / hacked
for(var/law in lawset.hacked)
UNTYPED_LIST_ADD(borg_laws, list("lawtype" = LAW_HACKED, "law" = law, "num" = -1))
for(var/law in lawset.ion)
UNTYPED_LIST_ADD(borg_laws, list("lawtype" = LAW_ION, "law" = law, "num" = -1))
// normie laws
var/lawnum = 1
for(var/law in lawset.inherent)
UNTYPED_LIST_ADD(borg_laws, list("lawtype" = LAW_INHERENT, "law" = law, "num" = lawnum))
lawnum += 1
for(var/law in lawset.supplied)
if(law) // Supplied is full of a bunch of empties
UNTYPED_LIST_ADD(borg_laws, list("lawtype" = LAW_SUPPLIED, "law" = law, "num" = lawnum))
lawnum += 1
borg_information["laws"] = borg_laws
UNTYPED_LIST_ADD(all_silicons, borg_information)
data["all_silicons"] = all_silicons
return data