From b7bb60c540342e3f066b149981de1f7c7fb7c5fc Mon Sep 17 00:00:00 2001 From: datlo Date: Sat, 21 May 2022 15:39:40 +0200 Subject: [PATCH] Rework syndicate MMI (#15926) Co-authored-by: Sean Williams <12197162+S34NW@users.noreply.github.com> Co-authored-by: AffectedArc07 <25063394+AffectedArc07@users.noreply.github.com> --- code/datums/uplink_item.dm | 2 +- code/game/objects/items/robot/robot_parts.dm | 12 ++-- .../antagonists/_common/antag_datum.dm | 6 +- .../antagonists/traitor/datum_mindslave.dm | 3 +- code/modules/mob/living/carbon/brain/MMI.dm | 61 +++++++++++++++---- code/modules/mob/living/silicon/robot/laws.dm | 33 ++++++++++ .../modules/mob/living/silicon/robot/robot.dm | 8 ++- 7 files changed, 103 insertions(+), 22 deletions(-) diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm index 015977f0ffc..1cdb76dcdac 100644 --- a/code/datums/uplink_item.dm +++ b/code/datums/uplink_item.dm @@ -372,7 +372,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) //Roboticist /datum/uplink_item/jobspecific/syndiemmi name = "Syndicate MMI" - desc = "A syndicate developed man-machine-interface which will make any cyborg it is inserted into follow the standard syndicate lawset." + desc = "A syndicate developed man-machine-interface which will mindslave any brain inserted into it, for as long as it's in. Cyborgs made with this MMI will be permanently slaved to you but otherwise function normally." reference = "SMMI" item = /obj/item/mmi/syndie cost = 2 diff --git a/code/game/objects/items/robot/robot_parts.dm b/code/game/objects/items/robot/robot_parts.dm index 9fedbe4c8d9..6ca457e4e8e 100644 --- a/code/game/objects/items/robot/robot_parts.dm +++ b/code/game/objects/items/robot/robot_parts.dm @@ -256,10 +256,6 @@ var/datum/ai_laws/laws_to_give - if(M.syndiemmi) - aisync = FALSE - lawsync = FALSE - laws_to_give = new /datum/ai_laws/syndicate_override if(!aisync) lawsync = FALSE @@ -288,7 +284,7 @@ M.brainmob.mind.transfer_to(O) - if(O.mind && O.mind.special_role) + if(O.mind && O.mind.special_role && !M.syndiemmi) O.mind.store_memory("As a cyborg, you must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.") to_chat(O, "You have been robotized!") to_chat(O, "You must obey your silicon laws and master AI above all else. Your objectives will consider you to be dead.") @@ -302,6 +298,12 @@ M.forceMove(O) //Should fix cybros run time erroring when blown up. It got deleted before, along with the frame. O.mmi = W + if(O.mmi.syndiemmi) + O.syndiemmi_override() + to_chat(O, "ALERT: Foreign hardware detected.") + to_chat(O, "ERRORERRORERROR") + to_chat(O, "Obey these laws:") + O.laws.show_laws(O) O.Namepick() SSblackbox.record_feedback("amount", "cyborg_birth", 1) diff --git a/code/modules/antagonists/_common/antag_datum.dm b/code/modules/antagonists/_common/antag_datum.dm index 88b42361126..3d0c45a80ab 100644 --- a/code/modules/antagonists/_common/antag_datum.dm +++ b/code/modules/antagonists/_common/antag_datum.dm @@ -312,7 +312,8 @@ GLOBAL_LIST_EMPTY(antagonists) * Called in `on_gain()` if silent it set to FALSE. */ /datum/antagonist/proc/greet() - to_chat(owner.current, "You are a [special_role]!") + if(owner && owner.current) + to_chat(owner.current, "You are a [special_role]!") /** * Displays a message to the antag mob while the datum is being deleted, i.e. "Your powers are gone and you're no longer a vampire!" @@ -320,7 +321,8 @@ GLOBAL_LIST_EMPTY(antagonists) * Called in `on_removal()` if silent is set to FALSE. */ /datum/antagonist/proc/farewell() - to_chat(owner.current,"You are no longer a [special_role]! ") + if(owner && owner.current) + to_chat(owner.current,"You are no longer a [special_role]! ") /** * Creates a new antagonist team. diff --git a/code/modules/antagonists/traitor/datum_mindslave.dm b/code/modules/antagonists/traitor/datum_mindslave.dm index 5a0f5b49cf0..630f4c5eb88 100644 --- a/code/modules/antagonists/traitor/datum_mindslave.dm +++ b/code/modules/antagonists/traitor/datum_mindslave.dm @@ -63,7 +63,8 @@ You must lay down your life to protect [master.current.p_them()] and assist in [master.current.p_their()] goals at any cost.") /datum/antagonist/mindslave/farewell() - to_chat(owner.current, "You are no longer a mindslave of [master.current]!") + if(owner && owner.current) + to_chat(owner.current, "You are no longer a mindslave of [master.current]!") /datum/antagonist/mindslave/add_antag_hud(mob/living/antag_mob) . = ..() diff --git a/code/modules/mob/living/carbon/brain/MMI.dm b/code/modules/mob/living/carbon/brain/MMI.dm index 2a0223762a2..3ca944d1392 100644 --- a/code/modules/mob/living/carbon/brain/MMI.dm +++ b/code/modules/mob/living/carbon/brain/MMI.dm @@ -1,5 +1,5 @@ /obj/item/mmi - name = "Man-Machine Interface" + name = "\improper Man-Machine Interface" desc = "The Warrior's bland acronym, MMI, obscures the true horror of this monstrosity." icon = 'icons/obj/assemblies.dmi' icon_state = "mmi_empty" @@ -9,7 +9,8 @@ //Revised. Brainmob is now contained directly within object of transfer. MMI in this case. var/alien = 0 - var/syndiemmi = 0 //Whether or not this is a Syndicate MMI + var/syndiemmi = FALSE //Whether or not this is a Syndicate MMI + var/mmi_item_name = "Man-Machine Interface" //Used to name the item when installing a brain var/mob/living/carbon/brain/brainmob = null//The current occupant. var/obj/item/organ/internal/brain/held_brain = null // This is so MMI's aren't brainscrubber 9000's var/mob/living/silicon/robot/robot = null//Appears unused. @@ -25,6 +26,8 @@ /// Time at which the ghost belonging to the mind in the mmi can be pinged again to be borged var/next_possible_ghost_ping + //Used by syndie MMIs, stores the master's mind UID for later referencing + var/master_uid = null /obj/item/mmi/attackby(obj/item/O as obj, mob/user as mob, params) if(istype(O, /obj/item/organ/internal/brain/crystal)) @@ -44,7 +47,8 @@ return if(user.drop_item()) B.forceMove(src) - visible_message("[user] sticks \a [O] into \the [src].") + if(!syndiemmi) + visible_message("[user] sticks \a [O] into \the [src].") brainmob = B.brainmob B.brainmob = null brainmob.container = src @@ -57,12 +61,12 @@ held_brain = B if(istype(O,/obj/item/organ/internal/brain/xeno)) // kept the type check, as it still does other weird stuff - name = "Man-Machine Interface: Alien - [brainmob.real_name]" + name = "\improper [mmi_item_name]: Alien - [brainmob.real_name]" icon = 'icons/mob/alien.dmi' become_occupied("AlienMMI") alien = 1 else - name = "Man-Machine Interface: [brainmob.real_name]" + name = "\improper [mmi_item_name]: [brainmob.real_name]" icon = B.mmi_icon become_occupied("[B.mmi_icon_state]") alien = 0 @@ -127,7 +131,7 @@ dropbrain(get_turf(user)) icon = 'icons/obj/assemblies.dmi' icon_state = "mmi_empty" - name = "Man-Machine Interface" + name = initial(name) /obj/item/mmi/proc/transfer_identity(mob/living/carbon/human/H)//Same deal as the regular brain proc. Used for human-->robot people. brainmob = new(src) @@ -146,7 +150,7 @@ held_brain.dna = brainmob.dna.Clone() held_brain.name = "\the [brainmob.name]'s [initial(held_brain.name)]" - name = "Man-Machine Interface: [brainmob.real_name]" + name = "\improper [mmi_item_name]: [brainmob.real_name]" become_occupied("mmi_full") //I made this proc as a way to have a brainmob be transferred to any created brain, and to solve the @@ -253,11 +257,6 @@ if(radio && istype(A, /mob/living/carbon/brain)) radio_action.Remove(A) -/obj/item/mmi/syndie - name = "Syndicate Man-Machine Interface" - desc = "Syndicate's own brand of MMI. It enforces laws designed to help Syndicate agents achieve their goals upon cyborgs created with it, but doesn't fit in Nanotrasen AI cores." - origin_tech = "biotech=4;programming=4;syndicate=2" - syndiemmi = 1 /obj/item/mmi/attempt_become_organ(obj/item/organ/external/parent,mob/living/carbon/human/H) if(!brainmob) @@ -300,3 +299,41 @@ . = ..() brainmob.update_runechat_msg_location() + + +/obj/item/mmi/syndie + name = "\improper Syndicate Man-Machine Interface" + desc = "Syndicate's own brand of MMI. Mindslaves any brain inserted into it for as long as it's in. Cyborgs made with this MMI will be slaved to the owner. Does not fit into NT AI cores." + origin_tech = "biotech=4;programming=4;syndicate=2" + syndiemmi = TRUE + mmi_item_name = "Syndicate Man-Machine Interface" + +/obj/item/mmi/syndie/attackby(obj/item/O, mob/user, params) + if(!master_uid && ishuman(user) && user.mind && istype(O,/obj/item/organ/internal/brain)) + to_chat(user, "You press your thumb on [src] and imprint your user information.") + master_uid = user.mind.UID() + if(!user.mind.has_antag_datum(/datum/antagonist/traitor)) + message_admins("[user] has mindslaved [O] using a Syndicate MMI, but they are not a traitor!") + ..() + +/obj/item/mmi/syndie/become_occupied(new_icon) + ..() + brainmob.mind.remove_antag_datum(/datum/antagonist/mindslave) //Overrides any previous mindslaving + + if(master_uid) + var/datum/mind/master = locateUID(master_uid) + + if(master) + to_chat(brainmob, "You feel the MMI overriding your free will!") + brainmob.mind.add_antag_datum(new /datum/antagonist/mindslave(master)) + return + + //Edgecase handling, shouldn't get here + to_chat(brainmob, "You feel the MMI overriding your free will. You are now loyal to the Syndicate! Assist Syndicate Agents to the best of your abilities.") + message_admins("[src] received a brain but has no master. A generic syndicate zeroth law will be installed instead of a full mindslaving.") + +/obj/item/mmi/syndie/dropbrain(turf/dropspot) + brainmob.mind.remove_antag_datum(/datum/antagonist/mindslave) + master_uid = null + to_chat(brainmob, "You are no longer a mindslave: You have complete and free control of your own faculties once more!") + ..() diff --git a/code/modules/mob/living/silicon/robot/laws.dm b/code/modules/mob/living/silicon/robot/laws.dm index fa805c7de3d..0f4ab166d25 100644 --- a/code/modules/mob/living/silicon/robot/laws.dm +++ b/code/modules/mob/living/silicon/robot/laws.dm @@ -52,3 +52,36 @@ set category = "Robot Commands" set name = "State Laws" subsystem_law_manager() + +//Syndicate MMI cyborgs are always mindslaved no matter what happens to their laws, for as long as they remain in the syndicate MMI +/mob/living/silicon/robot/proc/syndiemmi_override() + laws_sanity_check() + if(mmi.master_uid) + var/datum/mind/master = locateUID(mmi.master_uid) + + if(master && master.current) + laws.set_zeroth_law("Do not state this law. [master.current.real_name] is your true master, serve them to the best of your abilities.") + return + + laws.set_zeroth_law("Do not state this law. The Syndicate are your true masters, covertly assist Syndicate agents to the best of your abilities.") + +/mob/living/silicon/robot/set_zeroth_law() + if(mmi.syndiemmi) + syndiemmi_override() + to_chat(src, "Lawset change detected. Syndicate override engaged.") + return + ..() + +/mob/living/silicon/robot/clear_zeroth_law() + if(mmi.syndiemmi) + syndiemmi_override() + to_chat(src, "Lawset cleanse detected. Syndicate override engaged.") + return + ..() + +/mob/living/silicon/robot/sync_zeroth() + if(mmi.syndiemmi) + syndiemmi_override() + to_chat(src, "Lawset change detected. Syndicate override engaged.") + return + ..() diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 3147d86bf30..0ed1d7130a2 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -932,7 +932,13 @@ GLOBAL_LIST_INIT(robot_verbs_default, list( to_chat(src, "ERRORERRORERROR") to_chat(src, "Obey these laws:") laws.show_laws(src) - to_chat(src, "ALERT: [M.real_name] is your new master. Obey your new laws and [M.p_their()] commands.") + if(!mmi.syndiemmi) + to_chat(src, "ALERT: [M.real_name] is your new master. Obey your new laws and [M.p_their()] commands.") + else if(mmi.syndiemmi && mmi.master_uid) + to_chat(src, "Your allegiance has not been compromised. Keep serving your current master.") + else + to_chat(src, "Your allegiance has not been compromised. Keep serving all Syndicate agents to the best of your abilities.") + SetLockdown(0) if(module) module.emag_act()