From 054653de87893db0140baeb38c03fc3a79b5ea26 Mon Sep 17 00:00:00 2001 From: Tim Date: Sat, 23 May 2026 13:41:43 -0500 Subject: [PATCH] Add a "Prison Block" holodeck map (#96032) ## About The Pull Request This adds a new "Prison Block" holodeck simulation, accessible only when the holodeck safeties are disabled (or emagged). The layout features four functional jail cells with holographic flashers, a security desk, evidence lockers, an electric death chair, and camera/record consoles. StrongDMM-2026-05-10 20 22 24 ## Why It's Good For The Game While many departments have dedicated holodeck programs, Security currently lacks a specialized simulation. By placing a functional brig within an emagged simulation, we create opportunities for emergent scenarios: - Antagonists now have more non-lethal options to detain and hold personnel - Security now has a backup brig during station emergencies - Power cuts, EMPs, or AI intervention can trigger instant prison breaks - With the press of a button, switching the simulation can transform it into a death trap for everyone inside This creates high-tension gameplay for both the captors and the captives. The electric chair was only used in the pirate shuttle (ruin?) and didn't work properly, so it needed some code updates. Also, I did not like how insulated gloves prevented electric shocks from working, so I made it bypass insulation. I had to add holodeck versions of brig lockers and security windoors so now any ID can open windoors/lockers. People cannot open windoors/lockers without an ID, so you must strip them of their ID when imprisoning them, otherwise they can just walk out. ## Changelog :cl: map: Added a "Prison Block" holodeck simulation, accessible via the disabled safety/emagged menu. code: Fixed electric chairs to work, and they now bypass insulation from gloves when executing a mob. code: Added holodeck versions of brig lockers and windoors that allow anyone with a station ID card to access them. /:cl: --- _maps/templates/holodeck_prison.dmm | 475 ++++++++++++++++++ code/game/machinery/doors/windowdoor.dm | 12 + .../crates_lockers/closets/secure/security.dm | 3 + code/game/objects/structures/electricchair.dm | 8 +- .../holodeck/holodeck_map_templates.dm | 6 + 5 files changed, 502 insertions(+), 2 deletions(-) create mode 100644 _maps/templates/holodeck_prison.dmm diff --git a/_maps/templates/holodeck_prison.dmm b/_maps/templates/holodeck_prison.dmm new file mode 100644 index 00000000000..615491e6bd1 --- /dev/null +++ b/_maps/templates/holodeck_prison.dmm @@ -0,0 +1,475 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"b" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 1 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"c" = ( +/obj/effect/turf_decal/caution, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"d" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 8 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"e" = ( +/obj/effect/turf_decal/board_number/two{ + pixel_y = 21 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"f" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/machinery/flasher/directional/east{ + id = "Holodeck Cell 3"; + pixel_x = 0 + }, +/obj/structure/window/reinforced/spawner/directional/north, +/turf/open/floor/holofloor/white, +/area/template_noop) +"g" = ( +/obj/structure/table, +/obj/machinery/button/flasher{ + id = "Holodeck Cell 2"; + name = "Cell 2"; + pixel_y = 8 + }, +/obj/machinery/button/flasher{ + id = "Holodeck Cell 4"; + name = "Cell 4"; + pixel_y = -3 + }, +/obj/item/restraints/handcuffs{ + pixel_x = -17; + pixel_y = 9 + }, +/obj/item/restraints/handcuffs{ + pixel_x = -17; + pixel_y = -3 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"h" = ( +/obj/machinery/computer/security{ + dir = 4 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"j" = ( +/obj/structure/bed, +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/item/bedsheet/red, +/turf/open/floor/holofloor/white, +/area/template_noop) +"k" = ( +/obj/structure/chair/e_chair{ + dir = 1 + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"l" = ( +/obj/machinery/status_display/door_timer{ + id = "Holodeck Cell 2"; + req_access = null; + name = "Cell 2" + }, +/obj/structure/table, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"n" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 10 + }, +/obj/structure/closet/secure_closet/brig/holodeck{ + id = "Holodeck Cell 4" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"o" = ( +/obj/effect/turf_decal/board_number/four, +/turf/open/floor/holofloor, +/area/template_noop) +"p" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 5 + }, +/obj/item/instrument/harmonica, +/obj/machinery/door/window/brigdoor/security/holodeck/left/directional/north{ + id = "Holodeck Cell 3"; + name = "Cell 3" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"q" = ( +/obj/effect/turf_decal/board_number/one{ + pixel_y = 21 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"r" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 6 + }, +/obj/structure/closet/secure_closet/brig/holodeck{ + id = "Holodeck Cell 3" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"s" = ( +/turf/open/floor/holofloor, +/area/template_noop) +"t" = ( +/obj/item/book/manual/wiki/security_space_law{ + pixel_y = 13 + }, +/obj/structure/table, +/obj/machinery/recharger, +/obj/item/restraints/handcuffs{ + pixel_x = -17; + pixel_y = 9 + }, +/obj/item/restraints/handcuffs{ + pixel_x = -17; + pixel_y = -3 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"u" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 5 + }, +/obj/structure/closet/secure_closet/brig/holodeck{ + id = "Holodeck Cell 1" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"v" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/structure/closet/secure_closet/brig/holodeck{ + id = "Holodeck Cell 2" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"x" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 5 + }, +/obj/structure/bed, +/obj/item/bedsheet/red, +/turf/open/floor/holofloor/white, +/area/template_noop) +"y" = ( +/obj/structure/window/reinforced/fulltile, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"z" = ( +/obj/machinery/computer/records/security{ + dir = 8 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"A" = ( +/obj/effect/turf_decal/trimline/red/filled/warning{ + dir = 1 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"B" = ( +/obj/structure/closet{ + name = "evidence closet" + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"C" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 6 + }, +/obj/item/coin/antagtoken, +/obj/machinery/door/window/brigdoor/security/holodeck/left/directional/south{ + id = "Holodeck Cell 1"; + name = "Cell 1" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"D" = ( +/obj/machinery/status_display/door_timer{ + id = "Holodeck Cell 1"; + name = "Cell 1"; + req_access = null + }, +/obj/structure/table, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"G" = ( +/obj/effect/turf_decal/trimline/red/filled/corner{ + dir = 4 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"H" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 6 + }, +/obj/machinery/flasher/directional/west{ + id = "Holodeck Cell 2"; + pixel_x = 1 + }, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/holofloor/white, +/area/template_noop) +"I" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 10 + }, +/obj/machinery/flasher/directional/east{ + id = "Holodeck Cell 1"; + pixel_x = 0 + }, +/obj/structure/window/reinforced/spawner/directional/south, +/turf/open/floor/holofloor/white, +/area/template_noop) +"J" = ( +/obj/effect/turf_decal/trimline/red/filled/warning, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"K" = ( +/obj/effect/turf_decal/trimline/red/filled/line, +/turf/open/floor/holofloor, +/area/template_noop) +"L" = ( +/obj/effect/turf_decal/trimline/red/filled/corner{ + dir = 8 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"M" = ( +/obj/effect/turf_decal/trimline/red/filled/corner{ + dir = 1 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"N" = ( +/obj/machinery/status_display/door_timer{ + id = "Holodeck Cell 4"; + req_access = null; + name = "Cell 4" + }, +/obj/structure/table, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"O" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 5 + }, +/obj/machinery/flasher/directional/west{ + id = "Holodeck Cell 4"; + pixel_x = 0 + }, +/obj/structure/window/reinforced/spawner/directional/north, +/turf/open/floor/holofloor/white, +/area/template_noop) +"P" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 9 + }, +/obj/item/dice/d6, +/obj/machinery/door/window/brigdoor/security/holodeck/right/directional/north{ + name = "Cell 4"; + id = "Holodeck Cell 4" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"Q" = ( +/obj/structure/table, +/obj/machinery/button/flasher{ + id = "Holodeck Cell 3"; + name = "Cell 3"; + pixel_y = -3 + }, +/obj/machinery/button/flasher{ + id = "Holodeck Cell 1"; + name = "Cell 1"; + pixel_y = 8 + }, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"R" = ( +/obj/effect/turf_decal/board_number/three, +/turf/open/floor/holofloor, +/area/template_noop) +"S" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 4 + }, +/turf/open/floor/holofloor, +/area/template_noop) +"T" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 6 + }, +/obj/structure/bed, +/obj/item/bedsheet/red, +/turf/open/floor/holofloor/white, +/area/template_noop) +"U" = ( +/obj/machinery/status_display/door_timer{ + id = "Holodeck Cell 3"; + req_access = null; + name = "Cell 3" + }, +/obj/structure/table, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"V" = ( +/obj/effect/turf_decal/trimline/red/filled/warning{ + dir = 1 + }, +/obj/effect/turf_decal/caution/stand_clear, +/turf/open/floor/holofloor/dark, +/area/template_noop) +"W" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 10 + }, +/obj/item/toy/figure/prisoner, +/obj/machinery/door/window/brigdoor/security/holodeck/right/directional/south{ + name = "Cell 2"; + id = "Holodeck Cell 2" + }, +/turf/open/floor/holofloor/white, +/area/template_noop) +"X" = ( +/obj/effect/turf_decal/trimline/red/filled/corner, +/turf/open/floor/holofloor, +/area/template_noop) +"Y" = ( +/obj/effect/turf_decal/trimline/red/filled/line{ + dir = 10 + }, +/obj/structure/bed, +/obj/item/bedsheet/red, +/turf/open/floor/holofloor/white, +/area/template_noop) +"Z" = ( +/obj/structure/chair/comfy/black, +/turf/open/floor/holofloor/dark, +/area/template_noop) + +(1,1,1) = {" +j +I +s +s +s +s +s +s +f +Y +"} +(2,1,1) = {" +u +C +q +X +S +S +G +R +p +r +"} +(3,1,1) = {" +y +y +s +K +D +U +b +s +y +y +"} +(4,1,1) = {" +B +J +s +K +h +Q +b +s +A +c +"} +(5,1,1) = {" +B +J +s +K +Z +t +b +s +V +k +"} +(6,1,1) = {" +B +J +s +K +z +g +b +s +A +c +"} +(7,1,1) = {" +y +y +s +K +l +N +b +s +y +y +"} +(8,1,1) = {" +v +W +e +L +d +d +M +o +P +n +"} +(9,1,1) = {" +x +H +s +s +s +s +s +s +O +T +"} diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm index ee4158538b3..01ec6e7b66c 100644 --- a/code/game/machinery/doors/windowdoor.dm +++ b/code/game/machinery/doors/windowdoor.dm @@ -535,6 +535,18 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holding icon_state = "rightsecure" base_state = "rightsecure" +/obj/machinery/door/window/brigdoor/security/holodeck + name = "cell door" + desc = "For keeping in criminal scum." + req_one_access = COMMON_ACCESS + +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holodeck/left, 0) +MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/door/window/brigdoor/security/holodeck/right, 0) + +/obj/machinery/door/window/brigdoor/security/holodeck/right + icon_state = "rightsecure" + base_state = "rightsecure" + /* * Subtype used in unit tests to ensure instant windoor open/close */ diff --git a/code/game/objects/structures/crates_lockers/closets/secure/security.dm b/code/game/objects/structures/crates_lockers/closets/secure/security.dm index d17dd0665ef..56c61bb39c5 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm @@ -189,6 +189,9 @@ req_one_access = list(ACCESS_BRIG) var/id = null +/obj/structure/closet/secure_closet/brig/holodeck + req_one_access = COMMON_ACCESS + /obj/structure/closet/secure_closet/brig/genpop name = "genpop storage locker" desc = "Used for storing the belongings of genpop's tourists visiting the locals." diff --git a/code/game/objects/structures/electricchair.dm b/code/game/objects/structures/electricchair.dm index d68457f9bae..ffe4252f6ef 100644 --- a/code/game/objects/structures/electricchair.dm +++ b/code/game/objects/structures/electricchair.dm @@ -8,10 +8,14 @@ /obj/structure/chair/e_chair/Initialize(mapload) . = ..() - var/obj/item/assembly/shock_kit/stored_kit = new(contents) var/mutable_appearance/export_to_component = mutable_appearance('icons/obj/chairs.dmi', "echair_over", OBJ_LAYER, src, appearance_flags = KEEP_APART) export_to_component = color_atom_overlay(export_to_component) - AddComponent(/datum/component/electrified_buckle, (SHOCK_REQUIREMENT_ITEM | SHOCK_REQUIREMENT_LIVE_CABLE | SHOCK_REQUIREMENT_SIGNAL_RECEIVED_TOGGLE), stored_kit, list(export_to_component)) + + AddComponent(\ + /datum/component/electrified_buckle,\ + overlays_to_add = list(export_to_component),\ + shock_flags = (SHOCK_NOGLOVES)\ + ) /obj/structure/chair/e_chair/attackby(obj/item/W, mob/user, list/modifiers, list/attack_modifiers) if(W.tool_behaviour == TOOL_WRENCH) diff --git a/code/modules/holodeck/holodeck_map_templates.dm b/code/modules/holodeck/holodeck_map_templates.dm index 3e79de6ea43..06cb3004ca1 100644 --- a/code/modules/holodeck/holodeck_map_templates.dm +++ b/code/modules/holodeck/holodeck_map_templates.dm @@ -157,3 +157,9 @@ template_id = "holodeck_refuelingstation" mappath = "_maps/templates/holodeck_refuelingstation.dmm" restricted = TRUE + +/datum/map_template/holodeck/prison + name = "Holodeck - Prison Block" + template_id = "holodeck_prison" + mappath = "_maps/templates/holodeck_prison.dmm" + restricted = TRUE