Adds silicon access and built-in radio to AI Uplink Brain (only when controlled by AI) (#90112)

## About The Pull Request
- adds silicon access to body controlled by an AI. This is done just by
adding a trait
- adds internal headset with same channels as AI has in its core
(including syndicate and special channels for special AIs)
- binary channel required some additional code to work properly for
carbons without binary key so I decided to also fix big bold text for
borg shells and for big brother. They all have big texts in binary. This
is done by adding new `TRAIT_LOUD_BINARY`
- turns out borg shells also lack loud mode for regular radio, so it is
added too
- ai also locks bodies for themselves the same way as they do with
shells, for consistency
## Why It's Good For The Game
While AIs losing their ability to listen radio when inside uplink brain
can provide so much needed human VS ai conflict (because AI ignored open
door request from that one assistant), it feels a bit unjustified. Same
reason for AI lacking its innate all-access while in carbon body. You
can still open doors for yourself by juggling between uplink brain and
your core so why bother people with additional clicks. It brings carbon
shell on par with silicon shells (and makes them superior cough cough)
## Changelog
🆑
balance: AI uplink brain now comes with built-in radio and free silicon
access for the AI to use
balance: AI entering uplink brain now locks it for themselves. You can
reinsert that brain to reset its controlling AI
fix: fixed AI borg shells and big brother not having loud binary. Now
they do.
/🆑
This commit is contained in:
Iajret
2025-04-29 17:48:16 -06:00
committed by Shadow-Quill
parent 240e4a28f3
commit 9d4fee41a5
8 changed files with 65 additions and 8 deletions
@@ -18,8 +18,12 @@
can_smoothen_out = FALSE
/// if connected, our AI
var/mob/living/silicon/ai/mainframe
/// owner AI of this body (resets in on_mob_remove)
var/mob/living/silicon/ai/connected_ai
/// action for undeployment
var/datum/action/innate/brain_undeployment/undeployment_action = new
/// Weakref to our imaginary brain radio implant
var/datum/weakref/radio_weakref
/obj/item/organ/brain/cybernetic/ai/Initialize(mapload)
. = ..()
@@ -42,12 +46,21 @@
RegisterSignals(brain_owner, list(COMSIG_QDELETING, COMSIG_LIVING_PRE_WABBAJACKED), PROC_REF(undeploy))
RegisterSignal(brain_owner, COMSIG_CARBON_GAIN_ORGAN, PROC_REF(on_organ_gain))
var/obj/item/implant/radio/radio = new(owner)
radio.implant(owner, null, TRUE, TRUE)
radio_weakref = WEAKREF(radio)
/obj/item/organ/brain/cybernetic/ai/on_mob_remove(mob/living/carbon/organ_owner, special, movement_flags)
undeploy()
. = ..()
organ_owner.remove_traits(list(HUMAN_SENSORS_VISIBLE_WITHOUT_SUIT, TRAIT_NO_MINDSWAP, TRAIT_CORPSELOCKED), REF(src))
UnregisterSignal(organ_owner, list(COMSIG_LIVING_HEALTH_UPDATE, COMSIG_CLICK, COMSIG_MOB_GET_STATUS_TAB_ITEMS, COMSIG_MOB_MIND_BEFORE_MIDROUND_ROLL, COMSIG_QDELETING, COMSIG_LIVING_PRE_WABBAJACKED))
var/obj/item/implant/radio/radio = radio_weakref.resolve()
if(radio)
QDEL_NULL(radio)
connected_ai = null
/obj/item/organ/brain/cybernetic/ai/proc/cancel_rolls(mob/living/source, datum/mind/mind, datum/antagonist/antagonist)
SIGNAL_HANDLER
if(ispath(antagonist, /datum/antagonist/malf_ai))
@@ -88,6 +101,8 @@
lines += "Estimated organic/inorganic integrity: [owner.health]"
if(mainframe)
lines += span_warning("Already occupied by another digital entity.")
else if(connected_ai && connected_ai != user)
lines += span_warning("Uplink is locked by another digital entity.")
else if(!is_sufficiently_augmented())
lines += span_warning("Organic organs detected. Robotic organs only, cannot take over.")
else
@@ -118,14 +133,27 @@
ADD_TRAIT(AI.mind, TRAIT_UNCONVERTABLE, REF(src))
ADD_TRAIT(AI, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
AI.mind.transfer_to(owner)
to_chat(owner, span_boldbig("You are still considered a silicon/cyborg/AI. Follow your laws."))
/obj/item/organ/brain/cybernetic/ai/proc/deploy_init(mob/living/silicon/ai/AI)
//todo camera maybe
mainframe = AI
connected_ai = AI
RegisterSignal(AI, COMSIG_QDELETING, PROC_REF(ai_deleted))
undeployment_action.Grant(owner)
update_med_hud_status(owner)
to_chat(owner, span_boldbig("You are still considered a silicon/cyborg/AI. Follow your laws."))
owner.add_traits(list(TRAIT_SILICON_ACCESS, TRAIT_LOUD_BINARY), REF(src))
var/obj/item/implant/radio/implant = radio_weakref.resolve()
if(implant.radio && AI.radio)
if((AI.radio.special_channels & RADIO_SPECIAL_SYNDIE))
implant.radio.make_syndie()
implant.radio.subspace_transmission = TRUE
implant.radio.command = TRUE
implant.radio.channels = AI.radio.channels
for(var/channel in implant.radio.channels)
implant.radio.secure_radio_connections[channel] = add_radio(implant.radio, GLOB.radiochannels[channel])
/obj/item/organ/brain/cybernetic/ai/proc/undeploy(datum/source)
SIGNAL_HANDLER
@@ -144,6 +172,12 @@
mainframe.eyeobj.setLoc(loc)
REMOVE_TRAIT(mainframe.mind, TRAIT_UNCONVERTABLE, REF(src))
REMOVE_TRAIT(mainframe, TRAIT_MIND_TEMPORARILY_GONE, REF(src))
owner.remove_traits(list(TRAIT_SILICON_ACCESS, TRAIT_LOUD_BINARY), REF(src)) // we don't want randoms using our body as free AA, so we only have it when we active.
var/obj/item/implant/radio/implant = radio_weakref.resolve()
if(implant)
implant.radio.resetChannels()
mainframe = null
update_med_hud_status(owner)