mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-08-29 16:10:02 +01:00
Adds a Prisoner-VR Cyborg/Mech Control Program (#8057)
Adds a program for security to monitor & control prisoners using mechs/cyborgs via VR.
This commit is contained in:
@@ -2025,6 +2025,7 @@
|
||||
#include "code\modules\modular_computers\file_system\programs\research\ntmonitor.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\camera.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\digitalwarrant.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\security\penalmechs.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\client_manager.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\configurator.dm"
|
||||
#include "code\modules\modular_computers\file_system\programs\system\file_browser.dm"
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#define NETWORK_ENGINEERING_OUTPOST "Engineering Outpost"
|
||||
#define NETWORK_ERT "ZeEmergencyResponseTeam"
|
||||
#define NETWORK_STATION "Station"
|
||||
#define NETWORK_MECHS "Mechs"
|
||||
#define NETWORK_MEDICAL "Medical"
|
||||
#define NETWORK_MERCENARY "MercurialNet"
|
||||
#define NETWORK_MINE "MINE"
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
var/list/mechs = list() // A list of lists, containing the mechs and their networks
|
||||
|
||||
// IPC BODIES
|
||||
var/list/robotnetworks = list("remoterobots", "bunkerrobots")
|
||||
var/list/robotnetworks = list("remoterobots", "bunkerrobots", "prisonrobots")
|
||||
var/list/robots = list()
|
||||
|
||||
/datum/controller/subsystem/virtualreality/New()
|
||||
|
||||
@@ -28,9 +28,6 @@
|
||||
if(!software)
|
||||
to_chat(user, "<span class='warning'>It is missing a software control module.</span>")
|
||||
|
||||
/obj/item/mech_component/sensors/prebuild()
|
||||
radio = new(src)
|
||||
camera = new(src)
|
||||
|
||||
/obj/item/mech_component/sensors/prebuild()
|
||||
radio = new(src)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
else . = ..()
|
||||
|
||||
/mob/living/heavy_vehicle/MouseDrop_T(src_object, over_object, src_location, over_location, src_control, over_control, params, var/mob/user)
|
||||
if(!user || incapacitated() || user.incapacitated())
|
||||
if(!user || incapacitated() || user.incapacitated() || lockdown)
|
||||
return FALSE
|
||||
|
||||
if(!(user in pilots) && user != src)
|
||||
@@ -30,7 +30,7 @@
|
||||
|
||||
/mob/living/heavy_vehicle/ClickOn(var/atom/A, params, var/mob/user)
|
||||
|
||||
if(!user || incapacitated() || user.incapacitated())
|
||||
if(!user || incapacitated() || user.incapacitated() || lockdown)
|
||||
return
|
||||
|
||||
if(!loc) return
|
||||
@@ -258,7 +258,7 @@
|
||||
if(world.time < next_move)
|
||||
return 0
|
||||
|
||||
if(!user || incapacitated() || user.incapacitated())
|
||||
if(!user || incapacitated() || user.incapacitated() || lockdown)
|
||||
return
|
||||
|
||||
if(!legs)
|
||||
@@ -491,3 +491,10 @@
|
||||
return TRUE
|
||||
L.apply_damage(legs.trample_damage, BRUTE)
|
||||
return TRUE
|
||||
|
||||
/mob/living/heavy_vehicle/proc/ToggleLockdown()
|
||||
lockdown = !lockdown
|
||||
if(lockdown)
|
||||
src.visible_message("<span class='warning'>\The [src] beeps loudly as its servos sieze up, and it enters lockdown mode!</span>")
|
||||
else
|
||||
src.visible_message("<span class='warning'>\The [src] hums with life as it is released from its lockdown mode!</span>")
|
||||
@@ -22,7 +22,10 @@
|
||||
update_pilot_overlay()
|
||||
|
||||
if(radio)
|
||||
radio.on = (head && head.radio && head.radio.is_functional())
|
||||
radio.on = (head?.radio && head.radio.is_functional())
|
||||
|
||||
if(camera)
|
||||
camera.status = (head?.camera && head.camera.is_functional())
|
||||
|
||||
body.update_air(hatch_closed && use_air)
|
||||
|
||||
|
||||
@@ -47,6 +47,10 @@
|
||||
to_chat(mover, "<span class='warning'>Maintenance protocols are in effect.</span>")
|
||||
next_move = world.time + 3 // Just to stop them from getting spammed with messages.
|
||||
return MOVEMENT_STOP
|
||||
if(exosuit.lockdown)
|
||||
to_chat(mover, span("warning", "You cannot move while the exosuit's lockdown mode is active."))
|
||||
next_move = world.time + 3 // Just to stop them from getting spammed with messages.
|
||||
return MOVEMENT_STOP
|
||||
var/obj/item/cell/C = exosuit.get_cell()
|
||||
if(!C || !C.check_charge(exosuit.legs.power_use * CELLRATE))
|
||||
to_chat(mover, "<span class='warning'>The power indicator flashes briefly.</span>")
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
var/offset_y = 0
|
||||
|
||||
var/obj/item/device/radio/exosuit/radio
|
||||
var/obj/machinery/camera/camera
|
||||
|
||||
var/wreckage_path = /obj/structure/mech_wreckage
|
||||
|
||||
@@ -49,6 +50,7 @@
|
||||
var/list/hardpoints = list()
|
||||
var/hardpoints_locked
|
||||
var/maintenance_protocols
|
||||
var/lockdown
|
||||
|
||||
// Material
|
||||
var/material/material
|
||||
@@ -181,6 +183,11 @@
|
||||
if(head && head.radio)
|
||||
radio = new(src)
|
||||
|
||||
if(!camera)
|
||||
camera = new /obj/machinery/camera(src)
|
||||
camera.c_tag = name
|
||||
camera.replace_networks(list(NETWORK_MECHS))
|
||||
|
||||
// Create HUD.
|
||||
instantiate_hud()
|
||||
|
||||
|
||||
@@ -177,6 +177,7 @@
|
||||
new /datum/computer_file/program/comm(TRUE),
|
||||
new /datum/computer_file/program/camera_monitor(),
|
||||
new /datum/computer_file/program/digitalwarrant(),
|
||||
new /datum/computer_file/program/penal_mechs(),
|
||||
new /datum/computer_file/program/civilian/cargocontrol(),
|
||||
new /datum/computer_file/program/civilian/cargoorder(),
|
||||
new /datum/computer_file/program/alarm_monitor(),
|
||||
@@ -200,6 +201,7 @@
|
||||
new /datum/computer_file/program/camera_monitor(),
|
||||
new /datum/computer_file/program/comm(),
|
||||
new /datum/computer_file/program/digitalwarrant(),
|
||||
new /datum/computer_file/program/penal_mechs(),
|
||||
new /datum/computer_file/program/records/security()
|
||||
)
|
||||
return _prg_list
|
||||
@@ -216,6 +218,7 @@
|
||||
new /datum/computer_file/program/chatclient(),
|
||||
new /datum/computer_file/program/camera_monitor(),
|
||||
new /datum/computer_file/program/digitalwarrant(),
|
||||
new /datum/computer_file/program/penal_mechs(),
|
||||
new /datum/computer_file/program/records/security(),
|
||||
new /datum/computer_file/program/records/employment(),
|
||||
new /datum/computer_file/program/records/medical()
|
||||
@@ -235,6 +238,7 @@
|
||||
new /datum/computer_file/program/civilian/cargoorder(),
|
||||
new /datum/computer_file/program/camera_monitor(),
|
||||
new /datum/computer_file/program/digitalwarrant(),
|
||||
new /datum/computer_file/program/penal_mechs(),
|
||||
new /datum/computer_file/program/records/security(),
|
||||
new /datum/computer_file/program/records/employment()
|
||||
)
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
/datum/computer_file/program/penal_mechs
|
||||
filename = "penalmechs"
|
||||
filedesc = "Remote Penal Monitoring"
|
||||
program_icon_state = "security"
|
||||
extended_desc = "This program allows monitoring and control of active penal miner mechs."
|
||||
required_access_run = access_armory
|
||||
required_access_download = access_armory
|
||||
requires_ntnet = 1
|
||||
available_on_ntnet = 1
|
||||
network_destination = "penal mining mech monitoring system"
|
||||
size = 11
|
||||
usage_flags = PROGRAM_ALL_REGULAR
|
||||
color = LIGHT_COLOR_ORANGE
|
||||
|
||||
var/obj/machinery/camera/current_camera = null
|
||||
|
||||
/datum/computer_file/program/penal_mechs/ui_interact(mob/user)
|
||||
var/datum/vueui/ui = SSvueui.get_open_ui(user, src)
|
||||
if (!ui)
|
||||
ui = new /datum/vueui/modularcomputer(user, src, "mcomputer-security-penalcontroller", 500, 400, "Penal Mech Monitoring")
|
||||
ui.auto_update_content = 1
|
||||
ui.open()
|
||||
|
||||
/datum/computer_file/program/penal_mechs/vueui_transfer(oldobj)
|
||||
for(var/o in SSvueui.transfer_uis(oldobj, src, "mcomputer-security-penalcontroller", 500, 400, "Penal Mech Monitoring"))
|
||||
var/datum/vueui/ui = o
|
||||
// Let's ensure our ui's autoupdate after transfer.
|
||||
// TODO: revert this value on transfer out.
|
||||
ui.auto_update_content = 1
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/penal_mechs/vueui_data_change(var/list/data, var/mob/user, var/datum/vueui/ui)
|
||||
. = ..()
|
||||
data = . || data || list()
|
||||
|
||||
// Gather data for computer header
|
||||
data["_PC"] = get_header_data(data["_PC"])
|
||||
|
||||
var/datum/signal/signal
|
||||
signal = telecomms_process_active()
|
||||
|
||||
var/list/mechs = list()
|
||||
var/list/robots = list()
|
||||
|
||||
if(signal.data["done"])
|
||||
for(var/mech in SSvirtualreality.mechs["prisonmechs"])
|
||||
var/mob/living/heavy_vehicle/M = mech
|
||||
|
||||
if(!ismech(M))
|
||||
continue
|
||||
if(!AreConnectedZLevels(computer.loc.z, M.loc.z))
|
||||
continue
|
||||
var/list/mechData = list("location" = null, "name" = null, "pilot" = null, "ref" = "\ref[M]", "camera" = null, "lockdown" = null)
|
||||
|
||||
mechData["name"] = M.name
|
||||
mechData["pilot"] = "[M.old_mob]"
|
||||
var/turf/mech_turf = get_turf(M)
|
||||
mechData["location"] = "[mech_turf.x], [mech_turf.y], [mech_turf.z]"
|
||||
|
||||
mechData["camera_status"] = M.camera.status
|
||||
mechData["lockdown"] = M.lockdown
|
||||
mechs[++mechs.len] = mechData
|
||||
|
||||
for(var/robot in SSvirtualreality.robots["prisonrobots"])
|
||||
var/mob/living/R = robot
|
||||
|
||||
if(!ismob(R))
|
||||
continue
|
||||
if(!AreConnectedZLevels(computer.loc.z, R.loc.z))
|
||||
continue
|
||||
var/list/robotData = list("location" = null, "name" = null, "pilot" = null, "ref" = "\ref[R]")
|
||||
|
||||
robotData["name"] = R.name
|
||||
robotData["pilot"] = "[R.old_mob]"
|
||||
var/turf/robot_turf = get_turf(R)
|
||||
robotData["location"] = "[robot_turf.x], [robot_turf.y], [robot_turf.z]"
|
||||
|
||||
robots[++robots.len] = robotData
|
||||
|
||||
data["mechs"] = sortByKey(mechs, "pilot")
|
||||
data["robots"] = sortByKey(robots, "pilot")
|
||||
|
||||
data["current_cam_loc"] = current_camera ? "\ref[current_camera.loc]" : null
|
||||
|
||||
return data // This UI needs to constantly update
|
||||
|
||||
|
||||
/datum/computer_file/program/penal_mechs/Topic(href, href_list)
|
||||
. = ..()
|
||||
|
||||
if(href_list["track_mech"])
|
||||
if(current_camera)
|
||||
reset_current()
|
||||
usr.reset_view()
|
||||
else
|
||||
var/mob/living/heavy_vehicle/M = locate(href_list["track_mech"]) in mob_list
|
||||
if(!istype(M))
|
||||
return FALSE
|
||||
var/obj/machinery/camera/C = M.camera
|
||||
if(C)
|
||||
switch_to_camera(usr, C)
|
||||
return TRUE
|
||||
|
||||
if(href_list["lockdown_mech"])
|
||||
var/mob/living/heavy_vehicle/M = locate(href_list["lockdown_mech"]) in mob_list
|
||||
if(ismob(M))
|
||||
M.ToggleLockdown()
|
||||
return TRUE
|
||||
|
||||
if(href_list["terminate"])
|
||||
var/mob/living/M = locate(href_list["terminate"]) in mob_list
|
||||
if(M?.old_mob && M.vr_mob)
|
||||
to_chat(M, span("warning", "Your connection to remote-controlled [M] is forcibly severed!"))
|
||||
M.body_return()
|
||||
return TRUE
|
||||
|
||||
if(href_list["message_pilot"])
|
||||
var/mob/living/M = locate(href_list["message_pilot"]) in mob_list
|
||||
if(ismob(M))
|
||||
var/message = sanitize(input("Message to [M.old_mob]", "Set Message") as text|null)
|
||||
|
||||
to_chat(usr, span("notice", "Sending message to [M.old_mob]: [message]"))
|
||||
to_chat(M, span("warning", "Remote Penal Monitoring: [message]"))
|
||||
return TRUE
|
||||
|
||||
|
||||
// ToDo - Move this set of camera procs to a general datum when more VueUI programs need cameras
|
||||
/datum/computer_file/program/penal_mechs/proc/switch_to_camera(var/mob/user, var/obj/machinery/camera/C)
|
||||
//don't need to check if the camera works for AI because the AI jumps to the camera location and doesn't actually look through cameras.
|
||||
if(isAI(user))
|
||||
var/mob/living/silicon/ai/A = user
|
||||
// Only allow non-carded AIs to view because the interaction with the eye gets all wonky otherwise.
|
||||
if(!A.is_in_chassis())
|
||||
return FALSE
|
||||
|
||||
A.eyeobj.setLoc(get_turf(C))
|
||||
A.client.eye = A.eyeobj
|
||||
return TRUE
|
||||
|
||||
set_current(C)
|
||||
user.machine = ui_host()
|
||||
user.reset_view(current_camera)
|
||||
check_eye(user)
|
||||
return TRUE
|
||||
|
||||
/datum/computer_file/program/penal_mechs/proc/set_current(var/obj/machinery/camera/C)
|
||||
if(current_camera == C)
|
||||
return
|
||||
|
||||
if(current_camera)
|
||||
reset_current()
|
||||
|
||||
current_camera = C
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_initiated()
|
||||
|
||||
/datum/computer_file/program/penal_mechs/proc/reset_current()
|
||||
if(current_camera)
|
||||
var/mob/living/L = current_camera.loc
|
||||
if(istype(L))
|
||||
L.tracking_cancelled()
|
||||
current_camera = null
|
||||
|
||||
/datum/computer_file/program/penal_mechs/check_eye(var/mob/user)
|
||||
if(!current_camera)
|
||||
return FALSE
|
||||
var/viewflag = current_camera.check_eye(user)
|
||||
if ( viewflag < 0 ) //camera doesn't work
|
||||
reset_current()
|
||||
return viewflag
|
||||
@@ -0,0 +1,8 @@
|
||||
author: mikomyazaki
|
||||
|
||||
delete-after: True
|
||||
|
||||
changes:
|
||||
- rscadd: "Mechs now have a lockdown function."
|
||||
- rscadd: "Mechs can now be linked to cameranet networks."
|
||||
- rscadd: "Adds a program for security that allows them to monitor & lockdown prisoner-controlled mechs and robots."
|
||||
@@ -46,6 +46,7 @@
|
||||
NETWORK_ENGINEERING,
|
||||
NETWORK_ENGINEERING_OUTPOST,
|
||||
NETWORK_STATION,
|
||||
NETWORK_MECHS,
|
||||
NETWORK_MEDICAL,
|
||||
NETWORK_MINE,
|
||||
NETWORK_RESEARCH,
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
<template>
|
||||
<div>
|
||||
<hr>
|
||||
<h3>Remote Penal Mechs</h3>
|
||||
<hr>
|
||||
<div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Pilot</th>
|
||||
<th>Mech Type</th>
|
||||
<th>Location</th>
|
||||
<th>Camera</th>
|
||||
<th>Lockdown</th>
|
||||
<th>End Connection</th>
|
||||
</tr>
|
||||
<tr v-for="mech in mechs" :key="mech.ref">
|
||||
<td>
|
||||
<template v-if="mech.pilot"><vui-button :params="{message_pilot: mech.ref}">{{ mech.pilot }}</vui-button></template>
|
||||
<template v-else><span class="red">n/a</span></template>
|
||||
</td>
|
||||
<td>{{ mech.name }}</td>
|
||||
<td>{{ mech.location }}</td>
|
||||
<td><vui-button :class="{'selected': current_cam_loc == mech.ref}" :params="{track_mech: mech.ref}" :disabled="!mech.camera_status">Track</vui-button></td>
|
||||
<td><vui-button :class="{'red': mech.lockdown}" :params="{lockdown_mech: mech.ref}">Lockdown</vui-button></td>
|
||||
<td><vui-button :params="{terminate: mech.ref}" icon="eject">Terminate</vui-button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<hr>
|
||||
<h3>Remote Penal Cyborgs</h3>
|
||||
<hr>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Pilot</th>
|
||||
<th>Robot Type</th>
|
||||
<th>Location</th>
|
||||
<th>End Connection</th>
|
||||
</tr>
|
||||
<tr v-for="robot in robots" :key="robot.ref">
|
||||
<td>
|
||||
<template v-if="robot.pilot"><vui-button :params="{message_pilot: robot.ref}">{{ robot.pilot }}</vui-button></template>
|
||||
<template v-else><span class="red">n/a</span></template>
|
||||
</td>
|
||||
<td>{{ robot.name }}</td>
|
||||
<td>{{ robot.location }}</td>
|
||||
<td><vui-button :params="{terminate: robot.ref}" icon="eject">Terminate</vui-button></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return this.$root.$data.state
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.table {
|
||||
display: table;
|
||||
width: 100%;
|
||||
|
||||
.header, .mech, .cyborg {
|
||||
display: table-row;
|
||||
font-weight: bold;
|
||||
width: 20%;
|
||||
.header-item, .item {
|
||||
display: table-cell;
|
||||
padding: 1px;
|
||||
vertical-align: middle;
|
||||
font-weight: normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user