Files
Bubberstation/code/datums/wires/robot.dm
John Willard 5fc14ff4bb Adds a notification to silicon/drones being watched (#90471)
## About The Pull Request

Cyborgs now have an alert that shows when someone is watching their
internal camera through a security camera console. SyndEye is excluded
from this as it's spying instead.
Made as an alternative to
https://github.com/tgstation/tgstation/pull/90410 but they also aren't
mutually exclusive, though I have the same fix for borg camera cutting
in this one too.


https://github.com/user-attachments/assets/5dfe92f8-8948-4a80-bb64-cbeaca4f80e0

##### This is part of the same code bounty as
https://github.com/tgstation/tgstation/pull/90410

## Why It's Good For The Game

Pretty much the same reason this PR is an alternative to, it's hard for
borgs to get away with doing antagonist stuff when people are able to
silently watch them at any point from any console or laptop laying
around the station, of which there are many. This hopefully lets borgs
know if someone is watching, to avoid doing anything in front of the
cameras, and to encourage them to get said cameras cut if they plan on
doing anything.

## Changelog

🆑
add: Drones now have internal cameras that shows up on camera consoles
(like Cyborgs)
balance: Cyborgs (and drones) now get a notification when someone is
watching them through a security camera console.
fix: Cutting a Cyborg's camera wire now properly disables it, and
mending it now properly re-enables it.
/🆑

---------

Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com>
2025-04-08 21:41:47 +00:00

121 lines
4.9 KiB
Plaintext

/datum/wires/robot
holder_type = /mob/living/silicon/robot
proper_name = "Cyborg"
randomize = TRUE
/datum/wires/robot/New(atom/holder)
wires = list(
WIRE_AI, WIRE_CAMERA,
WIRE_LAWSYNC, WIRE_LOCKDOWN,
WIRE_RESET_MODEL
)
add_duds(2)
..()
/datum/wires/robot/interactable(mob/user)
if(!..())
return FALSE
var/mob/living/silicon/robot/R = holder
if(R.wiresexposed)
return TRUE
/datum/wires/robot/get_status()
var/mob/living/silicon/robot/R = holder
var/list/status = list()
status += "The law sync module is [R.lawupdate ? "on" : "off"]."
status += "The intelligence link display shows [R.connected_ai ? R.connected_ai.name : "NULL"]."
status += "The camera light is [!isnull(R.builtInCamera) && R.builtInCamera.camera_enabled ? "on" : "off"]."
status += "The lockdown indicator is [R.lockcharge ? "on" : "off"]."
status += "There is a star symbol above the [get_color_of_wire(WIRE_RESET_MODEL)] wire."
return status
/datum/wires/robot/on_pulse(wire, user)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Pulse to pick a new AI.
if(!R.emagged)
var/new_ai
var/is_a_syndi_borg = (ROLE_SYNDICATE in R.faction)
if(user)
new_ai = select_active_ai(user, R.z, !is_a_syndi_borg, is_a_syndi_borg)
else
new_ai = select_active_ai(R, R.z, !is_a_syndi_borg, is_a_syndi_borg)
R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED)
if(new_ai && (new_ai != R.connected_ai))
R.set_connected_ai(new_ai)
log_silicon("[key_name(usr)] synced [key_name(R)] [R.connected_ai ? "from [key_name(R.connected_ai)]": ""] to [key_name(new_ai)]")
if(R.shell)
R.undeploy() //If this borg is an AI shell, disconnect the controlling AI and assign ti to a new AI
R.notify_ai(AI_NOTIFICATION_AI_SHELL)
else
R.notify_ai(TRUE)
if(WIRE_CAMERA) // Pulse to disable the camera.
if(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
R.builtInCamera.toggle_cam(usr, FALSE)
R.visible_message(span_notice("[R]'s camera lens focuses loudly."), span_notice("Your camera lens focuses loudly."))
log_silicon("[key_name(usr)] toggled [key_name(R)]'s camera to [R.builtInCamera.camera_enabled ? "on" : "off"] via pulse")
if(WIRE_LAWSYNC) // Forces a law update if possible.
if(R.lawupdate)
R.visible_message(span_notice("[R] gently chimes."), span_notice("LawSync protocol engaged."))
log_silicon("[key_name(usr)] forcibly synced [key_name(R)]'s laws via pulse")
// TODO, log the laws they gained here
R.lawsync()
R.show_laws()
if(WIRE_LOCKDOWN)
R.SetLockdown(!R.lockcharge) // Toggle
log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)] via pulse")
if(WIRE_RESET_MODEL)
if(R.has_model())
R.visible_message(span_notice("[R]'s model servos twitch."), span_notice("Your model display flickers."))
/datum/wires/robot/on_cut(wire, mend, source)
var/mob/living/silicon/robot/R = holder
switch(wire)
if(WIRE_AI) // Cut the AI wire to reset AI control.
if(!mend)
R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED)
log_silicon("[key_name(usr)] cut AI wire on [key_name(R)][R.connected_ai ? " and disconnected from [key_name(R.connected_ai)]": ""]")
if(R.shell)
R.undeploy()
R.set_connected_ai(null)
R.logevent("AI connection fault [mend ? "cleared" : "detected"]")
if(WIRE_LAWSYNC) // Cut the law wire, and the borg will no longer receive law updates from its AI. Repair and it will re-sync.
if(mend)
if(!R.emagged)
R.lawupdate = TRUE
log_silicon("[key_name(usr)] enabled [key_name(R)]'s lawsync via wire")
else if(!R.deployed) //AI shells must always have the same laws as the AI
R.lawupdate = FALSE
log_silicon("[key_name(usr)] disabled [key_name(R)]'s lawsync via wire")
R.logevent("Lawsync Module fault [mend ? "cleared" : "detected"]")
if (WIRE_CAMERA) // Disable the camera.
if(!QDELETED(R.builtInCamera) && !R.scrambledcodes)
var/fixing_camera = !mend
R.builtInCamera.camera_enabled = fixing_camera
R.builtInCamera.toggle_cam(usr, 0)
R.visible_message(span_notice("[R]'s camera lens focuses loudly."), span_notice("Your camera lens focuses loudly."))
R.logevent("Camera Module fault [fixing_camera ? "cleared" : "detected"]")
log_silicon("[key_name(usr)] [fixing_camera ? "enabled" : "disabled"] [key_name(R)]'s camera via wire")
if(WIRE_LOCKDOWN) // Simple lockdown.
R.SetLockdown(!mend)
R.logevent("Motor Controller fault [mend?"cleared":"detected"]")
log_silicon("[key_name(usr)] [!R.lockcharge ? "locked down" : "released"] [key_name(R)] via wire")
if(WIRE_RESET_MODEL)
if(R.has_model() && !mend)
R.ResetModel()
log_silicon("[key_name(usr)] reset [key_name(R)]'s module via wire")
/datum/wires/robot/can_reveal_wires(mob/user)
if(HAS_TRAIT(user, TRAIT_KNOW_ROBO_WIRES))
return TRUE
return ..()
/datum/wires/robot/always_reveal_wire(color)
// Always reveal the reset model wire.
if(color == get_color_of_wire(WIRE_RESET_MODEL))
return TRUE
return ..()