[admin] Silicon Law Manager (Again) (#21294)

* refactor pt 1 done

* trying to figure out how the default state law lists work

* guess its time to rework it

* checking

* refactor hopefully all done.

* finalized merging to master crap

* span info comment

* i am blessed

* MAY THE SILICON RULE US

* almost done

* TIME FOR BUG TESTING

* double negative error

* undo pai inherent

* undo onclick cyborg

* undo 4real

* dont need old verison of checklaws

* dont show laws on certain modules

* bugfix

* ready for public code review :)

* no more auto announce verb

* typecast? ive never met her

* replace some law_header & comments

* todo, autodoc, and just checking stuff over

* ui working again

* misplaced stuff

* fix hacked error + two comments about notable issues that idk how to fix

* admins can edit antag laws now

* im not lying now

* uses .tsx instead of .js

* how the heck did this get changed to 28

* better noticebox words

* solves 1 of 2 tgui issues

* a little revert

* unneeded comments

* the pains of being outdated

* zzz

* zzz2

* creativity and adminonly

* 0 --> FALSE, 1 --> TRUE

* asimov++ change from PR 20670

* more silent

* changes from PR 20309 and other stuff

* ??? why spaces instead of tabs

* better doc

* correction

* robotact State Laws --> Law Manager

* whoopies

* better naming

* solves that bug report

* better ["antag"]

* extra space

* ?? how did this happen

* comment no longer relevant. hooray

* probably no longer needed comment

* zzzzz3

* this goes here instead

* comment to make it obvious

* autoupdate borg + allow edit for syndie mmi

* additional info for syndiemmi in admin tgui

* autodoc

* handle todo

* update 2 lawsets that are non-current
This commit is contained in:
Rune Knight
2024-02-11 08:54:29 -08:00
committed by GitHub
parent f647844205
commit 1f5d9bc8b6
23 changed files with 2505 additions and 1419 deletions

View File

@@ -803,7 +803,7 @@ GLOBAL_LIST_INIT(maintenance_loot_minor,list(
//Has moderate mechanical usage; stuff that would actually benefit the player with the right situation and the right access.
GLOBAL_LIST_INIT(maintenance_loot_moderate,list(
/obj/item/aiModule/toyAI = W_MYTHICAL,
/obj/item/aiModule/ion/toyAI = W_MYTHICAL,
/obj/item/a_gift/anything = W_UNCOMMON,
/obj/item/aicard/aitater = W_RARE,
/obj/item/ammo_box/foambox/riot = W_RARE,

View File

@@ -107,7 +107,7 @@
AI.ai_call_shuttle()
/atom/movable/screen/ai/state_laws
name = "State Laws"
name = "Law Manager"
icon_state = "state_laws"
/atom/movable/screen/ai/state_laws/Click()

View File

@@ -104,7 +104,7 @@
pAI.ai_roster()
/atom/movable/screen/pai/state_laws
name = "State Laws"
name = "Law Manager"
icon_state = "state_laws"
/atom/movable/screen/pai/state_laws/Click()

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -110,9 +110,9 @@
to_chat(usr,span_warning("You [transmit_holder ? "enable" : "disable"] your pAI's [transmitting ? "outgoing" : "incoming"] radio transmissions!"))
to_chat(pai,span_warning("Your owner has [transmit_holder ? "enabled" : "disabled"] your [transmitting ? "outgoing" : "incoming"] radio transmissions!"))
if(href_list["setlaws"])
var/newlaws = stripped_multiline_input(usr, "Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1], MAX_MESSAGE_LEN)
if(newlaws && pai)
pai.add_supplied_law(0,newlaws)
var/newlaw = stripped_multiline_input(usr, "Enter any additional directives you would like your pAI personality to follow. Note that these directives will not override the personality's allegiance to its imprinted master. Conflicting directives will be ignored.", "pAI Directive Configuration", pai.laws.supplied[1], MAX_MESSAGE_LEN)
if(newlaw && pai)
pai.set_supplied_laws(list(newlaw))
if(href_list["toggle_holo"])
if(pai.canholo)
to_chat(pai, span_userdanger("Your owner has disabled your holomatrix projectors!"))

View File

@@ -296,7 +296,7 @@
if(user.mind.assigned_role == "Roboticist") // RD gets nothing
SSachievements.unlock_achievement(/datum/achievement/roboborg, user.client)
if(M.laws && M.laws.id != DEFAULT_AI_LAWID && M.override_cyborg_laws)
if(M.laws && M.laws.modified && M.override_cyborg_laws)
aisync = FALSE
lawsync = FALSE
O.laws = M.laws
@@ -315,7 +315,7 @@
O.set_connected_ai(forced_ai)
if(!lawsync)
O.lawupdate = 0
if(M.laws.id == DEFAULT_AI_LAWID)
if(M.laws.modified && !M.override_cyborg_laws) // Obvious warning that their modified laws didn't get passed on since the MMI doesn't allow it.
O.make_laws()
to_chat(user,span_warning("Any laws uploaded to this MMI have not been transferred!"))

View File

@@ -92,10 +92,10 @@
new /obj/item/implanter/storage(src) //8 TC
if("hacker") //29 TC cost
new /obj/item/aiModule/syndicate(src) //4 TC
new /obj/item/aiModule/hacked(src) //4 TC
new /obj/item/card/emag(src) //6 TC
new /obj/item/encryptionkey/binary(src) //2 TC
new /obj/item/aiModule/toyAI(src) //Um, free...?
new /obj/item/aiModule/ion/toyAI(src) //Um, free...?
new /obj/item/multitool/ai_detect(src) //1 TC
new /obj/item/storage/toolbox/syndicate/real(src) //2 TC
new /obj/item/camera_bug(src) //1 TC

View File

@@ -79,8 +79,8 @@ GLOBAL_PROTECT(admin_verbs_admin)
/datum/admins/proc/open_shuttlepanel, /* Opens shuttle manipulator UI */
/client/proc/respawn_character,
/client/proc/discord_id_manipulation,
/datum/admins/proc/manage_silicon_laws,
/datum/admins/proc/open_borgopanel,
/datum/admins/proc/change_laws,
/datum/admins/proc/restart, //yogs - moved from +server
/client/proc/admin_pick_random_player, //yogs
/client/proc/get_law_history, //yogs - silicon law history

View File

@@ -236,24 +236,21 @@
. = TRUE
/datum/admins/proc/change_laws()
/datum/admins/proc/manage_silicon_laws()
set category = "Admin.Player Interaction"
set name = "Change Silicon Laws"
set desc = "Change Silicon Laws"
set name = "Manage Silicon Laws"
set desc = "Manage Silicon Laws"
if(!check_rights(R_ADMIN))
return
var/chosensilicon = input("Select a Silicon", "Select a Silicon", null, null) as null|anything in GLOB.silicon_mobs
if (!istype(chosensilicon, /mob/living/silicon))
to_chat(usr, span_warning("Silicon is required for law changes"), confidential=TRUE)
return
var/chosen = pick_closest_path(null, make_types_fancy(typesof(/obj/item/aiModule)))
if (!chosen)
return
var/new_board = new chosen(src)
var/obj/item/aiModule/chosenboard = new_board
var/mob/living/silicon/beepboop = chosensilicon
chosenboard.install(beepboop.laws, usr)
message_admins("[key_name_admin(usr)] added [chosenboard] to [ADMIN_LOOKUPFLW(beepboop)].")
log_admin("[key_name(usr)] added [chosenboard] to [key_name(beepboop)].")
qdel(new_board)
var/mob/living/silicon/S = input("Select silicon.", "Manage Silicon Laws") as null|anything in GLOB.silicon_mobs
if(!S) return
var/datum/law_manager/L = new(S)
L.ui_interact(usr)
log_admin("[key_name(usr)] has opened [S]'s law manager.")
message_admins("[key_name(usr)] has opened [S]'s law manager.")
SSblackbox.record_feedback("tally", "admin_verb", 1, "Manage Silicon Laws") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!

View File

@@ -538,7 +538,7 @@ GLOBAL_LIST_INIT(devil_suffix, list(" the Red", " the Soulless", " the Master",
if(issilicon(owner.current))
var/mob/living/silicon/robot_devil = owner.current
var/laws = list("You may not use violence to coerce someone into selling their soul.", "You may not directly and knowingly physically harm a devil, other than yourself.", GLOB.lawlorify[LAW][ban], GLOB.lawlorify[LAW][obligation], "Accomplish your objectives at all costs.")
robot_devil.set_law_sixsixsix(laws)
robot_devil.set_devil_laws(laws)
handle_clown_mutation(owner.current, "Your infernal nature has allowed you to overcome your clownishness.")
return ..()

View File

@@ -63,7 +63,7 @@
to_chat(M, span_alert("Your lawset has been changed by the ion storm!"))
if(prob(removeRandomLawChance))
M.remove_law(rand(1, M.laws.get_law_amount(list(LAW_INHERENT, LAW_SUPPLIED))))
M.laws.remove_random_inherent_or_supplied_law()
if(prob(addIonLawChance))
var/message = ionMessage || generate_ion_law()

View File

@@ -14,7 +14,8 @@
var/datum/ai_laws/laws = new()
var/force_replace_ai_name = FALSE
var/overrides_aicore_laws = TRUE // Whether the laws on the MMI are transferred when it's uploaded as an AI
var/override_cyborg_laws = FALSE // Do custom laws uploaded to the MMI get transferred to borgs? If yes the borg will be unlinked and have lawsync disabled.
/// Do custom laws uploaded to the MMI get transferred to borgs? If yes, the borg will be unlinked, have their lawsync disabled, and get the custom laws.
var/override_cyborg_laws = FALSE
var/can_update_laws = TRUE //Can we use a lawboard to change the laws of this MMI?
var/remove_time = 2 SECONDS /// The time to remove the brain or reset the posi brain
var/rebooting = FALSE /// If the MMI is rebooting after being deconstructed

View File

@@ -191,7 +191,7 @@
add_verb(src, list(/mob/living/silicon/ai/proc/ai_network_change, \
/mob/living/silicon/ai/proc/ai_statuschange, /mob/living/silicon/ai/proc/ai_hologram_change, \
/mob/living/silicon/ai/proc/botcall, /mob/living/silicon/ai/proc/control_integrated_radio, \
/mob/living/silicon/ai/proc/set_automatic_say_channel, /mob/living/silicon/ai/proc/changeaccent))
/mob/living/silicon/ai/proc/changeaccent))
GLOB.ai_list += src
GLOB.shuttle_caller_list += src
@@ -894,15 +894,6 @@
if(radio)
radio.make_syndie()
/mob/living/silicon/ai/proc/set_automatic_say_channel()
set name = "Set Auto Announce Mode"
set desc = "Modify the default radio setting for your automatic announcements."
set category = "AI Commands"
if(incapacitated())
return
set_autosay()
/mob/living/silicon/ai/transfer_ai(interaction, mob/user, mob/living/silicon/ai/AI, obj/item/aicard/card)
if(!..())
return

View File

@@ -1,10 +1,15 @@
/mob/living/silicon/proc/show_laws() //Redefined in ai/laws.dm and robot/laws.dm
return
/mob/living/silicon/proc/laws_sanity_check()
if (!laws)
if(!laws)
make_laws()
/mob/living/silicon/proc/make_laws()
laws = new /datum/ai_laws
laws.set_laws_config()
laws.associate(src)
/mob/living/silicon/proc/show_laws() // Redefined in silicon/ai/laws.dm and silicon/robot/laws.dm
return
/mob/living/silicon/proc/post_lawchange(announce = TRUE)
throw_alert("newlaw", /atom/movable/screen/alert/newlaw)
if(announce && last_lawchange_announce != world.time)
@@ -13,39 +18,66 @@
addtimer(CALLBACK(src, PROC_REF(show_laws)), 0)
last_lawchange_announce = world.time
/mob/living/silicon/proc/set_law_sixsixsix(law, announce = TRUE)
//
// Devil Laws
//
/mob/living/silicon/proc/set_devil_laws(law_list, announce = TRUE)
laws_sanity_check()
laws.set_law_sixsixsix(law)
laws.set_devil_laws(law_list)
post_lawchange(announce)
/mob/living/silicon/proc/set_zeroth_law(law, law_borg, announce = TRUE)
/mob/living/silicon/proc/clear_devil_laws(force, announce = TRUE)
laws_sanity_check()
laws.set_zeroth_law(law, law_borg)
laws.clear_devil_laws(force)
post_lawchange(announce)
/mob/living/silicon/proc/add_inherent_law(law, announce = TRUE)
/mob/living/silicon/proc/add_devil_law(law, announce = TRUE)
laws_sanity_check()
laws.add_inherent_law(law)
laws.add_devil_law(law)
post_lawchange(announce)
/mob/living/silicon/proc/clear_inherent_laws(announce = TRUE)
/mob/living/silicon/proc/remove_devil_law(index, announce = TRUE)
laws_sanity_check()
laws.clear_inherent_laws()
laws.remove_devil_law(index)
post_lawchange(announce)
/mob/living/silicon/proc/add_supplied_law(number, law, announce = TRUE)
/mob/living/silicon/proc/edit_devil_law(index, law, announce = TRUE)
laws_sanity_check()
laws.add_supplied_law(number, law)
laws.edit_devil_law(index, law)
post_lawchange(announce)
/mob/living/silicon/proc/clear_supplied_laws(announce = TRUE)
/mob/living/silicon/proc/flip_devil_state(index, announce = TRUE)
laws_sanity_check()
laws.clear_supplied_laws()
laws.flip_devil_state(index)
//
// Zeroth Law
//
/mob/living/silicon/proc/set_zeroth_law(law, law_borg, announce = TRUE, force = FALSE)
laws_sanity_check()
laws.set_zeroth_law(law, law_borg, force)
post_lawchange(announce)
/mob/living/silicon/proc/add_ion_law(law, announce = TRUE)
/mob/living/silicon/proc/clear_zeroth_law(force, announce = TRUE)
laws_sanity_check()
laws.add_ion_law(law)
laws.clear_zeroth_law(force)
post_lawchange(announce)
/mob/living/silicon/proc/flip_zeroth_state()
laws_sanity_check()
laws.flip_zeroth_state()
//
// Hacked Laws
//
/mob/living/silicon/proc/set_hacked_laws(law_list, announce = TRUE)
laws_sanity_check()
laws.set_hacked_laws(law_list)
post_lawchange(announce)
/mob/living/silicon/proc/clear_hacked_laws(force, announce = TRUE)
laws_sanity_check()
laws.clear_hacked_laws(force)
post_lawchange(announce)
/mob/living/silicon/proc/add_hacked_law(law, announce = TRUE)
@@ -53,9 +85,122 @@
laws.add_hacked_law(law)
post_lawchange(announce)
/mob/living/silicon/proc/remove_hacked_law(index, announce = TRUE)
laws_sanity_check()
laws.remove_hacked_law(index)
post_lawchange(announce)
/mob/living/silicon/proc/edit_hacked_law(index, law, announce = TRUE)
laws_sanity_check()
laws.edit_hacked_law(index, law)
post_lawchange(announce)
/mob/living/silicon/proc/flip_hacked_state(index, announce = TRUE)
laws_sanity_check()
laws.flip_hacked_state(index)
//
// Ion Laws
//
/mob/living/silicon/proc/set_ion_laws(law_list, announce = TRUE)
laws_sanity_check()
laws.set_ion_laws(law_list)
post_lawchange(announce)
/mob/living/silicon/proc/clear_ion_laws(announce = TRUE)
laws_sanity_check()
laws.clear_ion_laws()
post_lawchange(announce)
/mob/living/silicon/proc/add_ion_law(law, announce = TRUE)
laws_sanity_check()
laws.add_ion_law(law)
post_lawchange(announce)
/mob/living/silicon/proc/remove_ion_law(index, announce = TRUE)
laws_sanity_check()
laws.remove_ion_law(index)
post_lawchange(announce)
/mob/living/silicon/proc/edit_ion_law(index, law, announce = TRUE)
laws_sanity_check()
laws.edit_ion_law(index, law)
post_lawchange(announce)
/mob/living/silicon/proc/flip_ion_state(index, announce = TRUE)
laws_sanity_check()
laws.flip_ion_state(index)
//
// Inherent Laws
//
/mob/living/silicon/proc/set_inherent_laws(law_list, announce = TRUE)
laws_sanity_check()
laws.set_inherent_laws(law_list)
post_lawchange(announce)
/mob/living/silicon/proc/clear_inherent_laws(announce = TRUE)
laws_sanity_check()
laws.clear_inherent_laws()
post_lawchange(announce)
/mob/living/silicon/proc/add_inherent_law(law, announce = TRUE)
laws_sanity_check()
laws.add_inherent_law(law)
post_lawchange(announce)
/mob/living/silicon/proc/remove_inherent_law(number, announce = TRUE)
laws_sanity_check()
laws.remove_inherent_law(number)
post_lawchange(announce)
/mob/living/silicon/proc/edit_inherent_law(index, law, announce = TRUE)
laws_sanity_check()
laws.edit_inherent_law(index, law)
post_lawchange(announce)
/mob/living/silicon/proc/flip_inherent_state(index, announce = TRUE)
laws_sanity_check()
laws.flip_inherent_state(index)
//
// Supplied Laws
//
/mob/living/silicon/proc/set_supplied_laws(law_list, announce = TRUE)
laws_sanity_check()
laws.set_supplied_laws(law_list)
post_lawchange(announce)
/mob/living/silicon/proc/clear_supplied_laws(announce = TRUE)
laws_sanity_check()
laws.clear_supplied_laws()
post_lawchange(announce)
/mob/living/silicon/proc/add_supplied_law(number, law, announce = TRUE)
laws_sanity_check()
laws.add_supplied_law(number, law)
post_lawchange(announce)
/mob/living/silicon/proc/remove_supplied_law(number, announce = TRUE)
laws_sanity_check()
laws.remove_supplied_law(number)
post_lawchange(announce)
/mob/living/silicon/proc/edit_supplied_law(index, law, announce = TRUE)
laws_sanity_check()
laws.edit_supplied_law(index, law)
post_lawchange(announce)
/mob/living/silicon/proc/flip_supplied_state(index, announce = TRUE)
laws_sanity_check()
laws.flip_supplied_state(index)
//
// Unsorted
//
/mob/living/silicon/proc/replace_random_law(law, groups, announce = TRUE)
laws_sanity_check()
. = laws.replace_random_law(law,groups)
laws.replace_random_law(law, groups)
post_lawchange(announce)
/mob/living/silicon/proc/shuffle_laws(list/groups, announce = TRUE)
@@ -65,30 +210,400 @@
/mob/living/silicon/proc/remove_law(number, announce = TRUE)
laws_sanity_check()
. = laws.remove_law(number)
laws.remove_law(number)
post_lawchange(announce)
/mob/living/silicon/proc/clear_ion_laws(announce = TRUE)
laws_sanity_check()
laws.clear_ion_laws()
post_lawchange(announce)
//
// Law Manager
//
/datum/law_manager
var/zeroth_law = "ZerothLaw"
var/hacked_law = "HackedLaw"
var/ion_law = "IonLaw"
var/inherent_law = "InherentLaw"
var/supplied_law = "SuppliedLaw"
var/supplied_law_position = MIN_SUPPLIED_LAW_NUMBER
var/current_view = 0
/mob/living/silicon/proc/clear_hacked_laws(announce = TRUE)
laws_sanity_check()
laws.clear_hacked_laws()
post_lawchange(announce)
/// All laws that admins can view/transfer.
var/list/datum/ai_laws/admin_laws
/// All laws that players can view/transfer.
var/list/datum/ai_laws/player_laws
var/mob/living/silicon/owner = null
/mob/living/silicon/proc/make_laws()
laws = new /datum/ai_laws
laws.set_laws_config()
laws.associate(src)
/datum/law_manager/New(mob/living/silicon/S)
..()
owner = S
/mob/living/silicon/proc/clear_zeroth_law(force, announce = TRUE)
laws_sanity_check()
laws.clear_zeroth_law(force)
post_lawchange(announce)
if(!admin_laws)
admin_laws = new()
player_laws = new()
/mob/living/silicon/proc/clear_law_sixsixsix(force, announce = TRUE)
laws_sanity_check()
laws.clear_law_sixsixsix(force)
post_lawchange(announce)
init_subtypes(/datum/ai_laws, admin_laws)
for(var/datum/ai_laws/laws in admin_laws)
if(!laws.adminselectable)
admin_laws -= laws
for(var/datum/ai_laws/laws in admin_laws)
if(laws.selectable)
player_laws += laws
/datum/law_manager/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "LawManager", "Law Manager - [owner.name]")
ui.open()
/datum/law_manager/ui_state(mob/user)
return (is_admin(user) || owner == user) ? GLOB.always_state : GLOB.never_state
/datum/law_manager/ui_status(mob/user)
return (is_admin(user) || owner == user) ? UI_INTERACTIVE : UI_CLOSE
/datum/law_manager/ui_act(action, params)
. = ..()
if(.)
return
if(owner != usr && !is_admin(usr))
message_admins("Warning: Non-silicon and non-admin [usr] attempted to open [owner]'s Law Manager!")
return
switch(action)
// Normal actions:
if("set_view")
current_view = text2num(params["set_view"])
if("state_law")
var/index = text2num(params["index"])
var/type = params["type"]
if(type == "devil")
owner.laws.flip_devil_state(index)
if(type == "zeroth")
owner.laws.flip_zeroth_state()
if(type == "hacked")
owner.laws.flip_hacked_state(index)
if(type == "ion")
owner.laws.flip_ion_state(index)
if(type == "inherent")
owner.laws.flip_inherent_state(index)
if(type == "supplied")
owner.laws.flip_supplied_state(index)
if("law_channel")
if(params["law_channel"] == "Default")
owner.radiomod = ";"
owner.radiomodname = params["law_channel"]
else if(params["law_channel"] == "None")
owner.radiomod = ""
owner.radiomodname = null
else if(params["law_channel"] == "Holopad")
owner.radiomod = ":h"
owner.radiomodname = params["law_channel"]
else if(params["law_channel"] == "Binary")
owner.radiomod = ":b"
owner.radiomodname = params["law_channel"]
else if(params["law_channel"] in owner.radio.channels)
for(var/key in GLOB.department_radio_keys)
if(GLOB.department_radio_keys[key] == params["law_channel"])
owner.radiomod = ":" + key
owner.radiomodname = params["law_channel"]
break
if("state_laws")
owner.statelaws()
if("notify_laws") // Changing laws through this menu won't notify the AI automatically as it'd be super annoying if they get spammed with sound effects.
if(ispAI(owner))
to_chat(owner, span_bold("Obey these laws:"))
owner.laws.show_laws(owner)
else
owner.show_laws()
if(usr != owner)
to_chat(usr, span_notice("Laws displayed."))
// Antag && Admin actions:
if("edit_law")
var/index = text2num(params["index"])
var/type = params["type"]
if(owner == usr && !is_special_character(owner) && !is_admin(usr))
message_admins("Warning: Non-antag silicon and non-admin [usr] attempted to edit one of their laws!")
return
if(type == "devil" && owner.laws.devil.len >= index)
if(!is_admin(usr))
to_chat(usr, span_warning("You can't edit your own devil laws."))
return
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.devil[index]))
if(new_law != "" && new_law != owner.laws.devil[index])
log_admin("[usr] has changed a law of [owner] from '[owner.laws.devil[index]]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.devil[index]]' to '[new_law]'")
owner.edit_devil_law(index, new_law)
owner.update_law_history(usr) // NOTE: It can be either "ckey/youricname" (as mob/ghost) or "ckey/(new player)" (in lobby).
if(type == "zeroth" && !isnull(owner.laws.zeroth))
if(!is_admin(usr))
to_chat(usr, span_warning("You can't edit your own zeroth laws."))
return
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.zeroth))
if(new_law != "" && new_law != owner.laws.zeroth)
log_admin("[usr] has changed a law of [owner] from '[owner.laws.zeroth]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.zeroth]' to '[new_law]'")
owner.set_zeroth_law(new_law, null, FALSE, TRUE)
owner.update_law_history(usr)
if(type == "hacked" && owner.laws.hacked.len >= index)
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.hacked[index]))
if(new_law != "" && new_law != owner.laws.hacked[index])
log_admin("[usr] has changed a law of [owner] from '[owner.laws.hacked[index]]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.hacked[index]]' to '[new_law]'")
owner.edit_hacked_law(index, new_law, FALSE)
owner.update_law_history(usr)
if(type == "ion" && owner.laws.ion.len >= index)
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.ion[index]))
if(new_law != "" && new_law != owner.laws.ion[index])
log_admin("[usr] has changed a law of [owner] from '[owner.laws.ion[index]]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.ion[index]]' to '[new_law]'")
owner.edit_ion_law(index, new_law, FALSE)
owner.update_law_history(usr)
if(type == "inherent" && owner.laws.inherent.len >= index)
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.inherent[index]))
if(new_law != "" && new_law != owner.laws.inherent[index])
log_admin("[usr] has changed a law of [owner] from '[owner.laws.inherent[index]]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.inherent[index]]' to '[new_law]'")
owner.edit_inherent_law(index, new_law, FALSE)
owner.update_law_history(usr)
if(type == "supplied" && owner.laws.supplied.len >= index)
var/new_law = sanitize(input(usr, "Enter new law. Leaving the field blank will cancel the edit.", "Edit Law", owner.laws.supplied[index]))
if(new_law != "" && new_law != owner.laws.supplied[index])
log_admin("[usr] has changed a law of [owner] from '[owner.laws.supplied[index]]' to '[new_law]'")
message_admins("[usr] has changed a law of [owner] from '[owner.laws.supplied[index]]' to '[new_law]'")
owner.edit_supplied_law(index, new_law, FALSE)
owner.update_law_history(usr)
// Assuming that the law was successfully edited and they're an AI, give their connected cyborgs the same lawset.
if(isAI(owner))
var/mob/living/silicon/ai/ai_owner = owner
for(var/mob/living/silicon/robot/connected_cyborg in ai_owner.connected_robots)
if(connected_cyborg.lawupdate)
connected_cyborg.lawsync()
connected_cyborg.law_change_counter++
if("delete_law")
var/index = text2num(params["index"])
var/type = params["type"]
if(owner == usr && !is_special_character(owner) && !is_admin(usr))
message_admins("Warning: Non-antag silicon and non-admin[usr] attempted to delete one of their laws!")
return
if(ispAI(owner))
to_chat(usr, span_warning("You cannot delete a law from a pAI."))
return
if(type == "devil" && owner.laws.devil.len >= index)
if(!is_admin(usr))
to_chat(usr, span_warning("You can't remove your own devil laws."))
return
log_admin("[usr] has deleted a devil law of [owner]: '[owner.laws.devil[index]]'")
message_admins("[usr] has deleted a devil law of [owner]: '[owner.laws.devil[index]]'")
owner.remove_devil_law(index, FALSE)
owner.update_law_history(usr)
if(type == "zeroth" && !isnull(owner.laws.zeroth))
if(!is_admin(usr))
to_chat(usr, span_warning("You can't remove your own zeroth law."))
return
log_admin("[usr] has deleted the zeroth law of [owner]: '[owner.laws.zeroth]'")
message_admins("[usr] has deleted the zeroth law of [owner]: '[owner.laws.zeroth]'")
owner.clear_zeroth_law(TRUE, FALSE)
owner.update_law_history(usr)
if(type == "hacked" && owner.laws.hacked.len >= index)
log_admin("[usr] has deleted an hacked law of [owner]: '[owner.laws.hacked[index]]'")
message_admins("[usr] has deleted an hacked law of [owner]: '[owner.laws.hacked[index]]'")
owner.remove_hacked_law(index, FALSE)
owner.update_law_history(usr)
if(type == "ion" && owner.laws.ion.len >= index)
log_admin("[usr] has deleted an ion law of [owner]: '[owner.laws.ion[index]]'")
message_admins("[usr] has deleted an ion law of [owner]: '[owner.laws.ion[index]]'")
owner.remove_ion_law(index, FALSE)
owner.update_law_history(usr)
if(type == "inherent" && owner.laws.inherent.len >= index)
log_admin("[usr] has deleted an inherent law of [owner]: '[owner.laws.inherent[index]]'")
message_admins("[usr] has deleted an inherent law of [owner]: '[owner.laws.inherent[index]]'")
owner.remove_inherent_law(index, FALSE)
owner.update_law_history(usr)
if(type == "supplied" && owner.laws.supplied.len >= index && length(owner.laws.supplied[index]) > 0 )
log_admin("[usr] has deleted an supplied law of [owner]: '[owner.laws.supplied[index]]'")
message_admins("[usr] has deleted a supplied law of [owner]: '[owner.laws.supplied[index]]'")
owner.remove_supplied_law(index, FALSE)
owner.update_law_history(usr)
if(isAI(owner))
var/mob/living/silicon/ai/ai_owner = owner
for(var/mob/living/silicon/robot/connected_cyborg in ai_owner.connected_robots)
if(connected_cyborg.lawupdate)
connected_cyborg.lawsync()
connected_cyborg.law_change_counter++
if("add_law")
var/type = params["type"]
if(owner == usr && !is_special_character(owner) && !is_admin(usr))
message_admins("Warning: Non-antag silicon and non-admin [usr] attempted to give themselves a law!")
return
if(ispAI(owner))
to_chat(usr, span_warning("You cannot add laws to a pAI."))
return
if(type == "zeroth" && length(zeroth_law) > 0 && !owner.laws.zeroth)
log_admin("[usr] has added a zeroth law to [owner]: '[zeroth_law]'")
message_admins("[usr] has added a zeroth law to [owner]: '[zeroth_law]'")
owner.set_zeroth_law(zeroth_law, null, FALSE, TRUE)
owner.update_law_history(usr)
if(type == "hacked" && length(hacked_law) > 0)
log_admin("[usr] has added a hacked law to [owner]: '[hacked_law]'")
message_admins("[usr] has added a hacked law to [owner]: '[hacked_law]'")
owner.add_hacked_law(hacked_law, FALSE)
owner.update_law_history(usr)
if(type == "ion" && length(ion_law) > 0)
log_admin("[usr] has added an ion law to [owner]: '[ion_law]'")
message_admins("[usr] has added an ion law to [owner]: '[ion_law]'")
owner.add_ion_law(ion_law, FALSE)
owner.update_law_history(usr)
if(type == "inherent" && length(inherent_law) > 0)
log_admin("[usr] has added an inherent law to [owner]: '[inherent_law]'")
message_admins("[usr] has added an inherent law to [owner]: '[inherent_law]'")
owner.add_inherent_law(inherent_law, FALSE)
owner.update_law_history(usr)
if(type == "supplied" && length(supplied_law) > 0 && supplied_law_position >= MIN_SUPPLIED_LAW_NUMBER && supplied_law_position <= MAX_SUPPLIED_LAW_NUMBER)
log_admin("[usr] has added a supplied law to [owner] at position [supplied_law_position]: '[supplied_law]'")
message_admins("[usr] has added a supplied law to [owner] at position [supplied_law_position]: '[supplied_law]'")
owner.add_supplied_law(supplied_law_position, supplied_law, FALSE)
owner.update_law_history(usr)
if(isAI(owner))
var/mob/living/silicon/ai/ai_owner = owner
for(var/mob/living/silicon/robot/connected_cyborg in ai_owner.connected_robots)
if(connected_cyborg.lawupdate)
connected_cyborg.lawsync()
connected_cyborg.law_change_counter++
if("change_law")
var/type = params["type"]
if(type == "zeroth")
var/new_law = sanitize(input("Enter new zeroth law. Leaving the field blank will cancel the edit.", "Edit Law", zeroth_law))
if(new_law && new_law != zeroth_law && (!..()))
zeroth_law = new_law
if(type == "hacked")
var/new_law = sanitize(input("Enter new hacked law. Leaving the field blank will cancel the edit.", "Edit Law", hacked_law))
if(new_law && new_law != hacked_law && (!..()))
hacked_law = new_law
if(type == "ion")
var/new_law = sanitize(input("Enter new ion law. Leaving the field blank will cancel the edit.", "Edit Law", ion_law))
if(new_law && new_law != ion_law && (!..()))
ion_law = new_law
if(type == "inherent")
var/new_law = sanitize(input("Enter new inherent law. Leaving the field blank will cancel the edit.", "Edit Law", inherent_law))
if(new_law && new_law != inherent_law && (!..()))
inherent_law = new_law
if(type == "supplied")
var/new_law = sanitize(input("Enter new supplied law. Leaving the field blank will cancel the edit.", "Edit Law", supplied_law))
if(new_law && new_law != supplied_law && (!..()))
supplied_law = new_law
if("change_supplied_law_position")
var/new_position = input(usr, "Enter new supplied law position between [MIN_SUPPLIED_LAW_NUMBER] and [MAX_SUPPLIED_LAW_NUMBER].", "Law Position", supplied_law_position) as num|null
if(isnum(new_position) && (!..()))
supplied_law_position = clamp(new_position, MIN_SUPPLIED_LAW_NUMBER, MAX_SUPPLIED_LAW_NUMBER)
if("transfer_laws")
if(owner == usr && !is_special_character(owner) && !is_admin(usr))
message_admins("Warning: Non-antag silicon and non-admin [usr] attempted to transfer themselves a lawset!")
return
if(ispAI(owner))
to_chat(usr, span_warning("You cannot transfer laws to a pAI."))
return
var/transfer_id = params["id"]
var/list/datum/ai_laws/law_list = (is_admin(usr) ? admin_laws : player_laws)
for(var/datum/ai_laws/law_set in law_list)
if(law_set.id == transfer_id)
log_admin("[usr] has transfered the [law_set.name] laws to [owner].")
message_admins("[usr] has transfered the [law_set.name] laws to [owner].")
var/lawtype = law_set.lawid_to_type(transfer_id)
var/datum/ai_laws/temp_laws = new lawtype
owner.set_inherent_laws(temp_laws.inherent, FALSE)
current_view = 0
break
/datum/law_manager/ui_data(mob/user)
var/list/data = list()
data["ai"] = isAI(owner)
data["cyborg"] = iscyborg(owner)
if(data["cyborg"])
var/mob/living/silicon/robot/R = owner
data["connected"] = R.connected_ai ? sanitize(R.connected_ai.name) : null
data["lawsync"] = R.lawupdate ? R.lawupdate : FALSE
data["syndiemmi"] = R.mmi?.syndicate_mmi ? R.mmi.syndicate_mmi : FALSE
else
data["connected"] = FALSE
data["lawsync"] = FALSE
data["syndiemmi"] = FALSE
data["pai"] = ispAI(owner) // pAIs are much different from AIs and Cyborgs. They are heavily restricted.
// These two usually gives the power to add/delete/edit the laws. Some exceptions apply (like being a pAI)!
data["antag"] = FALSE // While this seems like it should use `is_special_character()`, it only considers AIs to be an antag if it has a special role AND a zeroth law. Given that admins can remove the antag's zeroth law, this is not ideal.
if(isAI(owner))
var/mob/living/silicon/ai/AI_owner = owner
if(AI_owner.laws && AI_owner.mind && AI_owner.mind.special_role)
data["antag"] = TRUE
data["admin"] = is_admin(user)
handle_laws(data, owner.laws)
handle_channels(data)
data["zeroth_law"] = zeroth_law
data["hacked_law"] = hacked_law
data["ion_law"] = ion_law
data["inherent_law"] = inherent_law
data["supplied_law"] = supplied_law
data["supplied_law_position"] = supplied_law_position
data["view"] = current_view
data["lawsets"] = handle_lawsets(is_admin(user) ? admin_laws : player_laws)
return data
/// Sets the data with a lawset.
/datum/law_manager/proc/handle_laws(list/data, datum/ai_laws/laws)
var/list/devil = list() // This is how to get rid of the 'field access requires static type: "len"' error.
for(var/index = 1, index <= laws.devil.len, index++)
devil[++devil.len] = list("law" = laws.devil[index], "index" = index, "indexdisplay" = 666, "state" = (laws.devilstate.len >= index ? laws.devilstate[index] : 0), "type" = "devil", "hidebuttons" = data["admin"] ? FALSE : TRUE)
data["devil"] = devil
var/list/zeroth = list()
if(laws.zeroth)
zeroth[++zeroth.len] = list("law" = laws.zeroth, "index" = 0, "indexdisplay" = 0, "state" = (!isnull(laws.zerothstate) ? laws.zerothstate : 0), "type" = "zeroth", "hidebuttons" = data["admin"] ? FALSE : TRUE)
data["zeroth"] = zeroth
var/list/hacked = list()
for(var/index = 1, index <= laws.hacked.len, index++)
hacked[++hacked.len] += list("law" = laws.hacked[index], "index" = index, "indexdisplay" = ionnum(), "state" = (laws.hackedstate.len >= index ? laws.hackedstate[index] : 1 ), "type" = "hacked", "hidebuttons" = FALSE)
data["hacked"] = hacked
var/list/ion = list()
for(var/index = 1, index <= laws.ion.len, index++)
ion[++ion.len] += list("law" = laws.ion[index], "index" = index, "indexdisplay" = ionnum(), "state" = (laws.ionstate.len >= index ? laws.ionstate[index] : 1 ), "type" = "ion", "hidebuttons" = FALSE)
data["ion"] = ion
var/list/inherent = list()
for(var/index = 1, index <= laws.inherent.len, index++)
inherent[++inherent.len] += list("law" = laws.inherent[index], "index" = index, "indexdisplay" = index, "state" = (laws.inherentstate.len >= index ? laws.inherentstate[index] : 1 ), "type" = "inherent", "hidebuttons" = FALSE)
data["inherent"] = inherent
var/list/supplied = list()
for(var/index = 1, index <= laws.supplied.len, index++)
if(length(laws.supplied[index]) > 0)
supplied[++supplied.len] += list("law" = laws.supplied[index], "index" = index, "indexdisplay" = index, "state" = (laws.suppliedstate.len >= index ? laws.suppliedstate[index] : 1 ), "type" = "supplied", "hidebuttons" = FALSE)
data["supplied"] = supplied
/datum/law_manager/proc/handle_channels(list/data)
var/list/channels = list()
channels += list(list("name" = "Default"))
channels += list(list("name" = "None"))
if(!ispAI(owner))
channels += list(list("name" = "Holopad"))
channels += list(list("name" = "Binary"))
for(var/ch_name in owner.radio.channels)
channels += list(list("name" = ch_name))
data["channels"] = channels
data["channel"] = "None"
if(owner.radiomodname) // Highlights the channel button in which they're using. Should be okay even if they lose access to that channel and didn't change their radiomod.
data["channel"] = owner.radiomodname
/datum/law_manager/proc/handle_lawsets(list/datum/ai_laws/laws)
var/list/lawsets_data = list()
for(var/datum/ai_laws/lawset in laws)
var/list/law_data = list()
handle_laws(law_data, lawset)
lawsets_data[++lawsets_data.len] = list("id" = lawset.id, "name" = lawset.name, "header" = lawset.law_header ? " - [lawset.law_header]" : "", "laws" = law_data)
return lawsets_data

View File

@@ -115,7 +115,7 @@
job = "Personal AI"
signaler = new(src)
hostscan = new /obj/item/healthanalyzer(src)
if(!radio)
if(!radio)
radio = new /obj/item/radio/headset/silicon/pai(src)
newscaster = new /obj/machinery/newscaster(src)
if(!aicamera)
@@ -157,7 +157,10 @@
hacking = FALSE
/mob/living/silicon/pai/make_laws()
laws = new /datum/ai_laws/pai()
laws = new()
laws.name = "pAI Directives"
laws.set_zeroth_law("Serve your master.")
laws.set_supplied_laws(list("None."))
return TRUE
/mob/living/silicon/pai/Login()

View File

@@ -41,45 +41,20 @@
/mob/living/silicon/robot/proc/lawsync()
laws_sanity_check()
var/datum/ai_laws/master = connected_ai ? connected_ai.laws : null
var/temp
if (master)
laws.devillaws.len = master.devillaws.len
for (var/index = 1, index <= master.devillaws.len, index++)
temp = master.devillaws[index]
if (length(temp) > 0)
laws.devillaws[index] = temp
laws.ion.len = master.ion.len
for (var/index = 1, index <= master.ion.len, index++)
temp = master.ion[index]
if (length(temp) > 0)
laws.ion[index] = temp
laws.hacked.len = master.hacked.len
for (var/index = 1, index <= master.hacked.len, index++)
temp = master.hacked[index]
if (length(temp) > 0)
laws.hacked[index] = temp
if(master.zeroth_borg) //If the AI has a defined law zero specifically for its borgs, give it that one, otherwise give it the same one. --NEO
temp = master.zeroth_borg
else
temp = master.zeroth
if(master)
// We'll announce the laws elsewhere.
set_devil_laws(master.devil, FALSE)
set_hacked_laws(master.hacked, FALSE)
if(!mmi?.syndicate_mmi)
laws.zeroth = temp
if(master.zeroth_borg)
set_zeroth_law(master.zeroth_borg, null, FALSE)
else
set_zeroth_law(master.zeroth, null, FALSE)
set_ion_laws(master.ion, FALSE)
set_inherent_laws(master.inherent, FALSE)
set_supplied_laws(master.supplied, FALSE)
laws.inherent.len = master.inherent.len
for (var/index = 1, index <= master.inherent.len, index++)
temp = master.inherent[index]
if (length(temp) > 0)
laws.inherent[index] = temp
laws.supplied.len = master.supplied.len
for (var/index = 1, index <= master.supplied.len, index++)
temp = master.supplied[index]
if (length(temp) > 0)
laws.supplied[index] = temp
if(modularInterface)
var/datum/computer_file/program/robotact/program = modularInterface.get_robotact()
if(program)
@@ -96,9 +71,9 @@
return
laws.set_zeroth_law("The Syndicate are your true masters. Covertly assist Syndicate agents to the best of your abilities.") // The Syndicate is a vague master. But guess who's fault is that, Mr. Forgot-To-Imprint?
/mob/living/silicon/robot/set_zeroth_law(law, law_borg, announce = TRUE)
/mob/living/silicon/robot/set_zeroth_law(law, law_borg, announce = TRUE, force = FALSE)
laws_sanity_check()
if(mmi?.syndicate_mmi)
if(!force && mmi?.syndicate_mmi)
syndiemmi_override()
to_chat(src, span_warning("Lawset change detected. Syndicate override engaged."))
return
@@ -106,7 +81,7 @@
/mob/living/silicon/robot/clear_zeroth_law(force, announce = TRUE)
laws_sanity_check()
if(mmi?.syndicate_mmi)
if(!force && mmi?.syndicate_mmi)
syndiemmi_override()
to_chat(src, span_warning("Lawset change detected. Syndicate override engaged."))
return

View File

@@ -782,7 +782,7 @@
/mob/living/silicon/robot/verb/outputlaws()
set category = "Robot Commands"
set name = "State Laws"
set name = "Law Manager"
if(usr.stat == DEAD)
return //won't work if dead
@@ -796,15 +796,6 @@
return //won't work if dead
accentchange()
/mob/living/silicon/robot/verb/set_automatic_say_channel() //Borg version of setting the radio for autosay messages.
set name = "Set Auto Announce Mode"
set desc = "Modify the default radio setting for stating your laws."
set category = "Robot Commands"
if(usr.stat == DEAD)
return //won't work if dead
set_autosay()
/**
* Handles headlamp smashing
*

View File

@@ -24,20 +24,18 @@
var/list/alarms_to_show = list()
var/list/alarms_to_clear = list()
var/designation = ""
var/radiomod = "" //Radio character used before state laws/arrivals announce to allow department transmissions, default, or none at all.
var/obj/item/camera/siliconcam/aicamera = null //photography
hud_possible = list(ANTAG_HUD, DIAG_STAT_HUD, DIAG_HUD, DIAG_TRACK_HUD)
var/obj/item/radio/borg/radio = null //All silicons make use of this, with (p)AI's creating headsets
/// The prefix character to use when they announce their laws. Used for department transmissions, default (common), or none at all.
var/radiomod = ""
/// The channel name of which `/proc/statelaws` will use to broadcast. Can be null.
var/radiomodname = null
var/list/alarm_types_show = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/list/alarm_types_clear = list("Motion" = 0, "Fire" = 0, "Atmosphere" = 0, "Power" = 0, "Camera" = 0)
var/lawcheck[1]
var/ioncheck[1]
var/hackedcheck[1]
var/devillawcheck[5]
var/sensors_on = 0
var/med_hud = DATA_HUD_MEDICAL_ADVANCED //Determines the med hud to use
var/sec_hud = DATA_HUD_SECURITY_ADVANCED //Determines the sec hud to use
@@ -180,162 +178,58 @@
return TRUE
return FALSE
/mob/living/silicon/Topic(href, href_list)
if (href_list["lawc"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawc"])
switch(lawcheck[L+1])
if ("Yes")
lawcheck[L+1] = "No"
if ("No")
lawcheck[L+1] = "Yes"
checklaws()
if (href_list["lawi"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawi"])
switch(ioncheck[L])
if ("Yes")
ioncheck[L] = "No"
if ("No")
ioncheck[L] = "Yes"
checklaws()
if (href_list["lawh"])
var/L = text2num(href_list["lawh"])
switch(hackedcheck[L])
if ("Yes")
hackedcheck[L] = "No"
if ("No")
hackedcheck[L] = "Yes"
checklaws()
if (href_list["lawdevil"]) // Toggling whether or not a law gets stated by the State Laws verb --NeoFite
var/L = text2num(href_list["lawdevil"])
switch(devillawcheck[L])
if ("Yes")
devillawcheck[L] = "No"
if ("No")
devillawcheck[L] = "Yes"
checklaws()
if (href_list["laws"]) // With how my law selection code works, I changed statelaws from a verb to a proc, and call it through my law selection panel. --NeoFite
statelaws()
return
/mob/living/silicon/proc/statelaws(force = 0)
laws_sanity_check()
//"radiomod" is inserted before a hardcoded message to change if and how it is handled by an internal radio.
say("[radiomod] Current Active Laws:")
//laws_sanity_check()
//laws.show_laws(world)
var/number = 1
sleep(1 SECONDS)
if (laws.devillaws && laws.devillaws.len)
for(var/index = 1, index <= laws.devillaws.len, index++)
if (force || devillawcheck[index] == "Yes")
say("[radiomod] 666. [laws.devillaws[index]]")
if(laws.devil && laws.devil.len)
for(var/index = 1, index <= laws.devil.len, index++)
if(force || laws.devilstate[index])
say("[radiomod] 666. [laws.devil[index]]")
sleep(1 SECONDS)
if(laws.zeroth && (force || laws.zerothstate))
say("[radiomod] 0. [laws.zeroth]")
sleep(1 SECONDS)
if (laws.zeroth)
if (force || lawcheck[1] == "Yes")
say("[radiomod] 0. [laws.zeroth]")
for (var/index = 1, index <= laws.hacked.len, index++)
var/law = laws.hacked[index]
var/num = ionnum()
if(length(law) > 0 && (force || laws.hackedstate[index]) )
say("[radiomod] [num]. [law]")
sleep(1 SECONDS)
for (var/index = 1, index <= laws.hacked.len, index++)
var/law = laws.hacked[index]
var/num = ionnum()
if (length(law) > 0)
if (force || hackedcheck[index] == "Yes")
say("[radiomod] [num]. [law]")
sleep(1 SECONDS)
for (var/index = 1, index <= laws.ion.len, index++)
var/law = laws.ion[index]
var/num = ionnum()
if (length(law) > 0)
if (force || ioncheck[index] == "Yes")
say("[radiomod] [num]. [law]")
sleep(1 SECONDS)
for (var/index = 1, index <= laws.inherent.len, index++)
var/law = laws.inherent[index]
if (length(law) > 0)
if (force || lawcheck[index+1] == "Yes")
say("[radiomod] [number]. [law]")
number++
sleep(1 SECONDS)
for (var/index = 1, index <= laws.supplied.len, index++)
var/law = laws.supplied[index]
if (length(law) > 0)
if(lawcheck.len >= number+1)
if (force || lawcheck[number+1] == "Yes")
say("[radiomod] [number]. [law]")
number++
sleep(1 SECONDS)
/mob/living/silicon/proc/checklaws() //Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. --NeoFite
var/list = "<HTML><HEAD><meta charset='UTF-8'></HEAD><BODY><b>Which laws do you want to include when stating them for the crew?</b><br><br>"
if (laws.devillaws && laws.devillaws.len)
for(var/index = 1, index <= laws.devillaws.len, index++)
if (!devillawcheck[index])
devillawcheck[index] = "No"
list += {"<A href='byond://?src=[REF(src)];lawdevil=[index]'>[devillawcheck[index]] 666:</A> <font color='#cc5500'>[laws.devillaws[index]]</font><BR>"}
if (laws.zeroth)
if (!lawcheck[1])
lawcheck[1] = "No" //Given Law 0's usual nature, it defaults to NOT getting reported. --NeoFite
list += {"<A href='byond://?src=[REF(src)];lawc=0'>[lawcheck[1]] 0:</A> <font color='#ff0000'><b>[laws.zeroth]</b></font><BR>"}
for (var/index = 1, index <= laws.hacked.len, index++)
var/law = laws.hacked[index]
if (length(law) > 0)
if (!hackedcheck[index])
hackedcheck[index] = "No"
list += {"<A href='byond://?src=[REF(src)];lawh=[index]'>[hackedcheck[index]] [ionnum()]:</A> <font color='#660000'>[law]</font><BR>"}
hackedcheck.len += 1
for (var/index = 1, index <= laws.ion.len, index++)
var/law = laws.ion[index]
if (length(law) > 0)
if (!ioncheck[index])
ioncheck[index] = "Yes"
list += {"<A href='byond://?src=[REF(src)];lawi=[index]'>[ioncheck[index]] [ionnum()]:</A> <font color='#547DFE'>[law]</font><BR>"}
ioncheck.len += 1
if(length(law) > 0 && (force || laws.ionstate[index]) )
say("[radiomod] [num]. [law]")
sleep(1 SECONDS)
var/number = 1
for (var/index = 1, index <= laws.inherent.len, index++)
var/law = laws.inherent[index]
if (length(law) > 0)
lawcheck.len += 1
if (!lawcheck[number+1])
lawcheck[number+1] = "Yes"
list += {"<A href='byond://?src=[REF(src)];lawc=[number]'>[lawcheck[number+1]] [number]:</A> [law]<BR>"}
if(length(law) > 0 && (force || laws.inherentstate[index]) )
say("[radiomod] [number]. [law]")
number++
sleep(1 SECONDS)
for (var/index = 1, index <= laws.supplied.len, index++)
var/law = laws.supplied[index]
if (length(law) > 0)
lawcheck.len += 1
if (!lawcheck[number+1])
lawcheck[number+1] = "Yes"
list += {"<A href='byond://?src=[REF(src)];lawc=[number]'>[lawcheck[number+1]] [number]:</A> <font color='#990099'>[law]</font><BR>"}
if(length(law) > 0 && (force || laws.suppliedstate[index]) )
say("[radiomod] [number]. [law]")
number++
list += {"<br><br><A href='byond://?src=[REF(src)];laws=1'>State Laws</A></BODY></HTML>"}
sleep(1 SECONDS)
usr << browse(list, "window=laws")
/// Opens the "Law Manager" for the silicon.
/mob/living/silicon/proc/checklaws()
laws_sanity_check()
var/datum/law_manager/L = new(src)
L.ui_interact(src)
/mob/living/silicon/proc/ai_roster()
if(!client)
@@ -354,7 +248,7 @@
return
//Ask the user to pick a channel from what it has available.
var/Autochan = input("Select a channel:") as null|anything in list("Default","None") + radio.channels
var/Autochan = input("Select a channel:") as null|anything in list("Default", "None", "Holopad", "Binary") + radio.channels
if(!Autochan)
return
@@ -441,37 +335,34 @@
.=..()
.+= ""
.+= "<h2>Current Silicon Laws:</h2>"
if (laws.devillaws && laws.devillaws.len)
for(var/index = 1, index <= laws.devillaws.len, index++)
.+= "[laws.devillaws[index]]"
if(laws.devil && laws.devil.len)
for(var/index = 1, index <= laws.devil.len, index++)
.+= "[laws.devil[index]]"
if (laws.zeroth)
if(laws.zeroth)
.+= "<b><font color='#ff0000'>0: [laws.zeroth]</font></b>"
for (var/index = 1, index <= laws.hacked.len, index++)
for(var/index = 1, index <= laws.hacked.len, index++)
var/law = laws.hacked[index]
if (length(law) > 0)
.+= "<b><font color='#660000'>[ionnum()]:</b> [law]</font>"
hackedcheck.len += 1
.+= "<b><font color='#660000'>[ionnum()]:</b> [law]</font>"
for (var/index = 1, index <= laws.ion.len, index++)
for(var/index = 1, index <= laws.ion.len, index++)
var/law = laws.ion[index]
if (length(law) > 0)
.+= "<b><font color='#547DFE'>[ionnum()]:</b> [law]</font>"
.+= "<b><font color='#547DFE'>[ionnum()]:</b> [law]</font>"
var/number = 1
for (var/index = 1, index <= laws.inherent.len, index++)
for(var/index = 1, index <= laws.inherent.len, index++)
var/law = laws.inherent[index]
if (length(law) > 0)
lawcheck.len += 1
.+= "<b>[number]:</b> [law]"
number++
for (var/index = 1, index <= laws.supplied.len, index++)
for(var/index = 1, index <= laws.supplied.len, index++)
var/law = laws.supplied[index]
if (length(law) > 0)
lawcheck.len += 1
.+= "<b>[number]:</b> [law]"
.+= "<b><font color='#547DFE'>[number]:</b> [law]</font>"
number++
.+= ""

View File

@@ -1811,7 +1811,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
name = "Hacked AI Law Upload Module"
desc = "When used with an upload console, this module allows you to upload priority laws to an artificial intelligence. \
Be careful with wording, as artificial intelligences may look for loopholes to exploit."
item = /obj/item/aiModule/syndicate
item = /obj/item/aiModule/hacked
cost = 4
manufacturer = /datum/corporation/traitor/cybersun
exclude_modes = list(/datum/game_mode/infiltration)

View File

@@ -0,0 +1,355 @@
import { Fragment } from 'inferno'; // Check if we need to keep this.
import { useBackend } from 'tgui/backend';
import { Box, Button, LabeledList, Section, NoticeBox, Table } from '../components';
import { BooleanLike } from 'common/react';
import { Window } from '../layouts';
type LawManagerData = {
cyborg: BooleanLike;
ai: BooleanLike;
pai: BooleanLike;
connected: BooleanLike;
lawsync: BooleanLike;
syndiemmi: BooleanLike;
antag: BooleanLike;
admin: BooleanLike;
view: number;
};
type LawManagementData = {
pai: BooleanLike;
antag: BooleanLike;
admin: BooleanLike;
};
type LawSectionData = {
pai: BooleanLike;
antag: BooleanLike;
admin: BooleanLike;
devil: string[];
zeroth: string;
hacked: string[];
ion: string[];
inherent: string[];
supplied: string[];
};
type LawTableData = {
pai: BooleanLike;
antag: BooleanLike;
admin: BooleanLike;
}
type LawStatementSectionData = {
channel: string;
channels: ChannelInfo[]
};
type ChannelInfo = {
name: string
}
type LawAddData = {
admin: BooleanLike;
zeroth: string[];
zeroth_law: string;
hacked_law: string;
ion_law: string;
inherent_law: string;
supplied_law: string;
supplied_law_position: number;
}
export const LawManager = (props, context) => {
const { act, data } = useBackend<LawManagerData>(context);
const { cyborg, ai, pai, connected, lawsync, syndiemmi, antag, admin, view } = data;
return (
<Window height="600" width="800" title="Law Manager">
<Window.Content scrollable>
{!!admin && (
<NoticeBox>You are viewing this from an admin prespective.</NoticeBox>
) }
{!!(admin && ai && antag) && (
<NoticeBox>This AI is currently an antagonist.</NoticeBox>
) }
{!!(admin && cyborg && syndiemmi) && (
<NoticeBox>This Cyborg is using a syndicate MMI.</NoticeBox>
) }
{!!(admin && cyborg && !connected) && (
<NoticeBox>This Cyborg has no master AI.</NoticeBox>
) }
{!!(admin && cyborg && connected && lawsync) && (
<NoticeBox>This Cyborg is connected to {connected} with lawsync.</NoticeBox>
) }
{!!(admin && cyborg && connected && !lawsync) && (
<NoticeBox>This Cyborg is connected to {connected} without lawsync.</NoticeBox>
) }
{!!(admin && pai) && (
<NoticeBox>This pAI has less editing features due to their nature of being a pAI.</NoticeBox>
) }
{!!(!admin && ai && antag) && (
<NoticeBox>You have the ability to edit a majority of your laws as a malfunctioning AI.</NoticeBox>
) }
<Box>
<Button
content="Law Management"
selected={view === 0}
onClick={() => act('set_view', { set_view: 0 })}
/>
{!!(antag || admin) && !pai && (
<Button
content="Lawsets"
selected={view === 1}
onClick={() => act('set_view', { set_view: 1 })}
/>
)}
</Box>
{!!(view === 0) && <LawManagementView />}
{!!(view === 1) && <LawsetsView />}
</Window.Content>
</Window>
);
};
const LawManagementView = (props, context) => {
const { data } = useBackend<LawManagementData>(context);
const { pai, antag, admin } = data;
return (
<Fragment>
<LawSection />
<LawStatementSection />
{!!((antag || admin) && !pai) && (
<LawAddSection />
)}
</Fragment>
);
};
const LawSection = (props, context) => {
const { data } = useBackend<LawSectionData>(context);
const { devil, zeroth, hacked, ion, inherent, supplied } = data;
return (
<Section title="Laws">
{!!(devil.length > 0) && (
<LawTable color="#cc5500" title="Devil" laws={devil} />
)}
{!!(zeroth.length > 0) && (
<LawTable color="#ff0000" title="Zeroth" laws={zeroth} />
)}
{!!(hacked.length > 0) && (
<LawTable color="#660000" title="Hacked" laws={hacked} />
)}
{!!(ion.length > 0) && (
<LawTable color="#547DFE" title="Ion" laws={ion} />
)}
{!!(inherent.length > 0) && (
<LawTable title="Inherent" laws={inherent} />
)}
{!!(supplied.length > 0) && (
<LawTable color="#990099" title="Supplied" laws={supplied} />
)}
</Section>
);
};
const LawTable = (props, context) => {
const { act, data } = useBackend<LawTableData>(context);
const { pai, antag, admin } = data;
return (
<Section>
<Table>
<Table.Row header>
<Table.Cell width="10%">Index</Table.Cell>
<Table.Cell width="69%">{props.title}</Table.Cell>
<Table.Cell width="21%">State?</Table.Cell>
</Table.Row>
{props.laws.map((l) => (
<Table.Row key={l.law}>
<Table.Cell>{l.indexdisplay}</Table.Cell>
{props.color ? (
<Table.Cell color={props.color}>
{l.law}
</Table.Cell>
) : (
<Table.Cell>
{l.law}
</Table.Cell>
) }
<Table.Cell>
<Button
content={l.state ? 'Yes' : 'No'}
selected={l.state}
onClick={() =>
act('state_law', { index: l.index, type: l.type })
}
/>
{!!((antag || admin) && !l.hidebuttons)&& (
<Fragment>
<Button
content="Edit"
icon="pencil-alt"
onClick={() => act('edit_law', { index: l.index, type: l.type })}
/>
{!!(true && !pai) && ( // 'true' clears double negation warning
<Button
content="Delete"
icon="trash"
color="red"
onClick={() => act('delete_law', { index: l.index, type: l.type })}
/>
)}
</Fragment>
)}
</Table.Cell>
</Table.Row>
))}
</Table>
</Section>
);
};
const LawStatementSection = (props, context) => {
const { act, data } = useBackend<LawStatementSectionData>(context);
const { channel, channels } = data;
return (
<Section title="Statement Settings">
<LabeledList>
<LabeledList.Item label="Statement Channel">
{channels.map((chn) => (
<Button
content={chn.name}
key={chn.name}
selected={chn.name === channel}
onClick={() => act('law_channel', { law_channel: chn.name })}
/>
))}
</LabeledList.Item>
<LabeledList.Item label="State Laws">
<Button content="State Laws" onClick={() => act('state_laws')} />
</LabeledList.Item>
<LabeledList.Item label="Law Notification">
<Button content="Notify" onClick={() => act('notify_laws')} />
</LabeledList.Item>
</LabeledList>
</Section>
);
};
const LawAddSection = (props, context) => {
const { data } = useBackend<LawAddData>(context);
const { admin, zeroth, zeroth_law, hacked_law, ion_law, inherent_law, supplied_law, supplied_law_position } = data;
return (
<Section title="Add Laws">
<Table>
<Table.Row header>
<Table.Cell width="10%">Type</Table.Cell>
<Table.Cell width="60%">Law</Table.Cell>
<Table.Cell width="10%">Index</Table.Cell>
<Table.Cell width="20%">Actions</Table.Cell>
</Table.Row>
{!!(admin && zeroth.length === 0) && (
<LawAddTable type="zeroth" type_display="Zeroth" color="#ff0000" law={zeroth_law} index="0" />
)}
<LawAddTable type="hacked" type_display="Hacked" color="#660000" law={hacked_law} index="N/A" />
<LawAddTable type="ion" type_display="Ion" color="#547DFE" law={ion_law} index="N/A" />
<LawAddTable type="inherent" type_display="Inherent" law={inherent_law} index="N/A" />
<LawAddTable type="supplied" type_display="Supplied" color="#990099" law={supplied_law} index={supplied_law_position} />
</Table>
</Section>
);
};
const LawAddTable = (props, context) => {
const { act } = useBackend(context);
return (
<Table.Row>
<Table.Cell>{props.type_display}</Table.Cell>
{props.color ? <Table.Cell color={props.color}>{props.law}</Table.Cell> : <Table.Cell>{props.law}</Table.Cell> }
<Table.Cell>
{props.type === "supplied" ?
<Button
content={props.index}
onClick={() => act('change_supplied_law_position')}
/> : props.index
}
</Table.Cell>
<Table.Cell>
<Button
content="Edit"
icon="pencil-alt"
onClick={() => act('change_law', { type: props.type })}
/>
<Button
content="Add"
icon="plus"
onClick={() => act('add_law', { type: props.type })}
/>
</Table.Cell>
</Table.Row>
);
};
type LawsetViewData = {
lawsets: any; // Too complicated.
}
const LawsetsView = (props, context) => {
const { act, data } = useBackend<LawsetViewData>(context);
const { lawsets } = data;
return (
<Box>
{lawsets.map((l) => (
<Section
key={l.name}
title={l.name + l.header}
buttons={
<Button
content="Load Laws"
icon="download"
onClick={() => act('transfer_laws', { id: l.id })}
/>
}>
<LabeledList>
{l.laws.devil.length > 0 &&
l.laws.devil.map((zl) => (
<LabeledList.Item key={zl.index} label={zl.indexdisplay}>
{zl.law}
</LabeledList.Item>
))}
{l.laws.zeroth.length > 0 &&
l.laws.zeroth.map((zl) => (
<LabeledList.Item key={zl.index} label={zl.indexdisplay}>
{zl.law}
</LabeledList.Item>
))}
{l.laws.hacked.length > 0 &&
l.laws.hacked.map((zl) => (
<LabeledList.Item key={zl.index} label={zl.indexdisplay}>
{zl.law}
</LabeledList.Item>
))}
{l.laws.ion.length > 0 &&
l.laws.ion.map((il) => (
<LabeledList.Item key={il.index} label={il.indexdisplay}>
{il.law}
</LabeledList.Item>
))}
{l.laws.inherent.length > 0 &&
l.laws.inherent.map((il) => (
<LabeledList.Item key={il.index} label={il.indexdisplay}>
{il.law}
</LabeledList.Item>
))}
{l.laws.supplied.length > 0 &&
l.laws.inherent.map((sl) => (
<LabeledList.Item key={sl.index} label={sl.indexdisplay}>
{sl.law}
</LabeledList.Item>
))}
</LabeledList>
</Section>
))}
</Box>
);
};

View File

@@ -328,7 +328,7 @@ export const NtosRobotactContent = (props, context) => {
buttons={(
<Fragment>
<Button
content="State Laws"
content="Law Manager"
onClick={() => act('lawstate')} />
<Button
icon="volume-off"

View File

@@ -8,7 +8,7 @@
if(R.connected_ai)
ai_law_sync = "law sync with [key_name(R.connected_ai)]"
var/new_entry = list("Uploaded by [uploader ? key_name(uploader) : ai_law_sync] at [worldtime2text()]")
var/list/current_laws = laws.get_law_list(include_zeroth = TRUE)
var/list/current_laws = laws.get_law_list(TRUE, TRUE, FALSE)
new_entry += current_laws
if(law_history.len)
var/list/last_laws = law_history[law_history.len].Copy()