Files
Aurora.3/code/game/objects/structures/machinery/computer/robot.dm
T
Batrachophreno 4ecb0bc21c Repath obj/machinery to obj/structure/machinery [MDB Ignore] (#22500)
Repaths obj/machinery to obj/structure/machinery. **Note for
reviewers:** the only meaningful changed code exists within
**code/game/objects/structures.dm** and
**code/game/objects/structures/_machinery.dm**, largely concerning
damage procs. With the exception of moving airlock defines to their own
file, ALL OTHER CHANGES ARE STRICTLY PATH CHANGES.

Objects, _categorically_, are largely divided between those you can hold
in your hand/inventory and those you can't. Machinery objects are
already subtypes of Structures behaviorally, this PR just makes their
pathing reflect that, and allows for future work (tool actions, more
health/destruction functionality) to be developed without unnecessary
code duplication.

I have tested this PR by loading up the Horizon and dismantling various
machines and structures with tools, shooting guns of various types
throughout the ship, and detonating a bunch of explosions throughout the
ship.
2026-05-26 19:35:48 +00:00

229 lines
8.2 KiB
Plaintext

/obj/structure/machinery/computer/robotics
name = "robotics control console"
desc = "Used to remotely lockdown or detonate linked cyborgs."
icon = 'icons/obj/modular_computers/modular_console.dmi'
icon_screen = "robot"
icon_keyboard = "purple_key"
icon_keyboard_emis = "purple_key_mask"
light_color = LIGHT_COLOR_PURPLE
req_one_access = list(ACCESS_RD, ACCESS_ROBOTICS)
circuit = /obj/item/circuitboard/robotics
var/safety = TRUE
/obj/structure/machinery/computer/robotics/attack_ai(mob/user)
if(!ai_can_interact(user))
return
ui_interact(user)
/obj/structure/machinery/computer/robotics/attack_hand(mob/user)
ui_interact(user)
/obj/structure/machinery/computer/robotics/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "RoboticsControl", "Robotic Control Console")
ui.open()
/obj/structure/machinery/computer/robotics/ui_data(mob/user)
return list(
"robots" = get_cyborgs(user),
"safety" = safety,
"is_ai" = issilicon(user)
)
/obj/structure/machinery/computer/robotics/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
return
var/mob/user = usr
if(!src.allowed(user))
to_chat(user, "Access denied.")
return
switch(action)
// Destroys the cyborg
if("detonate")
var/mob/living/silicon/robot/target = get_cyborg_by_name(params["name"])
if(!target || !istype(target))
return
if(isAI(user) && (target.connected_ai != user))
to_chat(user, "Access denied. This robot is not linked to you.")
return
// Cyborgs may blow up themselves via the console
if(isrobot(user) && user != target)
to_chat(user, "Access denied.")
return
var/choice = tgui_alert(user, "Really detonate [target.name]?", "Robotics Control", list("Yes", "No"))
if(choice != "Yes")
return TRUE
if(!target || !istype(target))
return TRUE
// Antagonistic cyborgs? Left here for downstream
if(target.mind && target.mind.special_role && target.emagged)
to_chat(target, "Extreme danger. Termination codes detected. Scrambling security codes and automatic AI unlink triggered.")
target.ResetSecurityCodes()
return TRUE
if(target.emagged)
to_chat(user, "Access denied. Safety protocols are disabled.")
return TRUE
message_admins("[key_name_admin(user)] detonated [target.name]!")
log_game("[key_name(user)] detonated [target.name]!")
to_chat(target, SPAN_DANGER("Self-destruct command received."))
addtimer(CALLBACK(target, TYPE_PROC_REF(/mob/living/silicon/robot, self_destruct)), 1 SECONDS)
return TRUE
// Locks or unlocks the cyborg
if("lockdown")
var/mob/living/silicon/robot/target = get_cyborg_by_name(params["name"])
if(!target || !istype(target))
return
if(isAI(user) && (target.connected_ai != user))
to_chat(user, "Access denied. This robot is not linked to you.")
return
if(isrobot(user))
to_chat(user, "Access denied.")
return
if(target.emagged)
return TRUE
var/choice = tgui_alert(user, "Really [target.lock_charge ? "unlock" : "lockdown"] [target.name]?", "Robotics Control", list("Yes", "No"))
if(choice != "Yes")
return TRUE
if(!target || !istype(target))
return TRUE
target.SetLockdown(!target.lock_charge)
message_admins("[key_name_admin(user)] [target.lock_charge ? "locked down" : "released"] [target.name]!")
log_game("[key_name(user)] [target.lock_charge ? "locked down" : "released"] [target.name]!")
to_chat(target, (target.lock_charge ? "You have been locked down!" : "Your lockdown has been lifted!"))
return TRUE
// Changes borg's access
if("access")
var/mob/living/silicon/robot/target = get_cyborg_by_name(params["name"])
if(!istype(target))
return
if(isAI(user) && (target.connected_ai != user))
to_chat(user, "Access denied. This robot is not linked to you.")
return
if(isrobot(user) || target.emagged)
to_chat(user, "Access denied.")
return
if(!target.module)
to_chat(user, "\The [src]\s access protocols are immutable.")
return TRUE
target.module.all_access = !target.module.all_access
target.update_access()
var/log_message = "[key_name_admin(user)] changed [target.name] access to [target.module.all_access ? "all access" : "role specific"]."
message_admins(log_message)
log_game(log_message)
to_chat(target, "Your access was changed to: [target.module.all_access ? "all access" : "role specific"].")
return TRUE
// Remotely hacks the cyborg. Only antag AIs can do this and only to linked cyborgs.
if("hack")
var/mob/living/silicon/robot/target = get_cyborg_by_name(params["name"])
if(!target || !istype(target))
return
if(!istype(user, /mob/living/silicon/ai) || !(user.mind.special_role && user.mind.original == user))
to_chat(user, "Access denied.")
return
if(target.emagged)
to_chat(user, "Robot is already hacked.")
return TRUE
var/choice = tgui_alert(user, "Really hack [target.name]? This cannot be undone.", "Robotics Control", list("Yes", "No"))
if(choice != "Yes")
return TRUE
if(!target || !istype(target))
return TRUE
message_admins("[key_name_admin(user)] emagged [target.name] using robotic console!")
log_game("[key_name(user)] emagged [target.name] using robotic console!")
target.emagged = TRUE
to_chat(target, SPAN_NOTICE("Failsafe protocols overriden. New tools available."))
return TRUE
// Arms/disarms the emergency self-destruct system
if("arm")
if(istype(user, /mob/living/silicon))
to_chat(user, "Access denied.")
return
safety = !safety
to_chat(user, "You [safety ? "disarm" : "arm"] the emergency self destruct")
return TRUE
// Destroys all accessible cyborgs if safety is disabled
if("nuke")
if(istype(user, /mob/living/silicon))
to_chat(user, "Access denied.")
return
if(safety)
to_chat(user, "Self-destruct aborted - safety active")
return TRUE
message_admins("[key_name_admin(user)] detonated all cyborgs!")
log_game("[key_name(user)] detonated all cyborgs!")
for(var/mob/living/silicon/robot/cyborg in GLOB.mob_list)
if(istype(cyborg, /mob/living/silicon/robot/drone))
continue
if(cyborg.scrambled_codes)
continue
if(cyborg.emagged)
continue
to_chat(cyborg, SPAN_DANGER("Self-destruct command received."))
addtimer(CALLBACK(cyborg, TYPE_PROC_REF(/mob/living/silicon/robot, self_destruct)), 1 SECONDS)
return TRUE
/**
* Returns a list of accessible cyborgs for the TGUI interface.
*
* * operator - The mob operating the console; determines AI-specific hackable status visibility
*/
/obj/structure/machinery/computer/robotics/proc/get_cyborgs(mob/operator)
var/list/robots = list()
for(var/mob/living/silicon/robot/cyborg in GLOB.mob_list)
// Ignore drones
if(istype(cyborg, /mob/living/silicon/robot/drone))
continue
// Ignore antagonistic cyborgs
if(cyborg.scrambled_codes)
continue
var/list/robot = list()
robot["name"] = cyborg.name
if(cyborg.stat)
robot["status"] = "Not Responding"
else if(cyborg.lock_charge) // changed this from !cyborg.canmove to cyborg.lock_charge because of issues with lockdown and chairs
robot["status"] = "Lockdown"
else
robot["status"] = "Operational"
if(cyborg.cell)
robot["cell"] = TRUE
robot["cell_capacity"] = cyborg.cell.maxcharge
robot["cell_current"] = cyborg.cell.charge
robot["cell_percentage"] = round(cyborg.cell.percent())
else
robot["cell"] = FALSE
robot["module"] = cyborg.module ? cyborg.module.name : "None"
robot["master_ai"] = cyborg.connected_ai ? cyborg.connected_ai.name : "None"
robot["hackable"] = FALSE
robot["access"] = cyborg.module ? cyborg.module.all_access : FALSE
// Antag AIs know whether linked cyborgs are hacked or not.
if(operator && istype(operator, /mob/living/silicon/ai) && (cyborg.connected_ai == operator) && (operator.mind.special_role && operator.mind.original == operator))
robot["hacked"] = cyborg.emagged ? TRUE : FALSE
robot["hackable"] = cyborg.emagged ? FALSE : TRUE
robots.Add(list(robot))
return robots
/// Finds a cyborg mob by name in the global mob list. Returns null if not found.
/obj/structure/machinery/computer/robotics/proc/get_cyborg_by_name(name)
if(!name)
return
for(var/mob/living/silicon/robot/cyborg in GLOB.mob_list)
if(cyborg.name == name)
return cyborg