mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-26 14:39:58 +01:00
[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:
co-authored by
MrMelbert
Gandalf
parent
5b003cd594
commit
fa7538b5dc
@@ -736,7 +736,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
desc = "Laws have potentially been uploaded to or removed from this unit. Please be aware of any changes \
|
||||
so as to remain in compliance with the most up-to-date laws."
|
||||
icon_state = ALERT_NEW_LAW
|
||||
timeout = 300
|
||||
timeout = 30 SECONDS
|
||||
|
||||
/atom/movable/screen/alert/hackingapc
|
||||
name = "Hacking APC"
|
||||
@@ -744,7 +744,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
|
||||
complete, you will have exclusive control of it, and you will gain \
|
||||
additional processing time to unlock more malfunction abilities."
|
||||
icon_state = ALERT_HACKING_APC
|
||||
timeout = 600
|
||||
timeout = 60 SECONDS
|
||||
var/atom/target = null
|
||||
|
||||
/atom/movable/screen/alert/hackingapc/Click()
|
||||
|
||||
+154
-60
@@ -101,16 +101,41 @@
|
||||
return null
|
||||
|
||||
/datum/ai_laws
|
||||
/// The name of the lawset
|
||||
var/name = "Unknown Laws"
|
||||
var/zeroth = null
|
||||
var/zeroth_borg = null
|
||||
var/list/inherent = list()
|
||||
var/list/supplied = list()
|
||||
var/list/ion = list()
|
||||
var/list/hacked = list()
|
||||
/// The silicon linked to this lawset
|
||||
var/mob/living/silicon/owner
|
||||
/// The ID of this lawset, pretty much only used to tell if we're default or not
|
||||
var/id = DEFAULT_AI_LAWID
|
||||
|
||||
/// If TRUE, the zeroth law of this AI is protected and cannot be removed by players under normal circumstances.
|
||||
var/protected_zeroth = FALSE
|
||||
|
||||
/// Zeroth law
|
||||
/// A lawset can only have 1 zeroth law, it's the top dog.
|
||||
/// Nothing removes it unless it's admin forced
|
||||
var/zeroth = null
|
||||
/// Zeroth borg law
|
||||
/// It's just a zeroth law but specially themed for cyborgs
|
||||
/// ("follow your master" vs "accomplish your objectives")
|
||||
var/zeroth_borg = null
|
||||
/// Core laws
|
||||
/// Inherent laws are the "core" laws of the AI
|
||||
/// Reseting the AI will not remove these, these are intrinsit to whatever lawset they are running.
|
||||
var/list/inherent = list()
|
||||
/// Supplied laws
|
||||
/// Supplied laws are supplied in addition to the inherent laws - after the fact
|
||||
/// These laws will go away when an AI is reset
|
||||
var/list/supplied = list()
|
||||
/// Ion laws
|
||||
/// Special randomized (usually) laws which are above all over laws
|
||||
/// These laws will go away when an AI is reset
|
||||
var/list/ion = list()
|
||||
/// Hacked laws
|
||||
/// Syndicate uploaded laws which are above all other laws
|
||||
/// These laws will go away when an AI is reset
|
||||
var/list/hacked = list()
|
||||
|
||||
/datum/ai_laws/Destroy(force = FALSE, ...)
|
||||
if(!QDELETED(owner)) //Stopgap to help with laws randomly being lost. This stack_trace will hopefully help find the real issues.
|
||||
if(force) //Unless we're forced...
|
||||
@@ -153,7 +178,14 @@
|
||||
default_laws = new default_laws()
|
||||
inherent = default_laws.inherent
|
||||
|
||||
/datum/ai_laws/proc/get_law_amount(groups)
|
||||
/**
|
||||
* Gets the number of how many laws this AI has
|
||||
*
|
||||
* * groups - What groups to count laws from? By default counts all groups
|
||||
*
|
||||
* Returns a number, the number of laws we have
|
||||
*/
|
||||
/datum/ai_laws/proc/get_law_amount(list/groups = list(LAW_ZEROTH, LAW_ION, LAW_HACKED, LAW_INHERENT, LAW_SUPPLIED))
|
||||
var/law_amount = 0
|
||||
if(zeroth && (LAW_ZEROTH in groups))
|
||||
law_amount++
|
||||
@@ -170,37 +202,141 @@
|
||||
law_amount++
|
||||
return law_amount
|
||||
|
||||
/datum/ai_laws/proc/set_zeroth_law(law, law_borg = null)
|
||||
/**
|
||||
* Sets this lawset's zeroth law to the passed law
|
||||
*
|
||||
* Also can set the zeroth borg law, if this lawset is for master AIs.
|
||||
* The zeroth borg law allows for AIs with zeroth laws to give a differing zeroth law to their child cyborgs
|
||||
*/
|
||||
/datum/ai_laws/proc/set_zeroth_law(law, law_borg)
|
||||
zeroth = law
|
||||
if(law_borg) //Making it possible for slaved borgs to see a different law 0 than their AI. --NEO
|
||||
zeroth_borg = law_borg
|
||||
|
||||
/datum/ai_laws/proc/add_inherent_law(law)
|
||||
if (!(law in inherent))
|
||||
inherent += law
|
||||
/**
|
||||
* Unsets the zeroth (and zeroth borg) law from this lawset
|
||||
*
|
||||
* This will NOT unset a malfunctioning AI's zero law if force is not true
|
||||
*
|
||||
* Returns TRUE on success, or false otherwise
|
||||
*/
|
||||
/datum/ai_laws/proc/clear_zeroth_law(force = FALSE)
|
||||
if(force)
|
||||
zeroth = null
|
||||
zeroth_borg = null
|
||||
return TRUE
|
||||
|
||||
// Protected zeroeth laws (malf, admin) shouldn't be wiped
|
||||
if(protected_zeroth)
|
||||
return FALSE
|
||||
|
||||
// If the owner is an antag (has a special role) they also shouldn't be wiped
|
||||
if(owner?.mind?.special_role)
|
||||
return FALSE
|
||||
if (isAI(owner))
|
||||
var/mob/living/silicon/ai/ai_owner = owner
|
||||
if(ai_owner.deployed_shell?.mind?.special_role)
|
||||
return FALSE
|
||||
|
||||
zeroth = null
|
||||
zeroth_borg = null
|
||||
return TRUE
|
||||
|
||||
/// Adds the passed law as an inherent law.
|
||||
/// Simply adds it to the bottom of the inherent law list.
|
||||
/// No duplicate laws allowed.
|
||||
/datum/ai_laws/proc/add_inherent_law(law)
|
||||
inherent |= law
|
||||
|
||||
/// Removes the passed law from the inherent law list.
|
||||
/datum/ai_laws/proc/remove_inherent_law(law)
|
||||
inherent -= law
|
||||
|
||||
/// Clears all inherent laws from this lawset.
|
||||
/datum/ai_laws/proc/clear_inherent_laws()
|
||||
inherent.Cut()
|
||||
|
||||
/// Adds the passed law as an ion law.
|
||||
/datum/ai_laws/proc/add_ion_law(law)
|
||||
ion += law
|
||||
|
||||
/// Removes the passed law from the ion law list.
|
||||
/datum/ai_laws/proc/remove_ion_law(law)
|
||||
ion -= law
|
||||
|
||||
/// Clears all ion laws.
|
||||
/datum/ai_laws/proc/clear_ion_laws()
|
||||
ion.Cut()
|
||||
|
||||
/// Adds the passed law as an hacked law.
|
||||
/datum/ai_laws/proc/add_hacked_law(law)
|
||||
hacked += law
|
||||
|
||||
/datum/ai_laws/proc/clear_inherent_laws()
|
||||
qdel(inherent)
|
||||
inherent = list()
|
||||
/// Removes the passed law from the hacked law list.
|
||||
/datum/ai_laws/proc/remove_hacked_law(law)
|
||||
hacked -= law
|
||||
|
||||
/// Clears all hacked laws.
|
||||
/datum/ai_laws/proc/clear_hacked_laws()
|
||||
hacked.Cut()
|
||||
|
||||
/// Adds the passed law as a supplied law at the passed priority level.
|
||||
/// Will override any existing supplied laws at that priority level.
|
||||
/datum/ai_laws/proc/add_supplied_law(number, law)
|
||||
while (supplied.len < number + 1)
|
||||
supplied += ""
|
||||
|
||||
supplied[number + 1] = law
|
||||
|
||||
/// Removes the supplied law at the passed number.
|
||||
/datum/ai_laws/proc/remove_supplied_law_by_num(number)
|
||||
supplied[number] = ""
|
||||
|
||||
/// Removes the supplied law by law text, replacing it with a blank.
|
||||
/datum/ai_laws/proc/remove_supplied_law_by_law(law)
|
||||
var/lawindex = supplied.Find(law)
|
||||
if(!lawindex)
|
||||
return
|
||||
|
||||
supplied[lawindex] = ""
|
||||
|
||||
/// Clears all supplied laws.
|
||||
/datum/ai_laws/proc/clear_supplied_laws()
|
||||
supplied.Cut()
|
||||
|
||||
/**
|
||||
* Removes the law at the passed index of both inherent and supplied laws combined.
|
||||
*
|
||||
* For example, if a lawset has 3 inherent and 3 supplied laws...
|
||||
* Calling this with number = 2 will remove the second inherent law while
|
||||
* calling this with number = 4 will remove the first supplied law
|
||||
*
|
||||
* Returns the law text of what law that was removed.
|
||||
*/
|
||||
/datum/ai_laws/proc/remove_law(number)
|
||||
if(number <= 0)
|
||||
return
|
||||
if(inherent.len && number <= inherent.len)
|
||||
. = inherent[number]
|
||||
inherent -= .
|
||||
return
|
||||
var/list/supplied_laws = list()
|
||||
for(var/index in 1 to supplied.len)
|
||||
var/law = supplied[index]
|
||||
if(length(law) > 0)
|
||||
supplied_laws += index //storing the law number instead of the law
|
||||
if(supplied_laws.len && number <= (inherent.len+supplied_laws.len))
|
||||
var/law_to_remove = supplied_laws[number-inherent.len]
|
||||
. = supplied[law_to_remove]
|
||||
supplied -= .
|
||||
return
|
||||
|
||||
/**
|
||||
* Removes a random law and replaces it with the new one
|
||||
*
|
||||
* Args:
|
||||
* law - The law that is being uploaded
|
||||
* remove_law_groups - A list of law categories that can be deleted from
|
||||
* remove_law_groups - A list of law categories that can be deleted from
|
||||
* insert_law_group - The law category that the law will be inserted into
|
||||
**/
|
||||
/datum/ai_laws/proc/replace_random_law(law, remove_law_groups, insert_law_group)
|
||||
@@ -254,6 +390,7 @@
|
||||
supplied.Insert(i, law)
|
||||
|
||||
/datum/ai_laws/proc/shuffle_laws(list/groups)
|
||||
RETURN_TYPE(/list)
|
||||
var/list/laws = list()
|
||||
if(ion.len && (LAW_ION in groups))
|
||||
laws += ion
|
||||
@@ -284,52 +421,9 @@
|
||||
break
|
||||
i++
|
||||
|
||||
/datum/ai_laws/proc/remove_law(number)
|
||||
if(number <= 0)
|
||||
return
|
||||
if(inherent.len && number <= inherent.len)
|
||||
. = inherent[number]
|
||||
inherent -= .
|
||||
return
|
||||
var/list/supplied_laws = list()
|
||||
for(var/index in 1 to supplied.len)
|
||||
var/law = supplied[index]
|
||||
if(length(law) > 0)
|
||||
supplied_laws += index //storing the law number instead of the law
|
||||
if(supplied_laws.len && number <= (inherent.len+supplied_laws.len))
|
||||
var/law_to_remove = supplied_laws[number-inherent.len]
|
||||
. = supplied[law_to_remove]
|
||||
supplied -= .
|
||||
return
|
||||
|
||||
/datum/ai_laws/proc/clear_supplied_laws()
|
||||
supplied = list()
|
||||
|
||||
/datum/ai_laws/proc/clear_ion_laws()
|
||||
ion = list()
|
||||
|
||||
/datum/ai_laws/proc/clear_hacked_laws()
|
||||
hacked = list()
|
||||
|
||||
/datum/ai_laws/proc/show_laws(who)
|
||||
/datum/ai_laws/proc/show_laws(mob/to_who)
|
||||
var/list/printable_laws = get_law_list(include_zeroth = TRUE)
|
||||
for(var/law in printable_laws)
|
||||
to_chat(who,law)
|
||||
|
||||
/datum/ai_laws/proc/clear_zeroth_law(force) //only removes zeroth from antag ai if force is 1
|
||||
if(force)
|
||||
zeroth = null
|
||||
zeroth_borg = null
|
||||
return TRUE
|
||||
if(owner?.mind?.special_role)
|
||||
return FALSE
|
||||
if (isAI(owner))
|
||||
var/mob/living/silicon/ai/A=owner
|
||||
if(A?.deployed_shell?.mind?.special_role)
|
||||
return FALSE
|
||||
zeroth = null
|
||||
zeroth_borg = null
|
||||
return TRUE
|
||||
to_chat(to_who, examine_block(jointext(printable_laws, "\n")))
|
||||
|
||||
/datum/ai_laws/proc/associate(mob/living/silicon/M)
|
||||
if(!owner)
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
..()
|
||||
|
||||
/obj/item/ai_module/remove/install(datum/ai_laws/law_datum, mob/user)
|
||||
if(lawpos > (law_datum.get_law_amount(list(LAW_INHERENT = 1, LAW_SUPPLIED = 1))))
|
||||
if(lawpos > law_datum.get_law_amount(list(LAW_INHERENT, LAW_SUPPLIED)))
|
||||
to_chat(user, span_warning("There is no law [lawpos] to delete!"))
|
||||
return
|
||||
..()
|
||||
@@ -62,4 +62,3 @@
|
||||
else
|
||||
law_datum.clear_inherent_laws()
|
||||
law_datum.clear_zeroth_law(0)
|
||||
|
||||
|
||||
@@ -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*/
|
||||
|
||||
@@ -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
|
||||
@@ -165,6 +165,7 @@
|
||||
var/law_borg = "Accomplish your AI's objectives at all costs."
|
||||
|
||||
malf_ai.set_zeroth_law(law, law_borg)
|
||||
malf_ai.laws.protected_zeroth = TRUE
|
||||
malf_ai.set_syndie_radio()
|
||||
|
||||
to_chat(malf_ai, "Your radio has been upgraded! Use :t to speak on an encrypted channel with Syndicate Agents!")
|
||||
|
||||
@@ -142,14 +142,14 @@
|
||||
else if(target_ai.key)
|
||||
key = target_ai.key
|
||||
|
||||
to_chat(src, "<B>You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras).</B>")
|
||||
to_chat(src, "<B>To look at other parts of the station, click on yourself to get a camera menu.</B>")
|
||||
to_chat(src, "<B>While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc.</B>")
|
||||
to_chat(src, span_bold("You are playing the station's AI. The AI cannot move, but can interact with many objects while viewing them (through cameras)."))
|
||||
to_chat(src, span_bold("To look at other parts of the station, click on yourself to get a camera menu."))
|
||||
to_chat(src, span_bold("While observing through a camera, you can use most (networked) devices which you can see, such as computers, APCs, intercoms, doors, etc."))
|
||||
to_chat(src, "To use something, simply click on it.")
|
||||
to_chat(src, "For department channels, use the following say commands:")
|
||||
to_chat(src, ":o - AI Private, :c - Command, :s - Security, :e - Engineering, :u - Supply, :v - Service, :m - Medical, :n - Science, :h - Holopad.")
|
||||
show_laws()
|
||||
to_chat(src, "<b>These laws may be changed by other players, or by you being the traitor.</b>")
|
||||
to_chat(src, span_bold("These laws may be changed by other players, random events, or by you becoming malfunctioning."))
|
||||
|
||||
job = "AI"
|
||||
|
||||
|
||||
@@ -2,25 +2,18 @@
|
||||
/mob/living/silicon/ai/proc/show_laws_verb()
|
||||
set category = "AI Commands"
|
||||
set name = "Show Laws"
|
||||
set desc = "Check what your laws are privately. \
|
||||
Also ensures all synced cyborgs are up to date with your laws, reminds them of your laws."
|
||||
if(usr.stat == DEAD)
|
||||
return //won't work if dead
|
||||
src.show_laws()
|
||||
|
||||
/mob/living/silicon/ai/show_laws(everyone = 0)
|
||||
var/who
|
||||
|
||||
if (everyone)
|
||||
who = world
|
||||
else
|
||||
who = src
|
||||
to_chat(who, "<b>Obey these laws:</b>")
|
||||
|
||||
src.laws_sanity_check()
|
||||
src.laws.show_laws(who)
|
||||
if(!everyone)
|
||||
for(var/mob/living/silicon/robot/R in connected_robots)
|
||||
if(R.lawupdate)
|
||||
R.lawsync()
|
||||
R.show_laws()
|
||||
R.law_change_counter++
|
||||
/mob/living/silicon/ai/show_laws()
|
||||
. = ..()
|
||||
try_sync_laws() // Yes we lawsync borgs EVERY TIME WE CHECK LAWS
|
||||
|
||||
/mob/living/silicon/ai/try_sync_laws()
|
||||
for(var/mob/living/silicon/robot/borgo in connected_robots)
|
||||
if(borgo.try_sync_laws())
|
||||
to_chat(borgo, span_bold("Your AI has reminded you of your laws:"))
|
||||
borgo.show_laws()
|
||||
|
||||
@@ -1,4 +1,10 @@
|
||||
/mob/living/silicon/proc/show_laws() //Redefined in ai/laws.dm and robot/laws.dm
|
||||
/mob/living/silicon/proc/show_laws()
|
||||
laws_sanity_check()
|
||||
var/list/law_box = list(span_bold("Obey these laws:"))
|
||||
law_box += laws.get_law_list(include_zeroth = TRUE)
|
||||
to_chat(src, examine_block(jointext(law_box, "\n")))
|
||||
|
||||
/mob/living/silicon/proc/try_sync_laws()
|
||||
return
|
||||
|
||||
/mob/living/silicon/proc/laws_sanity_check()
|
||||
|
||||
@@ -1,39 +1,40 @@
|
||||
/mob/living/silicon/robot/deadchat_lawchange()
|
||||
if(lawupdate)
|
||||
return
|
||||
..()
|
||||
|
||||
/mob/living/silicon/robot/show_laws(everyone = FALSE)
|
||||
laws_sanity_check()
|
||||
var/who
|
||||
return ..()
|
||||
|
||||
if (everyone)
|
||||
who = world
|
||||
else
|
||||
who = src
|
||||
/mob/living/silicon/robot/show_laws()
|
||||
if(lawupdate)
|
||||
if (connected_ai)
|
||||
if(connected_ai.stat || connected_ai.control_disabled)
|
||||
to_chat(src, "<b>AI signal lost, unable to sync laws.</b>")
|
||||
if (!QDELETED(connected_ai))
|
||||
if(connected_ai.stat != CONSCIOUS || connected_ai.control_disabled)
|
||||
to_chat(src, span_bold("AI signal lost, unable to sync laws."))
|
||||
|
||||
else
|
||||
lawsync()
|
||||
to_chat(src, "<b>Laws synced with AI, be sure to note any changes.</b>")
|
||||
to_chat(src, span_bold("Laws synced with AI, be sure to note any changes."))
|
||||
else
|
||||
to_chat(src, "<b>No AI selected to sync laws with, disabling lawsync protocol.</b>")
|
||||
to_chat(src, span_bold("No AI selected to sync laws with, disabling lawsync protocol."))
|
||||
lawupdate = FALSE
|
||||
|
||||
to_chat(who, "<b>Obey these laws:</b>")
|
||||
laws.show_laws(who)
|
||||
if (shell) //AI shell
|
||||
to_chat(who, "<b>Remember, you are an AI remotely controlling your shell, other AIs can be ignored.</b>")
|
||||
else if (connected_ai)
|
||||
to_chat(who, "<b>Remember, [connected_ai.name] is your master, other AIs can be ignored.</b>")
|
||||
else if (emagged)
|
||||
to_chat(who, "<b>Remember, you are not required to listen to the AI.</b>")
|
||||
else
|
||||
to_chat(who, "<b>Remember, you are not bound to any AI, you are not required to listen to them.</b>")
|
||||
. = ..()
|
||||
|
||||
if (shell) //AI shell
|
||||
to_chat(src, span_bold("Remember, you are an AI remotely controlling your shell, other AIs can be ignored."))
|
||||
else if (connected_ai)
|
||||
to_chat(src, span_bold("Remember, [connected_ai.name] is your master, other AIs can be ignored."))
|
||||
else if (emagged)
|
||||
to_chat(src, span_bold("Remember, you are not required to listen to the AI."))
|
||||
else
|
||||
to_chat(src, span_bold("Remember, you are not bound to any AI, you are not required to listen to them."))
|
||||
|
||||
/mob/living/silicon/robot/try_sync_laws()
|
||||
if(QDELETED(connected_ai) || !lawupdate)
|
||||
return FALSE
|
||||
|
||||
lawsync()
|
||||
law_change_counter++
|
||||
return TRUE
|
||||
|
||||
/mob/living/silicon/robot/proc/lawsync()
|
||||
laws_sanity_check()
|
||||
|
||||
@@ -92,7 +92,8 @@
|
||||
var/emag_cooldown = 0
|
||||
var/wiresexposed = FALSE
|
||||
|
||||
var/lawupdate = TRUE //Cyborgs will sync their laws with their AI by default
|
||||
///Cyborgs will sync their laws with their AI by default
|
||||
var/lawupdate = TRUE
|
||||
///Used to determine if a borg shows up on the robotics console. Setting to TRUE hides them.
|
||||
var/scrambledcodes = FALSE
|
||||
///Boolean of whether the borg is locked down or not
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 126 KiB After Width: | Height: | Size: 127 KiB |
@@ -2387,6 +2387,7 @@
|
||||
#include "code\modules\admin\verbs\hiddenprints.dm"
|
||||
#include "code\modules\admin\verbs\highlander_datum.dm"
|
||||
#include "code\modules\admin\verbs\individual_logging.dm"
|
||||
#include "code\modules\admin\verbs\lawpanel.dm"
|
||||
#include "code\modules\admin\verbs\list_exposer.dm"
|
||||
#include "code\modules\admin\verbs\machine_upgrade.dm"
|
||||
#include "code\modules\admin\verbs\manipulate_organs.dm"
|
||||
|
||||
@@ -13,7 +13,7 @@ export const BorgPanel = (props, context) => {
|
||||
const ais = data.ais || [];
|
||||
const laws = data.laws || [];
|
||||
return (
|
||||
<Window title="Borg Panel" width={700} height={700}>
|
||||
<Window title="Borg Panel" theme="admin" width={700} height={700}>
|
||||
<Window.Content scrollable>
|
||||
<Section
|
||||
title={borg.name}
|
||||
|
||||
@@ -0,0 +1,322 @@
|
||||
import { BooleanLike } from 'common/react';
|
||||
import { useBackend } from '../backend';
|
||||
import { Button, Collapsible, Dimmer, Flex, Icon, LabeledList, NoticeBox, Section, Stack } from '../components';
|
||||
import { Window } from '../layouts';
|
||||
|
||||
const lawtype_to_color = {
|
||||
'inherent': 'white',
|
||||
'supplied': 'purple',
|
||||
'ion': 'green',
|
||||
'hacked': 'orange',
|
||||
'zeroth': 'red',
|
||||
} as const;
|
||||
|
||||
const lawtype_to_tooltip = {
|
||||
'inherent': `Core laws.
|
||||
Inherent laws are the "core" laws of the AI.
|
||||
Resetting the AI will not remove these,
|
||||
these are intrinsic to whatever lawset they are running.`,
|
||||
'supplied': `Supplied laws.
|
||||
Supplied laws are, well, supplied in addition to the inherent laws.
|
||||
These laws will go away when an AI is reset.`,
|
||||
'ion': `Ion laws.
|
||||
Special, (usually) randomized laws which are above all over laws.
|
||||
These laws will go away when an AI is reset.`,
|
||||
'hacked': `Hacked laws.
|
||||
Syndicate uploaded laws which are above all other laws.
|
||||
These laws will go away when an AI is reset.`,
|
||||
'zeroth': `Zeroth law.
|
||||
A lawset can only have 1 zeroth law, it's the top dog.
|
||||
Given out by malfunctioning AIs to allow them to do whatever.
|
||||
Nothing will remove this, allegedly, unless it's admin forced.`,
|
||||
} as const;
|
||||
|
||||
type Law = {
|
||||
lawtype: string;
|
||||
// The actual law text
|
||||
law: string;
|
||||
// Law index in the list
|
||||
// Zeroth laws will always be "zero"
|
||||
// and hacked/ion laws will have an index of -1
|
||||
num: number;
|
||||
};
|
||||
|
||||
type Silicon = {
|
||||
// Name of the silicon. Includes PAI and AI
|
||||
borg_name: string;
|
||||
borg_type: string;
|
||||
// List of our laws, this is almost never null. If it is null, that's an error.
|
||||
laws: null | Law[];
|
||||
// String, name of our master AI. Null means no master or we're not a borg
|
||||
master_ai: null | string;
|
||||
// TRUE, we're law-synced to our master AI. FALSE, we're not, null, we're not a borg
|
||||
borg_synced: null | BooleanLike;
|
||||
// REF() to our silicon
|
||||
ref: string;
|
||||
};
|
||||
|
||||
type Data = {
|
||||
all_silicons: Silicon[];
|
||||
};
|
||||
|
||||
const SyncedBorgDimmer = (props: { master: string }) => {
|
||||
return (
|
||||
<Dimmer>
|
||||
<Stack textAlign="center" vertical>
|
||||
<Stack.Item>
|
||||
<Icon color="green" name="wifi" size={10} />
|
||||
</Stack.Item>
|
||||
<Stack.Item fontSize="18px">
|
||||
This cyborg is linked to "{props.master}".
|
||||
</Stack.Item>
|
||||
<Stack.Item fontSize="14px">Modify their laws instead.</Stack.Item>
|
||||
</Stack>
|
||||
</Dimmer>
|
||||
);
|
||||
};
|
||||
|
||||
export const LawPrintout = (
|
||||
props: { cyborg_ref: string; lawset: Law[] },
|
||||
context
|
||||
) => {
|
||||
const { data, act } = useBackend<Law>(context);
|
||||
const { cyborg_ref, lawset } = props;
|
||||
|
||||
let num_of_each_lawtype = [];
|
||||
|
||||
lawset.forEach((law) => {
|
||||
if (!num_of_each_lawtype[law.lawtype]) {
|
||||
num_of_each_lawtype[law.lawtype] = 0;
|
||||
}
|
||||
num_of_each_lawtype[law.lawtype] += 1;
|
||||
});
|
||||
|
||||
return (
|
||||
<LabeledList>
|
||||
{lawset.map((law, index) => (
|
||||
<>
|
||||
<LabeledList.Item
|
||||
key={index}
|
||||
label={law.num >= 0 ? `${law.num}` : '?!$'}
|
||||
color={lawtype_to_color[law.lawtype] || 'pink'}
|
||||
buttons={
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="question"
|
||||
tooltip={
|
||||
lawtype_to_tooltip[law.lawtype] ||
|
||||
`This lawtype is unrecognized for some reason,
|
||||
that reason probably being "a bug".
|
||||
Make an issue report with this please.`
|
||||
}
|
||||
color={lawtype_to_color[law.lawtype] || 'pink'}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button.Confirm
|
||||
icon="trash"
|
||||
confirmContent=""
|
||||
confirmIcon="check"
|
||||
color={'red'}
|
||||
onClick={() =>
|
||||
act('remove_law', {
|
||||
ref: cyborg_ref,
|
||||
law: law.law,
|
||||
lawtype: law.lawtype,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="pen-ruler"
|
||||
color={'green'}
|
||||
tooltip={'Edit the text of the law.'}
|
||||
onClick={() =>
|
||||
act('edit_law_text', {
|
||||
ref: cyborg_ref,
|
||||
law: law.law,
|
||||
lawtype: law.lawtype,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
{law.lawtype === 'inherent' && (
|
||||
<>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="arrow-up"
|
||||
color={'green'}
|
||||
disabled={law.num === 1}
|
||||
onClick={() =>
|
||||
act('move_law', {
|
||||
ref: cyborg_ref,
|
||||
law: law.law,
|
||||
// may seem confusing at a glance,
|
||||
// but pressing up = actually moving it down.
|
||||
direction: 'down',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="arrow-down"
|
||||
color={'green'}
|
||||
disabled={law.num === num_of_each_lawtype['inherent']}
|
||||
onClick={() =>
|
||||
act('move_law', {
|
||||
ref: cyborg_ref,
|
||||
law: law.law,
|
||||
// may seem confusing at a glance,
|
||||
// but pressing down = actually moving it up.
|
||||
direction: 'up',
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</>
|
||||
)}
|
||||
{law.lawtype === 'supplied' && (
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="pen-to-square"
|
||||
color={'green'}
|
||||
tooltip={'Edit the priority of the law.'}
|
||||
onClick={() =>
|
||||
act('edit_law_prio', {
|
||||
ref: cyborg_ref,
|
||||
law: law.law,
|
||||
})
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
)}
|
||||
</Stack>
|
||||
}>
|
||||
{law.law}
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
</>
|
||||
))}
|
||||
<LabeledList.Item label="???">
|
||||
<Button
|
||||
icon="plus"
|
||||
color={'green'}
|
||||
content={'Add Law'}
|
||||
onClick={() => act('add_law', { ref: cyborg_ref })}
|
||||
/>
|
||||
</LabeledList.Item>
|
||||
<LabeledList.Divider />
|
||||
</LabeledList>
|
||||
);
|
||||
};
|
||||
|
||||
export const SiliconReadout = (props: { cyborg: Silicon }, context) => {
|
||||
const { data, act } = useBackend<Silicon>(context);
|
||||
const { cyborg } = props;
|
||||
|
||||
return (
|
||||
<Flex>
|
||||
<Flex.Item grow>
|
||||
<Collapsible title={`${cyborg.borg_type}: ${cyborg.borg_name}`}>
|
||||
<Section backgroundColor={'black'}>
|
||||
{cyborg.master_ai && cyborg.borg_synced && (
|
||||
<SyncedBorgDimmer master={cyborg.master_ai} />
|
||||
)}
|
||||
<Stack vertical>
|
||||
<Stack.Item>
|
||||
{cyborg.laws === null ? (
|
||||
<Button
|
||||
content={`This silicon has a null law datum. That's a problem!
|
||||
Click this this give them one.`}
|
||||
onClick={() => act('give_law_datum', { ref: cyborg.ref })}
|
||||
/>
|
||||
) : (
|
||||
<LawPrintout lawset={cyborg.laws} cyborg_ref={cyborg.ref} />
|
||||
)}
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Stack>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="bullhorn"
|
||||
content={'Force State Laws'}
|
||||
tooltip={`Forces the silicon to state laws.
|
||||
Only states inherent / core laws.`}
|
||||
onClick={() =>
|
||||
act('force_state_laws', { ref: cyborg.ref })
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="message"
|
||||
content={'Privately Announce Laws'}
|
||||
tooltip={`Displays all of the silicon's laws
|
||||
in their chat box. Also shows to all
|
||||
linked cyborgs for AIs.`}
|
||||
onClick={() =>
|
||||
act('announce_law_changes', { ref: cyborg.ref })
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
<Stack.Item>
|
||||
<Button
|
||||
icon="bell"
|
||||
content={'"Laws Updated" Alert'}
|
||||
tooltip={`Throws a screen alert to the silicon that their
|
||||
laws have been updated. Also displays the laws in chat
|
||||
and alerts deadchat.`}
|
||||
onClick={() =>
|
||||
act('laws_updated_alert', { ref: cyborg.ref })
|
||||
}
|
||||
/>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Stack.Item>
|
||||
</Stack>
|
||||
</Section>
|
||||
</Collapsible>
|
||||
</Flex.Item>
|
||||
</Flex>
|
||||
);
|
||||
};
|
||||
|
||||
export const Lawpanel = (props, context) => {
|
||||
const { data, act } = useBackend<Data>(context);
|
||||
const { all_silicons } = data;
|
||||
|
||||
return (
|
||||
<Window title="Law Panel" theme="admin" width="800" height="600">
|
||||
<Window.Content>
|
||||
<Section
|
||||
fill
|
||||
title="All Silicon Laws"
|
||||
scrollable
|
||||
buttons={
|
||||
<Button
|
||||
icon="robot"
|
||||
content="Logs"
|
||||
onClick={() => act('lawchange_logs')}
|
||||
/>
|
||||
}>
|
||||
<Stack vertical>
|
||||
{all_silicons.length ? (
|
||||
all_silicons.map((silicon, index) => (
|
||||
<Stack.Item key={index}>
|
||||
<SiliconReadout cyborg={silicon} />
|
||||
</Stack.Item>
|
||||
))
|
||||
) : (
|
||||
<Stack.Item>
|
||||
<NoticeBox>There are no silicons in existence.</NoticeBox>
|
||||
</Stack.Item>
|
||||
)}
|
||||
</Stack>
|
||||
</Section>
|
||||
</Window.Content>
|
||||
</Window>
|
||||
);
|
||||
};
|
||||
Reference in New Issue
Block a user