diff --git a/_maps/virtual_domains/README.md b/_maps/virtual_domains/README.md
index 6e9abc655682..f0a8a1ebfd21 100644
--- a/_maps/virtual_domains/README.md
+++ b/_maps/virtual_domains/README.md
@@ -1,11 +1,12 @@
# Making new virtual domains
## REQUIRED:
-1. One way that the encrypted cache can spawn. This can be from a mob drop, a landmark (place a few, it'll pick one), or a signable landmark if you have a points system.
+1. One way that the encrypted cache can spawn. This can be from a mob drop, a landmark (place a few, it'll pick one), or a signal landmark if you have a points system.
2. Place a virtual domain baseturf helper in each area.
3. If you're using modular safehouses, ensure that the map has ONE tile marked with the safehouse modular map loader (and set the KEY). it will need an open 7x6 area.
4. Placing a safehouse area is redundant, but it will ensure there is power in the starting safehouse.
5. Create the dm file that defines the map qualities. You can use the existing ones as a template.
+6. Place a virtual domain baseturf helper in each area.
## Converting an existing map
1. Create a new map using the existing map's size - give yourself enough room to enclose it with a binary wall. There's no need for any space outside of it, so ensure that it fits and is enclosed, nothing outside of this.
@@ -18,7 +19,7 @@ You shouldn't need to fully enclose your map in 15 tiles of binary filler. Using
For areas, ideally just one on the map and one for the safehouse. Vdoms should never last so long as to need individual area power and atmos unless you're specifically going for a gimmick.
-Use modular mob segments! Use modular map segments! Add some variety to your maps! Just make sure you've set your map to have "is_modular" afterwards.
+Make it modular: Add modular map and mob segments! It adds variety. Just make sure you've set your map to have "is_modular" afterwards.
Adding some open tile padding around the safehouse is a good touch. About 7 tiles West/East for the visual effect of a larger map.
diff --git a/_maps/virtual_domains/beach_bar.dmm b/_maps/virtual_domains/beach_bar.dmm
index 49ff295a0739..cc7b93806d99 100644
--- a/_maps/virtual_domains/beach_bar.dmm
+++ b/_maps/virtual_domains/beach_bar.dmm
@@ -688,7 +688,7 @@
/area/virtual_domain/fullbright)
"CA" = (
/obj/structure/window/reinforced/spawner/directional/east,
-/obj/effect/mob_spawn/ghost_role/human/beach/lifeguard,
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/lifeguard,
/turf/open/floor/wood,
/area/virtual_domain/fullbright)
"CO" = (
@@ -917,7 +917,7 @@
/turf/open/floor/light/colour_cycle/dancefloor_a,
/area/virtual_domain/fullbright)
"OE" = (
-/obj/effect/mob_spawn/ghost_role/human/beach{
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach{
dir = 4
},
/turf/open/floor/wood,
@@ -948,7 +948,7 @@
/area/virtual_domain/fullbright)
"Pg" = (
/obj/structure/sign/poster/official/high_class_martini/directional/west,
-/obj/effect/mob_spawn/ghost_role/human/bartender{
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/bartender{
dir = 4
},
/turf/open/floor/wood,
diff --git a/_maps/virtual_domains/fredingtonfastingbear.dmm b/_maps/virtual_domains/fredingtonfastingbear.dmm
index a9118edf7348..25b8e273a79f 100644
--- a/_maps/virtual_domains/fredingtonfastingbear.dmm
+++ b/_maps/virtual_domains/fredingtonfastingbear.dmm
@@ -1,11 +1,11 @@
//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
"aV" = (
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"bu" = (
/obj/machinery/oven/range,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"bL" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -14,7 +14,7 @@
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/greenglow,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"bP" = (
/obj/structure/sign/poster/official/report_crimes,
/turf/closed/indestructible/reinforced,
@@ -23,7 +23,7 @@
/obj/machinery/chem_dispenser/drinks/beer,
/obj/structure/table/wood,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"bW" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -32,7 +32,7 @@
pixel_y = 6
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"cn" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -41,40 +41,41 @@
pixel_y = 2
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"cp" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/mob/living/basic/bear/snow,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"cY" = (
/obj/structure/sign/poster/official/no_erp/directional/north,
/obj/structure/sign/poster/official/no_erp/directional/north,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"dl" = (
/obj/structure/sign/poster/contraband/blood_geometer/directional/south,
/obj/effect/landmark/bitrunning/cache_spawn,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"dz" = (
/obj/structure/table/wood,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"dN" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/blood/xtracks,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"dV" = (
/obj/structure/table/glass,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ex" = (
-/turf/closed/indestructible/binary,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/obj/structure/sign/poster/contraband/bountyhunters/directional/south,
+/turf/template_noop,
+/area/virtual_domain)
"eE" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -83,28 +84,28 @@
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"eW" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"fd" = (
/obj/structure/table/wood/poker,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"fo" = (
/obj/structure/table/wood,
/obj/item/reagent_containers/cup/glass/shaker{
pixel_x = 5
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"fy" = (
/obj/machinery/stove,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"fz" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -114,15 +115,15 @@
pixel_y = 6
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"fU" = (
/obj/effect/decal/cleanable/blood/footprints,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"gl" = (
/obj/structure/sign/poster/contraband/blasto_detergent,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"gL" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -132,7 +133,7 @@
},
/obj/machinery/light/built/directional/east,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"hq" = (
/obj/structure/table/reinforced,
/obj/item/flashlight/seclite{
@@ -147,11 +148,11 @@
"hI" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"hK" = (
/obj/item/trash/popcorn,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"hR" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -160,7 +161,7 @@
/obj/effect/decal/cleanable/confetti,
/obj/effect/decal/cleanable/insectguts,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"jE" = (
/obj/structure/sign/poster/abductor/ayy_over_tizira,
/obj/structure/sign/poster/official/the_owl,
@@ -174,71 +175,71 @@
dir = 4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"kf" = (
/obj/structure/chair/stool/bar/directional/east,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"km" = (
/obj/structure/chair/sofa/corp/left{
dir = 1
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"kL" = (
/obj/machinery/light/built/directional/west,
/obj/item/light/tube/broken,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"lc" = (
/obj/machinery/vending/boozeomat,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"lL" = (
/obj/structure/table,
/obj/item/kitchen/rollingpin/illegal,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"lP" = (
/obj/machinery/vending/sovietsoda,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"lS" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/cobweb/cobweb2,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ma" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/structure/table,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ms" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/blood/tracks,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"mC" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/structure/table,
/obj/item/food/pizza,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"mX" = (
/obj/machinery/computer/arcade/amputation{
dir = 1
},
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ng" = (
/obj/effect/decal/cleanable/blood/drip,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"nF" = (
/obj/effect/spawner/structure/window/reinforced/indestructible,
/turf/open/floor/iron,
@@ -251,11 +252,11 @@
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/item/clothing/mask/animal/small/bear/cursed,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"nX" = (
/obj/structure/chair/sofa/corp/left,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ob" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -263,12 +264,12 @@
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/greenglow,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"of" = (
/obj/structure/railing,
/obj/effect/decal/cleanable/fuel_pool/hivis,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"oO" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -276,23 +277,23 @@
dir = 4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"pr" = (
/obj/machinery/light/built/directional/east,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"pK" = (
/obj/effect/decal/cleanable/blood/tracks{
dir = 4
},
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"pX" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/item/restraints/legcuffs/beartrap/prearmed,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ql" = (
/obj/structure/table/reinforced,
/obj/item/toy/plush/nukeplushie{
@@ -307,20 +308,20 @@
/area/virtual_domain/protected_space/fullbright)
"qK" = (
/turf/closed/indestructible/fakedoor,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"rc" = (
/obj/structure/chair/comfy/black{
dir = 8
},
/obj/effect/decal/cleanable/blood/splatter,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"re" = (
/obj/structure/chair/comfy/black{
dir = 8
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ri" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -329,14 +330,14 @@
},
/obj/effect/decal/cleanable/blood/tracks,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"rB" = (
/obj/item/trash/boritos/green{
pixel_x = 4;
pixel_y = 11
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"rD" = (
/obj/machinery/door/poddoor{
id = "door2"
@@ -350,21 +351,20 @@
dir = 4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"sg" = (
-/obj/structure/sign/poster/contraband/bountyhunters/directional/south,
-/turf/closed/indestructible/binary,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/turf/template_noop,
+/area/virtual_domain)
"si" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/structure/table,
/obj/item/balloon_mallet,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"sk" = (
/obj/machinery/computer/slot_machine,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"sl" = (
/obj/effect/spawner/structure/window/reinforced/indestructible,
/obj/structure/sign/poster/contraband/space_cola/directional/north,
@@ -375,28 +375,28 @@
dir = 1
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"td" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/decal/chempuff,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"to" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"tC" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/structure/table,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"tI" = (
/obj/item/trash/can,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"tN" = (
/obj/effect/baseturf_helper/virtual_domain,
/turf/template_noop,
@@ -405,7 +405,7 @@
/obj/structure/table/wood/poker,
/obj/item/trash/ready_donk,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ud" = (
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/cafeteria,
@@ -415,40 +415,40 @@
dir = 1
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"uZ" = (
/obj/effect/decal/cleanable/food/salt,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ve" = (
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vk" = (
/obj/structure/railing,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vm" = (
/obj/effect/landmark/bitrunning/cache_spawn,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vs" = (
/obj/structure/closet/secure_closet/freezer/cream_pie,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vw" = (
/mob/living/basic/bear/butter,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vy" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/decal/cleanable/blood/gibs/down,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vz" = (
/obj/effect/spawner/structure/window/reinforced/plasma,
/turf/open/floor/iron,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vF" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -458,18 +458,18 @@
id = "door2"
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vG" = (
/obj/structure/closet/secure_closet/freezer/kitchen,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vR" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/structure/table,
/obj/item/trash/tray,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"vT" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -478,7 +478,7 @@
},
/obj/effect/decal/cleanable/insectguts,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"wM" = (
/obj/item/toy/balloon/heart,
/obj/machinery/light/built/directional/west,
@@ -486,47 +486,47 @@
dir = 1
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"xa" = (
/obj/structure/railing,
/obj/structure/curtain/cloth/fancy/mechanical/start_closed,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"xk" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/structure/table,
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"xv" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/structure/sign/poster/official/moth_hardhat/directional/west,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"xY" = (
/obj/effect/decal/cleanable/insectguts,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"yz" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"yB" = (
/obj/structure/railing,
/obj/effect/decal/cleanable/blood/tracks,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"zU" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ag" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -534,7 +534,11 @@
dir = 4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
+"Ak" = (
+/obj/effect/landmark/bitrunning/cache_spawn,
+/turf/open/floor/iron/kitchen,
+/area/virtual_domain)
"AF" = (
/obj/structure/table/wood,
/obj/item/reagent_containers/cup/glass/bottle/goldschlager{
@@ -545,23 +549,23 @@
pixel_x = -4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Bc" = (
/turf/template_noop,
/area/virtual_domain/safehouse)
"Bf" = (
/obj/effect/spawner/random/trash/graffiti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Bj" = (
/obj/machinery/computer/arcade/amputation,
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Bo" = (
/obj/machinery/door/airlock,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"BU" = (
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/iron/cafeteria,
@@ -574,16 +578,16 @@
},
/obj/effect/decal/cleanable/blood/gibs/up,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Cm" = (
/turf/template_noop,
-/area/space)
+/area/template_noop)
"Ct" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/machinery/light/built/directional/east,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Dx" = (
/obj/effect/decal/cleanable/fuel_pool,
/obj/effect/decal/cleanable/confetti,
@@ -592,7 +596,7 @@
"Dz" = (
/mob/living/basic/bear/fightpit,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"DV" = (
/obj/machinery/door,
/turf/open/floor/iron/cafeteria,
@@ -605,14 +609,14 @@
},
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"EP" = (
/obj/structure/railing{
dir = 4
},
/obj/effect/decal/cleanable/leaper_sludge,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Fc" = (
/turf/closed/indestructible/reinforced,
/area/virtual_domain/protected_space/fullbright)
@@ -621,28 +625,28 @@
/obj/machinery/light/built/directional/west,
/obj/structure/fake_stairs/wood,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"FA" = (
/obj/effect/decal/cleanable/food/flour,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Gb" = (
/obj/item/trash/peanuts,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Gn" = (
/obj/machinery/light/built/directional/east,
/obj/effect/decal/cleanable/food/tomato_smudge,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"GD" = (
/obj/effect/decal/cleanable/blood,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"GK" = (
/obj/structure/closet/crate/trashcart/filled,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Hi" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -650,12 +654,12 @@
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ho" = (
/obj/effect/decal/cleanable/fuel_pool/hivis,
/mob/living/basic/bear/fightpit,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"HE" = (
/obj/structure/table/reinforced,
/obj/item/gun/energy/laser{
@@ -680,11 +684,11 @@
"HG" = (
/obj/structure/curtain/cloth/fancy/mechanical,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"If" = (
/mob/living/basic/bear/russian,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Io" = (
/obj/structure/closet/crate/trashcart/filled,
/turf/open/misc/dirt/jungle,
@@ -692,12 +696,12 @@
"IX" = (
/obj/machinery/computer/arcade/amputation,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"IY" = (
/obj/structure/table/wood/poker,
/obj/item/toy/cards/deck/syndicate,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Jh" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -707,13 +711,13 @@
pixel_y = 8
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"JD" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/decal/cleanable/blood/tracks,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"JF" = (
/obj/modular_map_root/safehouse{
key = "wood"
@@ -730,11 +734,11 @@
},
/obj/item/trash/pistachios,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"KJ" = (
/mob/living/basic/bear/fightpit,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ln" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -743,11 +747,11 @@
},
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"LP" = (
/obj/item/trash/shrimp_chips,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"LU" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
@@ -757,7 +761,7 @@
id = "door1"
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Mc" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -769,24 +773,24 @@
dir = 8
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Mm" = (
/obj/structure/chair/stool/bar/directional/north,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Mq" = (
/obj/structure/sign/poster/contraband/ambrosia_vulgaris/directional/west,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ML" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"MO" = (
/obj/effect/decal/cleanable/cobweb,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"MS" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -795,84 +799,84 @@
pixel_y = 2
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ne" = (
/turf/closed/indestructible/binary,
-/area/space)
+/area/virtual_domain/fullbright)
"Nz" = (
/obj/structure/sign/poster/official/pda_ad/directional/north,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"NA" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"NE" = (
/obj/structure/sign/poster/abductor/ayy_cops/directional/north,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Od" = (
/obj/structure/table/wood/poker,
/obj/item/toy/cards/deck,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ox" = (
/obj/structure/sign/poster/official/the_owl,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"OB" = (
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"OD" = (
/mob/living/basic/bear/russian,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"OM" = (
/obj/structure/table,
/obj/effect/decal/cleanable/food/salt,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Pm" = (
/obj/structure/chair/sofa/corp/right,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"PK" = (
/obj/structure/curtain/cloth/fancy/mechanical,
/obj/effect/decal/cleanable/blood/tracks,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Qg" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/item/toy/balloon/heart,
/obj/machinery/light/built/directional/west,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"RB" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/machinery/light/built/directional/west,
/obj/effect/decal/cleanable/glass/plastitanium,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Sp" = (
/obj/structure/chair/sofa/corp,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Sr" = (
/obj/effect/decal/cleanable/blood/footprints{
dir = 4
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"SE" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/machinery/light/built/directional/east,
/obj/effect/decal/cleanable/glass/plastitanium,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"SW" = (
/obj/machinery/door/poddoor{
id = "door1"
@@ -886,11 +890,11 @@
pixel_y = 6
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Tp" = (
/obj/structure/sign/poster/official/soft_cap_pop_art,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Tq" = (
/turf/open/misc/dirt/jungle,
/area/virtual_domain/fullbright)
@@ -902,34 +906,34 @@
},
/obj/effect/decal/cleanable/insectguts,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"TR" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/decal/cleanable/ants/fire,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"TW" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/mob/living/basic/bear/snow,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Uj" = (
/obj/structure/curtain/bounty/start_closed,
/turf/closed/indestructible/binary,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain/fullbright)
"Ux" = (
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"UR" = (
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"UW" = (
/obj/structure/sign/poster/official/no_erp/directional/north,
/turf/closed/indestructible/reinforced,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Vd" = (
/turf/open/floor/iron/cafeteria,
/area/virtual_domain/protected_space/fullbright)
@@ -937,14 +941,14 @@
/obj/structure/table,
/obj/item/kitchen/tongs,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Vs" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/decal/cleanable/blood/gibs/old,
/obj/machinery/light/built/directional/west,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"VS" = (
/obj/structure/table/reinforced,
/obj/machinery/computer/camera_advanced,
@@ -953,7 +957,7 @@
"VW" = (
/obj/structure/reagent_dispensers/water_cooler,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Wj" = (
/obj/structure/sign/poster/contraband/free_key/directional,
/turf/closed/indestructible/reinforced,
@@ -961,7 +965,7 @@
"Wy" = (
/obj/effect/decal/cleanable/molten_object/large,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"WG" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -970,11 +974,11 @@
},
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"XG" = (
/obj/machinery/roulette,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Yd" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
@@ -982,26 +986,26 @@
dir = 8
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Ye" = (
/obj/structure/table/glass,
/obj/item/reagent_containers/cup/soda_cans/grey_bull,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Yy" = (
/obj/machinery/computer/arcade/amputation{
dir = 1
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"YK" = (
/obj/effect/spawner/random/trash,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"YL" = (
/obj/item/trash/raisins,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"YT" = (
/obj/machinery/button/door/directional/west{
id = "door1"
@@ -1011,30 +1015,30 @@
"Zf" = (
/obj/machinery/deepfryer,
/turf/open/floor/iron/kitchen/small,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Zj" = (
/mob/living/basic/bear/fightpit,
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"Zp" = (
/obj/structure/chair/comfy/black{
dir = 8
},
/obj/effect/decal/cleanable/blood/old,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ZL" = (
/obj/structure/railing{
dir = 4
},
/turf/open/floor/wood,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ZU" = (
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/turf_decal/tile/blue/opposingcorners,
/obj/effect/decal/cleanable/confetti,
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
"ZZ" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
@@ -1042,7 +1046,7 @@
dir = 8
},
/turf/open/floor/iron/kitchen,
-/area/ruin/space/has_grav/powered/virtual_domain)
+/area/virtual_domain)
(1,1,1) = {"
Cm
@@ -1090,9 +1094,6 @@ Cm
Cm
Cm
Cm
-Cm
-Cm
-Cm
"}
(2,1,1) = {"
Cm
@@ -1110,6 +1111,13 @@ Cm
Cm
Cm
Cm
+Uj
+Uj
+Uj
+Uj
+Uj
+Uj
+Uj
Cm
Cm
Cm
@@ -1133,6 +1141,8 @@ Cm
Cm
Cm
Cm
+"}
+(3,1,1) = {"
Cm
Cm
Cm
@@ -1143,13 +1153,18 @@ Cm
Cm
Cm
Cm
-"}
-(3,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+Uj
+MO
+OB
+OB
+OB
+OB
+Uj
Cm
Cm
Cm
@@ -1173,6 +1188,8 @@ Cm
Cm
Cm
Cm
+"}
+(4,1,1) = {"
Cm
Cm
Cm
@@ -1188,13 +1205,18 @@ Cm
Cm
Cm
Cm
+Uj
+OB
+OB
+OB
+OB
+Zj
+Uj
Cm
Cm
Cm
Cm
Cm
-"}
-(4,1,1) = {"
Cm
Cm
Cm
@@ -1213,12 +1235,10 @@ Cm
Cm
Cm
Cm
+"}
+(5,1,1) = {"
Cm
Cm
-Ne
-Ne
-Ne
-Ne
Cm
Cm
Cm
@@ -1232,6 +1252,13 @@ Cm
Cm
Cm
Cm
+Uj
+vm
+OB
+OB
+OB
+vm
+Uj
Cm
Cm
Cm
@@ -1243,8 +1270,6 @@ Cm
Cm
Cm
Cm
-"}
-(5,1,1) = {"
Cm
Cm
Cm
@@ -1257,19 +1282,30 @@ Cm
Cm
Cm
Cm
+"}
+(6,1,1) = {"
Cm
Cm
Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
+Cm
+Cm
+ve
+ve
+ve
+ve
+ve
+ve
+Ox
+ve
+ve
+ve
+ve
+ve
+OB
+OB
+OB
+ve
+ve
Cm
Cm
Cm
@@ -1294,12 +1330,29 @@ Cm
Cm
Cm
"}
-(6,1,1) = {"
+(7,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+sk
+Ux
+Ux
+kL
+Ux
+Ux
+UR
+Ux
+Ux
+Ux
+Fy
+EP
+ZL
+ZL
+wM
+ve
Cm
Cm
Cm
@@ -1310,16 +1363,6 @@ Cm
Cm
Cm
Cm
-Ne
-Uj
-Uj
-Uj
-Uj
-Uj
-Uj
-Uj
-Ne
-Ne
Cm
Cm
Cm
@@ -1333,18 +1376,41 @@ Cm
Cm
Cm
Cm
+"}
+(8,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+GK
+Gb
+Ux
+IX
+rB
+YL
+mX
+UR
+Ux
+Ux
+Ux
+UR
+UR
+Ux
+Ux
+ve
Cm
Cm
+ve
+ve
+ve
+ve
+ve
+ve
Cm
Cm
Cm
-"}
-(7,1,1) = {"
Cm
Cm
Cm
@@ -1357,23 +1423,38 @@ Cm
Cm
Cm
Cm
+"}
+(9,1,1) = {"
Cm
Cm
-Ne
-Ne
-Uj
-MO
-OB
-OB
-OB
-OB
-Uj
-Ne
Cm
Cm
Cm
+gl
+GK
+Ux
+Ux
+Bj
+Ux
+Ux
+Yy
+Bf
+Ux
+Ux
+Ux
+Zp
+rc
+re
+Ux
+ve
Cm
Cm
+ve
+Ux
+Ux
+Ux
+Ux
+ve
Cm
Cm
Cm
@@ -1389,15 +1470,38 @@ Cm
Cm
Cm
Cm
+"}
+(10,1,1) = {"
Cm
Cm
Cm
Cm
-"}
-(8,1,1) = {"
Cm
+ve
+GK
+Ux
+Ux
+Bj
+UR
+Ux
+Yy
+Ux
+Ux
+Ux
+Ux
+Ke
+re
+re
+Ux
+Tp
Cm
Cm
+ve
+Ux
+vw
+Ux
+Ux
+ve
Cm
Cm
Cm
@@ -1409,29 +1513,42 @@ Cm
Cm
Cm
Cm
-Ne
-Ne
-Uj
-OB
-OB
-OB
-OB
-Zj
-Uj
-Ne
-Ne
-Ne
Cm
Cm
Cm
Cm
+"}
+(11,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+sk
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+re
+re
+re
+Ux
+ve
Cm
Cm
+ve
+Ux
+Ux
+Ux
+Ux
+ve
Cm
Cm
Cm
@@ -1443,98 +1560,49 @@ Cm
Cm
Cm
Cm
-"}
-(9,1,1) = {"
Cm
Cm
Cm
Cm
+"}
+(12,1,1) = {"
Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
Uj
-vm
-OB
-OB
-OB
-vm
Uj
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(10,1,1) = {"
-Cm
-Cm
-Cm
-Cm
-Cm
-Ne
+Uj
+Uj
ve
ve
ve
ve
+Ux
+Ux
+Ux
+Wy
ve
ve
-Ox
+NE
+Ux
+Ux
+Ux
+Ux
+Ho
ve
ve
ve
ve
ve
-OB
-OB
-OB
ve
ve
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
+ve
+ve
+ve
+UW
+UW
+cY
+UW
+ve
+ve
Cm
Cm
Cm
@@ -1544,29 +1612,43 @@ Cm
Cm
Cm
"}
-(11,1,1) = {"
-Cm
-Cm
-Cm
-Cm
+(13,1,1) = {"
Cm
-Ne
+Uj
+OB
+OB
+dl
+hI
+to
+Vs
+dN
+vT
+oO
+ML
+EO
+WG
+Qg
ve
-sk
-Ux
-Ux
-kL
-Ux
-Ux
-UR
Ux
+xY
Ux
Ux
-Fy
-EP
-ZL
-ZL
-wM
+NA
+NA
+NA
+NA
+RB
+NA
+NA
+zU
+NA
+NA
+NA
+yz
+yz
+yz
+yz
+nP
ve
Ne
Ne
@@ -1576,1092 +1658,373 @@ Ne
Ne
Ne
Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
"}
-(12,1,1) = {"
-Cm
-Cm
-Cm
-Cm
+(14,1,1) = {"
Cm
-Ne
+Uj
+OB
+OB
+OB
+xa
+jZ
+to
+eW
+bW
+ma
+to
+hR
+tC
+MS
ve
-GK
-Gb
-Ux
-IX
-rB
-YL
-mX
-UR
Ux
+XG
+XG
Ux
+NA
+pX
+NA
+NA
+NA
+NA
+NA
+NA
+NA
+NA
+td
+yz
+LU
+yz
+ob
+bL
+ve
+Ne
+Bc
+Bc
+Bc
+Bc
+Bc
+JF
+Ne
+"}
+(15,1,1) = {"
+Cm
+Uj
+OB
+OB
+OB
+HG
+of
+ML
+ZU
+mC
+vR
+ML
+tC
+Jh
+to
Ux
-UR
-UR
Ux
+Od
+tZ
Ux
+TR
+ve
+ve
+ve
ve
-Ne
-Ne
ve
ve
ve
+Fc
+Fc
+sl
+SW
+Fc
+Wj
+Fc
ve
ve
ve
+Bc
+Bc
+Bc
+Bc
+Bc
+Bc
Ne
+"}
+(16,1,1) = {"
Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(13,1,1) = {"
-Cm
-Cm
-Cm
-Cm
-Cm
-Ne
-gl
-GK
-Ux
-Ux
-Bj
-Ux
-Ux
-Yy
-Bf
-Ux
-Ux
-Ux
-Zp
-rc
-re
-Ux
-ve
-Ne
-Ne
-ve
-Ux
-Ux
-Ux
-Ux
-ve
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(14,1,1) = {"
-Cm
-Cm
-Cm
-Ne
-Ne
-Ne
-ve
-GK
-Ux
-Ux
-Bj
-UR
-Ux
-Yy
-Ux
-Ux
-Ux
-Ux
-Ke
-re
-re
-Ux
-Tp
-Ne
-Ne
-ve
-Ux
-vw
-Ux
-Ux
-ve
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(15,1,1) = {"
-Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-ve
-sk
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-re
-re
-re
-Ux
-ve
-Ne
-Ne
-ve
-Ux
-Ux
-Ux
-Ux
-ve
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(16,1,1) = {"
-Cm
-Ne
-Uj
-Uj
-Uj
-Uj
-ve
-ve
-ve
-ve
-Ux
-Ux
-Ux
-Wy
-ve
-ve
-NE
-Ux
-Ux
-Ux
-Ux
-Ho
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-UW
-UW
-cY
-UW
-ve
-ve
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Ne
-Ne
-Cm
-Cm
-"}
-(17,1,1) = {"
-Cm
-Ne
Uj
OB
OB
-dl
-hI
+OB
+HG
+vk
to
-Vs
-dN
-vT
-oO
ML
-EO
-WG
-Qg
-ve
+Ln
+ZZ
+to
+ZZ
+Yd
+eW
Ux
-xY
+hK
+fd
Ux
Ux
NA
-NA
-NA
-NA
-RB
-NA
-NA
-zU
-NA
-NA
-NA
-yz
-yz
-yz
-yz
-nP
+vz
+tI
+VW
ve
+sg
+sg
+sg
+Fc
+hq
+ud
+Dx
+YT
+Vd
+Fc
+Tq
+Tq
+Tq
+Bc
+Bc
+Bc
+Bc
+Bc
+Bc
Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Cm
-"}
-(18,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-OB
-xa
-jZ
-to
-eW
-bW
-ma
-to
-hR
-tC
-MS
-ve
-Ux
-XG
-XG
-Ux
-NA
-pX
-NA
-NA
-NA
-NA
-NA
-NA
-NA
-NA
-td
-yz
-LU
-yz
-ob
-bL
-ve
-Ne
-Bc
-Bc
-Bc
-Bc
-Bc
-JF
-Ne
-Cm
-Cm
-"}
-(19,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-OB
-HG
-of
-ML
-ZU
-mC
-vR
-ML
-tC
-Jh
-to
-Ux
-Ux
-Od
-tZ
-Ux
-TR
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-Fc
-Fc
-sl
-SW
-Fc
-Wj
-Fc
-ve
-ve
-ve
-Bc
-Bc
-Bc
-Bc
-Bc
-Bc
-Ne
-Cm
-Cm
-"}
-(20,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-OB
-HG
-vk
-to
-ML
-Ln
-ZZ
-to
-ZZ
-Yd
-eW
-Ux
-hK
-fd
-Ux
-Ux
-NA
-vz
-tI
-VW
-ve
-ex
-ex
-ex
-Fc
-hq
-ud
-Dx
-YT
-Vd
-Fc
-Tq
-Tq
-Tq
-Bc
-Bc
-Bc
-Bc
-Bc
-Bc
-Ne
-Cm
-Cm
-"}
-(21,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-OB
-HG
-vk
-ML
-to
-ML
-cn
-ML
-to
-ML
-ZU
-Ux
-Ux
-fd
-Ux
-Ux
-NA
-Ux
-Ux
-lP
-qK
-ex
-ex
-sg
-jE
-VS
-Vd
-Vd
-Vd
-Vd
-DV
-Tq
-Tq
-Tq
-Bc
-Bc
-Bc
-Bc
-Bc
-Bc
-Ne
-Cm
-Cm
-"}
-(22,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-pK
-PK
-yB
-to
-ML
-EO
-Ag
-to
-Ag
-EO
-eW
-Ux
-Ux
-fd
-Ux
-Ux
-NA
-vz
-LP
-lc
-ve
-ex
-ex
-ex
-JW
-ql
-BU
-ud
-HE
-Vd
-Fc
-Io
-Tq
-Tq
-Bc
-Bc
-Bc
-Bc
-Bc
-Bc
-Ne
-Cm
-Cm
-"}
-(23,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-pK
-xa
-Mc
-JD
-ZU
-xk
-tC
-ML
-si
-ma
-ZU
-YK
-Ux
-fd
-IY
-Ux
-NA
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-Fc
-Fc
-nF
-rD
-Fc
-bP
-Fc
-ve
-ve
-ve
-Bc
-Bc
-Bc
-Bc
-Bc
-Bc
-Ne
-Cm
-Cm
-"}
-(24,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-If
-ve
-ML
-rY
-ML
-tC
-Jh
-to
-ma
-fz
-TW
-ve
-Ux
-XG
-XG
-Ux
-NA
-NA
-NA
-NA
-NA
-NA
-NA
-xv
-NA
-NA
-NA
-yz
-vF
-yz
-yz
-Hi
-ve
-Ne
-Bc
-Bc
-Bc
-Bc
-Bc
-tN
-Ne
-Cm
-Cm
-"}
-(25,1,1) = {"
-Cm
-Ne
-Uj
-OB
-OB
-vm
-ve
-lS
-gL
-ms
-ri
-TG
-eW
-Yd
-Ce
-Ct
-ve
-Ux
-Ux
-Ux
-Ux
-cp
-NA
-NA
-NA
-SE
-NA
-NA
-vy
-NA
-NA
-NA
-yz
-yz
-yz
-yz
-eE
-ve
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-"}
-(26,1,1) = {"
-Cm
-Ne
-Uj
-Uj
-Uj
-Uj
-ve
-ve
-ve
-ve
-GD
-Ux
-Ux
-Ux
-ve
-ve
-ve
-Ux
-Ux
-Ux
-Ux
-Ux
-ve
-ve
-ve
-ve
-ve
-ve
-qK
-ve
-ve
-Nz
-ve
-ve
-ve
-ve
-ve
-ve
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Ne
-Cm
-Cm
-Cm
-"}
-(27,1,1) = {"
-Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-ve
-OD
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-ve
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(28,1,1) = {"
-Cm
-Cm
-Ne
-Ne
-Ne
-Ne
-ve
-kf
-kf
-kf
-kf
-kf
-kf
-Ux
-Ux
-Ux
-Ux
-Ux
-Pm
-Ye
-km
-Ux
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(29,1,1) = {"
-Cm
-Cm
-Cm
-Cm
-Ne
-Ne
-ve
-dz
-dz
-dz
-dz
-dz
-dz
-Mm
-Ux
-Ux
-Ux
-Ux
-Sp
-dV
-ur
-Ux
-Bo
-aV
-uZ
-KJ
-Ve
-lL
-ve
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
"}
-(30,1,1) = {"
-Cm
-Cm
-Cm
-Cm
+(17,1,1) = {"
Cm
-Ne
-Mq
-bR
-Ux
-Ux
+Uj
+OB
+OB
+OB
+HG
+vk
+ML
+to
+ML
+cn
+ML
+to
+ML
+ZU
Ux
Ux
-dz
-Mm
+fd
Ux
Ux
+NA
Ux
-Dz
-nX
-Ti
-sR
Ux
-Bo
-aV
-aV
-FA
-aV
-OM
-ve
-Ne
+lP
+qK
+sg
+sg
+ex
+jE
+VS
+Vd
+Vd
+Vd
+Vd
+DV
+Tq
+Tq
+Tq
+Bc
+Bc
+Bc
+Bc
+Bc
+Bc
Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
"}
-(31,1,1) = {"
-Cm
-Cm
-Cm
-Cm
+(18,1,1) = {"
Cm
-Ne
-ve
-lc
-Ux
-fo
-AF
-pr
-dz
-Mm
+Uj
+OB
+OB
+pK
+PK
+yB
+to
+ML
+EO
+Ag
+to
+Ag
+EO
+eW
Ux
Ux
-ng
-fU
-fU
-pr
+fd
Ux
Ux
+NA
+vz
+LP
+lc
ve
-ve
-ve
-vG
-aV
-Zf
-ve
-Ne
+sg
+sg
+sg
+JW
+ql
+BU
+ud
+HE
+Vd
+Fc
+Io
+Tq
+Tq
+Bc
+Bc
+Bc
+Bc
+Bc
+Bc
Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
"}
-(32,1,1) = {"
-Cm
-Cm
-Cm
-Cm
+(19,1,1) = {"
Cm
-Ne
-ve
-ve
-qK
-ve
-ve
+Uj
+OB
+OB
+pK
+xa
+Mc
+JD
+ZU
+xk
+tC
+ML
+si
+ma
+ZU
+YK
+Ux
+fd
+IY
+Ux
+NA
ve
ve
ve
ve
-Ux
-Sr
ve
ve
ve
+Fc
+Fc
+nF
+rD
+Fc
+bP
+Fc
ve
ve
ve
+Bc
+Bc
+Bc
+Bc
+Bc
+Bc
Ne
+"}
+(20,1,1) = {"
+Cm
+Uj
+OB
+OB
+If
ve
-vG
-aV
-fy
+ML
+rY
+ML
+tC
+Jh
+to
+ma
+fz
+TW
+ve
+Ux
+XG
+XG
+Ux
+NA
+NA
+NA
+NA
+NA
+NA
+NA
+xv
+NA
+NA
+NA
+yz
+vF
+yz
+yz
+Hi
ve
Ne
+Bc
+Bc
+Bc
+Bc
+Bc
+tN
Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
"}
-(33,1,1) = {"
-Cm
-Cm
-Cm
+(21,1,1) = {"
Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
+Uj
+OB
+OB
+vm
+ve
+lS
+gL
+ms
+ri
+TG
+eW
+Yd
+Ce
+Ct
ve
Ux
-Sr
+Ux
+Ux
+Ux
+cp
+NA
+NA
+NA
+SE
+NA
+NA
+vy
+NA
+NA
+NA
+yz
+yz
+yz
+yz
+eE
ve
Ne
Ne
@@ -2669,122 +2032,47 @@ Ne
Ne
Ne
Ne
-ve
-vs
-Gn
-bu
-ve
Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
+Ne
"}
-(34,1,1) = {"
-Cm
-Cm
-Cm
+(22,1,1) = {"
Cm
-Ne
-Ne
-ve
-ve
+Uj
+Uj
+Uj
+Uj
ve
ve
ve
ve
+GD
+Ux
+Ux
+Ux
ve
ve
ve
Ux
Ux
+Ux
+Ux
+Ux
ve
ve
ve
ve
ve
ve
-Ne
+qK
ve
ve
+Nz
+ve
ve
ve
ve
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(35,1,1) = {"
-Cm
-Cm
-Cm
-Cm
-Ne
-Ne
ve
-Ux
-Ux
-Ux
-Ux
-Ux
-Dz
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-Ux
ve
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
Cm
Cm
Cm
@@ -2794,14 +2082,18 @@ Cm
Cm
Cm
"}
-(36,1,1) = {"
+(23,1,1) = {"
+Cm
Cm
Cm
Cm
Cm
-Ne
-Ne
ve
+OD
+Ux
+Ux
+Ux
+Ux
Ux
Ux
Ux
@@ -2812,64 +2104,7 @@ Ux
Ux
Ux
Ux
-Ux
-Ux
-Ux
-Ux
-Ux
-ve
-Ne
-Ne
-Ne
-Ne
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-Cm
-"}
-(37,1,1) = {"
-Cm
-Cm
-Cm
-Cm
-Ne
-Ne
-ve
-ve
-ve
-qK
-qK
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-ve
-qK
-qK
-ve
ve
-Ne
-Ne
Cm
Cm
Cm
@@ -2894,36 +2129,35 @@ Cm
Cm
Cm
"}
-(38,1,1) = {"
-Cm
-Cm
-Cm
+(24,1,1) = {"
Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
Cm
Cm
Cm
Cm
+ve
+kf
+kf
+kf
+kf
+kf
+kf
+Ux
+Ux
+Ux
+Ux
+Ux
+Pm
+Ye
+km
+Ux
+ve
+ve
+ve
+ve
+ve
+ve
+ve
Cm
Cm
Cm
@@ -2941,19 +2175,36 @@ Cm
Cm
Cm
Cm
+"}
+(25,1,1) = {"
Cm
Cm
-"}
-(39,1,1) = {"
Cm
Cm
Cm
-Ne
-Ne
-Ne
-Ne
-Ne
-Ne
+ve
+dz
+dz
+dz
+dz
+dz
+dz
+Mm
+Ux
+Ux
+Ux
+Ux
+Sp
+dV
+ur
+Ux
+Bo
+aV
+uZ
+KJ
+Ve
+lL
+ve
Cm
Cm
Cm
@@ -2971,11 +2222,36 @@ Cm
Cm
Cm
Cm
+"}
+(26,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+Mq
+bR
+Ux
+Ux
+Ux
+Ux
+dz
+Mm
+Ux
+Ux
+Ux
+Dz
+nX
+Ti
+sR
+Ux
+Bo
+aV
+aV
+FA
+aV
+OM
+ve
Cm
Cm
Cm
@@ -2994,15 +2270,35 @@ Cm
Cm
Cm
"}
-(40,1,1) = {"
+(27,1,1) = {"
Cm
Cm
Cm
Cm
-Ne
-Ne
-Ne
Cm
+ve
+lc
+Ux
+fo
+AF
+pr
+dz
+Mm
+Ux
+Ux
+ng
+fU
+fU
+pr
+Ux
+Ux
+ve
+ve
+ve
+vG
+aV
+Zf
+ve
Cm
Cm
Cm
@@ -3020,12 +2316,36 @@ Cm
Cm
Cm
Cm
+"}
+(28,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+ve
+qK
+ve
+ve
+ve
+ve
+ve
+ve
+Ux
+Sr
+ve
+ve
+ve
+ve
+ve
+ve
Cm
+ve
+vG
+aV
+fy
+ve
Cm
Cm
Cm
@@ -3044,13 +2364,12 @@ Cm
Cm
Cm
"}
-(41,1,1) = {"
+(29,1,1) = {"
Cm
Cm
Cm
Cm
Cm
-Ne
Cm
Cm
Cm
@@ -3059,12 +2378,21 @@ Cm
Cm
Cm
Cm
+ve
+Ux
+Sr
+ve
Cm
Cm
Cm
Cm
Cm
Cm
+ve
+vs
+Gn
+bu
+ve
Cm
Cm
Cm
@@ -3082,19 +2410,41 @@ Cm
Cm
Cm
Cm
+"}
+(30,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+ve
+ve
+ve
+ve
+ve
+ve
+ve
+ve
+Ux
+Ux
+ve
+ve
+ve
+ve
+ve
+ve
Cm
+ve
+ve
+ve
+ve
+ve
Cm
Cm
Cm
Cm
Cm
-"}
-(42,1,1) = {"
Cm
Cm
Cm
@@ -3107,11 +2457,30 @@ Cm
Cm
Cm
Cm
+"}
+(31,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+Ux
+Ux
+Ux
+Ux
+Ux
+Dz
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+ve
Cm
Cm
Cm
@@ -3135,16 +2504,33 @@ Cm
Cm
Cm
Cm
+"}
+(32,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+Ux
+ve
Cm
Cm
Cm
-"}
-(43,1,1) = {"
Cm
Cm
Cm
@@ -3165,11 +2551,30 @@ Cm
Cm
Cm
Cm
+"}
+(33,1,1) = {"
Cm
Cm
Cm
Cm
Cm
+ve
+ve
+ve
+qK
+qK
+ve
+ve
+ve
+ve
+ve
+ve
+ve
+ve
+qK
+qK
+ve
+ve
Cm
Cm
Cm
diff --git a/_maps/virtual_domains/heretic_hunt.dmm b/_maps/virtual_domains/heretic_hunt.dmm
index e65d42cc1f92..80ef63e4466a 100644
--- a/_maps/virtual_domains/heretic_hunt.dmm
+++ b/_maps/virtual_domains/heretic_hunt.dmm
@@ -77,20 +77,21 @@
},
/turf/template_noop,
/area/virtual_domain/safehouse)
-"eB" = (
-/obj/machinery/defibrillator_mount/directional/west,
-/obj/structure/table/glass,
+"eT" = (
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/closed/indestructible/binary,
+/area/virtual_domain)
+"eV" = (
+/obj/machinery/stasis{
+ dir = 1
+ },
/obj/effect/turf_decal/tile/blue/fourcorners,
-/obj/item/stack/medical/wrap/gauze/improvised,
/obj/effect/turf_decal/siding/blue{
- dir = 4
+ dir = 6
},
+/obj/structure/cable,
/turf/open/floor/plastic,
/area/virtual_domain)
-"eT" = (
-/obj/effect/baseturf_helper/virtual_domain,
-/turf/closed/indestructible/binary,
-/area/virtual_domain)
"fd" = (
/obj/structure/frame/computer{
dir = 1;
@@ -378,6 +379,18 @@
/obj/item/storage/belt/unfathomable_curio,
/turf/open/floor/iron,
/area/virtual_domain)
+"oD" = (
+/mob/living/basic/fake_crewman/assistant,
+/obj/effect/mapping_helpers/broken_floor,
+/obj/item/restraints/handcuffs/cable/yellow{
+ pixel_x = 3;
+ pixel_y = 3
+ },
+/obj/item/stack/medical/gauze/improvised{
+ pixel_y = -2
+ },
+/turf/open/floor/plating,
+/area/virtual_domain)
"oL" = (
/obj/effect/turf_decal/tile/yellow,
/obj/structure/cable,
@@ -425,17 +438,6 @@
/obj/effect/decal/cleanable/cobweb,
/turf/open/floor/plating,
/area/virtual_domain)
-"qS" = (
-/obj/machinery/sleeper/stasis{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue/fourcorners,
-/obj/effect/turf_decal/siding/blue{
- dir = 5
- },
-/obj/structure/cable,
-/turf/open/floor/plastic,
-/area/virtual_domain)
"rq" = (
/obj/effect/turf_decal/tile/yellow/fourcorners,
/obj/machinery/suit_storage_unit,
@@ -567,6 +569,16 @@
/obj/structure/cable,
/turf/open/floor/plating,
/area/virtual_domain)
+"vO" = (
+/obj/machinery/defibrillator_mount/directional/west,
+/obj/structure/table/glass,
+/obj/effect/turf_decal/tile/blue/fourcorners,
+/obj/item/stack/medical/gauze/improvised,
+/obj/effect/turf_decal/siding/blue{
+ dir = 4
+ },
+/turf/open/floor/plastic,
+/area/virtual_domain)
"vP" = (
/obj/effect/turf_decal/tile/yellow{
dir = 1
@@ -602,6 +614,17 @@
},
/turf/open/floor/plating/heretic_rust,
/area/virtual_domain)
+"xa" = (
+/obj/machinery/stasis{
+ dir = 1
+ },
+/obj/effect/turf_decal/tile/blue/fourcorners,
+/obj/effect/turf_decal/siding/blue{
+ dir = 5
+ },
+/obj/structure/cable,
+/turf/open/floor/plastic,
+/area/virtual_domain)
"xg" = (
/obj/effect/turf_decal/tile/red{
dir = 8
@@ -839,16 +862,6 @@
/obj/structure/extinguisher_cabinet/directional/south,
/turf/open/floor/iron,
/area/virtual_domain)
-"GI" = (
-/obj/structure/table/glass,
-/obj/effect/turf_decal/tile/blue/fourcorners,
-/obj/effect/turf_decal/siding/blue/end{
- dir = 1
- },
-/obj/item/stack/medical/wrap/gauze/improvised,
-/obj/structure/cable,
-/turf/open/floor/plastic,
-/area/virtual_domain)
"GO" = (
/obj/structure/frame/computer{
pixel_y = 0;
@@ -1096,6 +1109,17 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/plating/heretic_rust,
/area/virtual_domain)
+"NN" = (
+/obj/effect/turf_decal/tile/blue/fourcorners,
+/obj/structure/table/glass,
+/obj/item/stack/medical/gauze{
+ pixel_y = 4
+ },
+/obj/effect/turf_decal/siding/blue{
+ dir = 8
+ },
+/turf/open/floor/plastic,
+/area/virtual_domain)
"NO" = (
/mob/living/basic/fake_crewman/md,
/turf/open/floor/plastic,
@@ -1122,6 +1146,16 @@
"Pr" = (
/turf/closed/indestructible/binary,
/area/virtual_domain)
+"PB" = (
+/obj/structure/table/glass,
+/obj/effect/turf_decal/tile/blue/fourcorners,
+/obj/effect/turf_decal/siding/blue/end{
+ dir = 1
+ },
+/obj/item/stack/medical/gauze/improvised,
+/obj/structure/cable,
+/turf/open/floor/plastic,
+/area/virtual_domain)
"PJ" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/blood/old,
@@ -1194,18 +1228,6 @@
/obj/effect/spawner/random/trash/garbage,
/turf/open/floor/plating,
/area/virtual_domain)
-"RP" = (
-/mob/living/basic/fake_crewman/assistant,
-/obj/effect/mapping_helpers/broken_floor,
-/obj/item/restraints/handcuffs/cable/yellow{
- pixel_x = 3;
- pixel_y = 3
- },
-/obj/item/stack/medical/wrap/gauze/improvised{
- pixel_y = -2
- },
-/turf/open/floor/plating,
-/area/virtual_domain)
"RQ" = (
/obj/effect/turf_decal/tile/blue,
/obj/structure/cable,
@@ -1308,17 +1330,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/plating/heretic_rust,
/area/virtual_domain)
-"VU" = (
-/obj/machinery/sleeper/stasis{
- dir = 4
- },
-/obj/effect/turf_decal/tile/blue/fourcorners,
-/obj/effect/turf_decal/siding/blue{
- dir = 6
- },
-/obj/structure/cable,
-/turf/open/floor/plastic,
-/area/virtual_domain)
"VW" = (
/obj/effect/turf_decal/tile/yellow/fourcorners,
/obj/structure/tank_dispenser,
@@ -1419,17 +1430,6 @@
},
/turf/open/floor/plastic,
/area/virtual_domain)
-"YC" = (
-/obj/effect/turf_decal/tile/blue/fourcorners,
-/obj/structure/table/glass,
-/obj/item/stack/medical/wrap/gauze{
- pixel_y = 4
- },
-/obj/effect/turf_decal/siding/blue{
- dir = 8
- },
-/turf/open/floor/plastic,
-/area/virtual_domain)
"YL" = (
/mob/living/basic/fake_crewman/sec,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -1825,7 +1825,7 @@ ge
Vh
rC
rt
-RP
+oD
Zu
JG
MF
@@ -2062,10 +2062,10 @@ JG
Zu
Zu
FH
-VU
+eV
sT
-qS
-eB
+xa
+vO
Zu
iL
oa
@@ -2161,7 +2161,7 @@ dh
uS
uj
uj
-GI
+PB
vt
JA
KR
@@ -2267,7 +2267,7 @@ Wo
Zu
VX
Yy
-YC
+NN
Zu
Zt
Pr
diff --git a/_maps/virtual_domains/island_brawl.dmm b/_maps/virtual_domains/island_brawl.dmm
new file mode 100644
index 000000000000..560ccee99672
--- /dev/null
+++ b/_maps/virtual_domains/island_brawl.dmm
@@ -0,0 +1,12262 @@
+//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE
+"al" = (
+/obj/structure/flora/coconuts{
+ pixel_x = -5;
+ pixel_y = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"as" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"aw" = (
+/obj/structure/railing{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"aA" = (
+/obj/structure/chair/stool/bamboo{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"aD" = (
+/obj/item/storage/medkit/regular{
+ pixel_y = 15;
+ pixel_x = -2
+ },
+/obj/structure/table/glass,
+/obj/item/emergency_bed{
+ pixel_y = 6
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"aE" = (
+/obj/structure/chair/stool/directional/south,
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"aQ" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/under/costume/sailor,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"aY" = (
+/obj/structure/table/wood,
+/obj/item/tape{
+ pixel_y = 7;
+ pixel_x = 11
+ },
+/obj/item/reagent_containers/cup/glass/coffee{
+ pixel_x = -7;
+ pixel_y = 12
+ },
+/obj/effect/spawner/random/bureaucracy/pen{
+ pixel_x = -3;
+ pixel_y = -2
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"aZ" = (
+/obj/structure/table/wood,
+/obj/item/food/grown/watermelon{
+ pixel_y = 8;
+ pixel_x = 6
+ },
+/obj/item/food/watermelonslice,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ba" = (
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"bb" = (
+/obj/item/circular_saw{
+ pixel_y = 4
+ },
+/obj/item/scalpel{
+ pixel_y = 15
+ },
+/obj/structure/table/glass,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"bp" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_y = -1;
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"bx" = (
+/obj/machinery/defibrillator_mount/directional/west,
+/obj/structure/bed/pod{
+ desc = "An old medical bed, just waiting for replacement with something up to date.";
+ dir = 4;
+ name = "medical bed"
+ },
+/obj/machinery/iv_drip{
+ pixel_y = 21;
+ pixel_x = -4
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"bD" = (
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/obj/item/reagent_containers/cup/soda_cans/melon_soda{
+ pixel_y = 13;
+ pixel_x = -9
+ },
+/obj/item/fishing_rod{
+ pixel_x = 8;
+ pixel_y = -6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"bE" = (
+/turf/open/floor/wood,
+/area/virtual_domain)
+"bK" = (
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"bT" = (
+/obj/item/cigbutt{
+ pixel_y = -4;
+ pixel_x = 2
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"bX" = (
+/obj/effect/turf_decal/sand/plating,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"bY" = (
+/turf/open/misc/beach/coast{
+ dir = 4
+ },
+/area/virtual_domain/fullbright)
+"cc" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/obj/machinery/vending/cigarette/beach,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"ce" = (
+/obj/structure/reagent_dispensers/fueltank,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/decal/cleanable/cobweb/cobweb2,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"cg" = (
+/obj/machinery/medical_kiosk,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ch" = (
+/obj/machinery/recharge_station,
+/obj/machinery/light/directional/east,
+/turf/open/floor/carpet/cyan,
+/area/virtual_domain)
+"cp" = (
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -8;
+ pixel_y = -6
+ },
+/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{
+ pixel_x = 15
+ },
+/obj/structure/fluff/beach_umbrella/science,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"cr" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/machinery/button/door/directional/north{
+ id = "beach_room_9";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/claymore/cutlass{
+ desc = "A piratey, foam sword used by kids to train themselves in the business of \"negotiating\" the transfer of treasure.";
+ force = 0;
+ name = "foam cutlass";
+ throwforce = 0
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"ct" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"cB" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/under/costume/pirate,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"cC" = (
+/obj/structure/reagent_dispensers/watertank,
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"cE" = (
+/turf/open/misc/beach/coast,
+/area/virtual_domain/fullbright)
+"cH" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/machinery/door/airlock/wood{
+ name = "Room 7";
+ id_tag = "beach_room_7"
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"cK" = (
+/obj/item/reagent_containers/cup/glass/bottle/wine{
+ pixel_y = 16;
+ pixel_x = -5
+ },
+/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{
+ pixel_y = 3;
+ pixel_x = -8
+ },
+/obj/structure/table/bronze,
+/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{
+ pixel_y = 10;
+ pixel_x = 6
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"cO" = (
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"cW" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/carpet/cyan,
+/area/virtual_domain)
+"db" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 11";
+ id_tag = "beach_room_11"
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"de" = (
+/obj/effect/turf_decal/sand,
+/mob/living/basic/crab,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"dj" = (
+/obj/machinery/door/airlock/wood/glass{
+ name = "Hotel's Facilities"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"dl" = (
+/obj/structure/table/bronze,
+/obj/item/reagent_containers/condiment/bbqsauce{
+ pixel_y = 13;
+ pixel_x = 3
+ },
+/obj/item/reagent_containers/condiment/hotsauce{
+ pixel_y = 9;
+ pixel_x = -3
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"dp" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"du" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_y = -1;
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"dv" = (
+/obj/structure/table,
+/obj/item/wrench{
+ pixel_y = 4
+ },
+/obj/item/storage/toolbox/emergency,
+/obj/effect/decal/cleanable/oil,
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"dA" = (
+/obj/structure/table/bronze,
+/obj/item/paper_bin/carbon{
+ pixel_y = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"dB" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"dD" = (
+/obj/item/trash/can{
+ pixel_y = -9;
+ pixel_x = 10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"dG" = (
+/obj/effect/turf_decal/siding/blue,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"dH" = (
+/obj/structure/closet/crate/bin,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"dS" = (
+/obj/structure/table/bronze,
+/obj/structure/sign/poster/random/directional/east,
+/obj/item/table_clock{
+ pixel_y = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"dW" = (
+/obj/structure/railing/corner/end/flip{
+ dir = 1
+ },
+/obj/machinery/door/airlock/wood{
+ name = "Balcony";
+ id_tag = "beach_room_x"
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"dX" = (
+/obj/item/toy/seashell{
+ pixel_y = -5
+ },
+/turf/open/misc/beach/coast,
+/area/virtual_domain/fullbright)
+"dY" = (
+/obj/structure/table/wood/poker,
+/obj/item/stack/spacecash/c100{
+ pixel_y = 5
+ },
+/obj/item/toy/cards/deck{
+ pixel_y = 13;
+ pixel_x = -5
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"ee" = (
+/obj/structure/table/reinforced,
+/obj/item/defibrillator/loaded{
+ pixel_y = 7
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"ef" = (
+/obj/effect/turf_decal/stripes/red/line{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"eh" = (
+/obj/structure/table/wood/fancy,
+/obj/effect/turf_decal/tile/dark_red/full,
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -13;
+ pixel_y = 14
+ },
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = 7;
+ pixel_y = 8
+ },
+/turf/open/floor/iron/smooth_large,
+/area/virtual_domain/fullbright)
+"en" = (
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"ev" = (
+/obj/structure/mineral_door/sandstone{
+ name = "Sandcastle"
+ },
+/obj/effect/turf_decal/sand/plating,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ew" = (
+/obj/effect/landmark/bitrunning/cache_goal_turf,
+/obj/effect/landmark/bitrunning/loot_signal,
+/turf/open/indestructible/binary,
+/area/virtual_domain/protected_space/fullbright)
+"eH" = (
+/turf/open/misc/beach/coast{
+ dir = 9
+ },
+/area/virtual_domain/fullbright)
+"eJ" = (
+/obj/structure/table/bronze,
+/obj/item/camera{
+ pixel_y = 5
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"eK" = (
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain/fullbright)
+"eM" = (
+/obj/item/trash/can{
+ pixel_y = -5;
+ pixel_x = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"eO" = (
+/obj/structure/table/bronze,
+/obj/item/camera{
+ pixel_y = 8;
+ pixel_x = -3
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"eP" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/food_cart,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"eZ" = (
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"fe" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_y = -2;
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"fg" = (
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain)
+"fv" = (
+/obj/item/toy/seashell{
+ pixel_x = 12;
+ pixel_y = -9
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"fH" = (
+/obj/structure/table/bronze,
+/obj/item/camera{
+ pixel_y = 8;
+ pixel_x = 6
+ },
+/obj/item/pen/blue{
+ pixel_x = -11;
+ pixel_y = 2
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"fI" = (
+/turf/open/misc/beach/sand,
+/area/virtual_domain/protected_space/fullbright)
+"fJ" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"fL" = (
+/obj/machinery/computer/order_console/cook,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"fY" = (
+/obj/structure/window/reinforced/spawner/directional/west,
+/obj/structure/window/reinforced/spawner/directional/south,
+/obj/item/binoculars{
+ pixel_y = 20
+ },
+/obj/item/megaphone{
+ pixel_y = 2;
+ pixel_x = 1
+ },
+/obj/structure/table/wood,
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"gc" = (
+/obj/structure/table/bronze,
+/obj/item/pai_card{
+ desc = "A real Nanotrasen success, these personal AIs provide all of the companionship of an AI without any law related red-tape.";
+ name = "\improper Nanotrasen-brand personal AI device exhibit";
+ pixel_y = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"gf" = (
+/obj/machinery/button/door/directional/south{
+ id = "beach_room_5";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"gi" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/obj/item/stack/arcadeticket{
+ pixel_y = 12;
+ pixel_x = -16
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"gs" = (
+/obj/structure/closet/crate,
+/obj/item/clothing/suit/hooded/carp_costume,
+/obj/item/clothing/head/hooded/carp_hood,
+/obj/item/toy/plush/carpplushie,
+/obj/item/toy/plush/shark,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"gw" = (
+/turf/open/floor/carpet/cyan,
+/area/virtual_domain)
+"gA" = (
+/obj/effect/turf_decal/sand{
+ density = 1
+ },
+/obj/effect/decal/fakelattice,
+/turf/open/floor/pod/light{
+ density = 1
+ },
+/area/virtual_domain/fullbright)
+"gB" = (
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"gC" = (
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -5;
+ pixel_y = -5
+ },
+/obj/structure/fluff/beach_umbrella/syndi,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"gH" = (
+/obj/structure/tank_holder/extinguisher,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"gI" = (
+/obj/item/storage/toolbox/fishing{
+ pixel_x = 2;
+ pixel_y = -13
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"gK" = (
+/obj/structure/bed/double,
+/obj/item/bedsheet/hos/double{
+ name = "bedsheet";
+ desc = "A bedsheet from the beach hotel."
+ },
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"gL" = (
+/turf/open/misc/beach/coast/corner,
+/area/virtual_domain/fullbright)
+"gN" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"gP" = (
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"gV" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 25
+ },
+/obj/structure/flora/coconuts{
+ pixel_x = -7;
+ pixel_y = 7
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"hh" = (
+/obj/effect/turf_decal/sand/plating,
+/obj/item/shovel{
+ pixel_y = 15;
+ pixel_x = -8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ho" = (
+/obj/structure/chair/stool/bar/directional/west,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"hu" = (
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/protected_space/fullbright)
+"hA" = (
+/obj/structure/table/wood,
+/obj/machinery/chem_dispenser/drinks/fullupgrade{
+ dir = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"hB" = (
+/obj/item/reagent_containers/cup/soda_cans/lemon_lime{
+ pixel_x = -12
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"hD" = (
+/obj/effect/decal/cleanable/oil,
+/obj/machinery/button/door/directional/south{
+ id = "BeachGarage"
+ },
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"hM" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/machinery/button/door/directional/south{
+ id = "BeachBoats"
+ },
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"hT" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/mapping_helpers/broken_floor,
+/obj/effect/decal/cleanable/cobweb,
+/obj/machinery/power/smes/full,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"hZ" = (
+/obj/structure/table/bronze,
+/obj/item/storage/bag/tray,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"ii" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood{
+ dir = 5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ij" = (
+/turf/open/misc/beach/coast{
+ dir = 10
+ },
+/area/virtual_domain/fullbright)
+"ik" = (
+/obj/structure/dresser,
+/obj/machinery/digital_clock/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"il" = (
+/obj/structure/chair/plastic,
+/obj/item/fishing_rod{
+ pixel_x = 11;
+ pixel_y = -8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"io" = (
+/obj/structure/railing{
+ dir = 10
+ },
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 9;
+ pixel_x = 6
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"iy" = (
+/obj/structure/window/reinforced/spawner/directional/east,
+/obj/structure/window/reinforced/spawner/directional/north{
+ layer = 2.9
+ },
+/obj/structure/chair/stool/directional/south,
+/obj/item/clothing/glasses/sunglasses{
+ pixel_y = -2;
+ pixel_x = 2
+ },
+/obj/item/bikehorn/airhorn{
+ pixel_y = -15;
+ pixel_x = -13
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 5
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"iF" = (
+/obj/structure/table/bronze,
+/obj/structure/desk_bell{
+ pixel_x = -11;
+ pixel_y = 9
+ },
+/obj/item/phone{
+ pixel_y = 9;
+ pixel_x = 8
+ },
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"iP" = (
+/obj/structure/chair/plastic,
+/obj/item/clothing/head/collectable/paper{
+ desc = "What looks like an ordinary paper hat is actually a rare and valuable collector's edition paper hat. Keep away from fire, Curators, and ocean waves.";
+ pixel_y = -4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"iQ" = (
+/obj/machinery/button/door/directional/north{
+ id = "beach_room_3";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"iU" = (
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"iY" = (
+/obj/item/storage/bag/tray,
+/obj/item/food/grown/watermelon{
+ pixel_y = 4;
+ pixel_x = -1
+ },
+/obj/effect/turf_decal/stripes/red/box,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"jb" = (
+/obj/structure/tank_holder/extinguisher{
+ pixel_y = 11
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"jm" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/machinery/light/small/directional/west,
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"jn" = (
+/obj/item/cigbutt{
+ pixel_y = -6;
+ pixel_x = -12
+ },
+/obj/structure/railing/corner/end/flip{
+ dir = 4
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"jp" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/neck/necklace/dope,
+/obj/item/clothing/suit/jacket/letterman,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"jq" = (
+/obj/structure/musician/piano,
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"jr" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 10;
+ pixel_x = 7
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"jw" = (
+/obj/machinery/space_heater,
+/obj/structure/sign/clock/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"jK" = (
+/obj/machinery/reagentgrinder{
+ pixel_y = 15;
+ pixel_x = -1
+ },
+/obj/structure/table/bronze,
+/obj/structure/desk_bell{
+ pixel_x = 12;
+ pixel_y = 3
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"jL" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"jP" = (
+/turf/open/indestructible/binary,
+/area/virtual_domain/protected_space/fullbright)
+"jV" = (
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"jW" = (
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"ka" = (
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ke" = (
+/obj/vehicle/ridden/atv{
+ dir = 4
+ },
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"ky" = (
+/obj/machinery/vending/snack,
+/obj/effect/turf_decal/sand,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"kD" = (
+/obj/machinery/door/airlock/maintenance,
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/floor/plating,
+/area/virtual_domain)
+"kI" = (
+/obj/effect/turf_decal/sand,
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain)
+"kJ" = (
+/obj/machinery/shower/directional/south,
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"kL" = (
+/obj/structure/billboard/space_cola,
+/obj/effect/turf_decal/siding/dark_red,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"kN" = (
+/obj/effect/turf_decal/sand/plating,
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"lc" = (
+/obj/machinery/space_heater,
+/obj/machinery/button/door/directional/north{
+ id = "beach_room_2";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"lh" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/item/storage/toolbox/mechanical/old,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"lk" = (
+/obj/effect/turf_decal/siding/dark_red/corner,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"lx" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/virtual_domain/fullbright)
+"lz" = (
+/obj/effect/turf_decal/siding/blue/corner{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"lA" = (
+/obj/machinery/shower/directional/west,
+/obj/effect/turf_decal/siding/wood{
+ dir = 9
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"lF" = (
+/obj/structure/table/reinforced,
+/obj/item/storage/medkit/o2{
+ pixel_y = 17;
+ pixel_x = -1
+ },
+/obj/item/storage/medkit/brute{
+ pixel_y = 23;
+ pixel_x = -1
+ },
+/obj/item/food/lollipop{
+ pixel_y = 8;
+ pixel_x = 12
+ },
+/obj/item/food/lollipop{
+ pixel_y = 5;
+ pixel_x = 12
+ },
+/obj/item/reagent_containers/cup/bottle/multiver{
+ pixel_x = -9;
+ pixel_y = 9
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"lG" = (
+/obj/item/toy/seashell{
+ pixel_y = 11;
+ pixel_x = -7
+ },
+/turf/open/misc/beach/coast,
+/area/virtual_domain/fullbright)
+"lI" = (
+/obj/structure/table/wood/poker,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"lJ" = (
+/obj/structure/table/wood,
+/obj/item/reagent_containers/cup/beaker/large{
+ pixel_y = 7
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"lP" = (
+/obj/structure/chair,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"lS" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"lU" = (
+/obj/machinery/door/airlock/security/glass{
+ name = "Temporary Holding Cell"
+ },
+/obj/effect/mapping_helpers/airlock/unres{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock/access/all/security/entrance,
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"lW" = (
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"mi" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 24
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"mv" = (
+/obj/effect/turf_decal/siding/dark_red{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"mx" = (
+/obj/machinery/door/airlock/wood{
+ name = "Arcade"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"mJ" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 25
+ },
+/obj/item/stack/sheet/mineral/sandstone/thirty{
+ pixel_y = -10;
+ pixel_x = -5
+ },
+/obj/item/stack/sheet/mineral/sandstone/thirty{
+ pixel_y = -2;
+ pixel_x = 9
+ },
+/obj/item/stack/sheet/mineral/sandstone/thirty{
+ pixel_y = -4;
+ pixel_x = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"mL" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/machinery/door/airlock/wood{
+ name = "Tropical Kitchen"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"mP" = (
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/obj/item/reagent_containers/cup/soda_cans/starkist{
+ pixel_y = 10;
+ pixel_x = -17
+ },
+/obj/item/fishing_rod{
+ pixel_x = -13;
+ pixel_y = 2
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"mV" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"mW" = (
+/obj/effect/turf_decal/siding/blue/corner{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"nc" = (
+/turf/open/misc/beach/coast/corner{
+ dir = 1
+ },
+/area/virtual_domain/fullbright)
+"nk" = (
+/obj/machinery/door/airlock/wood{
+ name = "Balcony";
+ id_tag = "beach_room_x"
+ },
+/obj/structure/railing/corner/end/flip{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"nR" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"nX" = (
+/obj/structure/table/wood,
+/obj/item/melee/baseball_bat{
+ pixel_y = 3;
+ pixel_x = 6
+ },
+/obj/item/clothing/glasses/blindfold/white{
+ pixel_y = 7;
+ pixel_x = -5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"oa" = (
+/turf/open/misc/beach/coast{
+ dir = 1
+ },
+/area/virtual_domain/fullbright)
+"ob" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"og" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"oq" = (
+/obj/structure/table/wood,
+/obj/item/food/grown/watermelon{
+ pixel_y = 13;
+ pixel_x = 6
+ },
+/obj/item/food/grown/watermelon{
+ pixel_y = 8;
+ pixel_x = -4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"os" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 12;
+ pixel_x = -7
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ot" = (
+/turf/template_noop,
+/area/template_noop)
+"ow" = (
+/obj/structure/reagent_dispensers/watertank,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"oC" = (
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -8;
+ pixel_y = 13
+ },
+/turf/open/floor/carpet/blue,
+/area/virtual_domain/fullbright)
+"oE" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/glasses/heat,
+/obj/item/clothing/head/cowboy/brown,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"oJ" = (
+/obj/item/flashlight/flare/torch{
+ pixel_x = -11;
+ pixel_y = -6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"oQ" = (
+/obj/structure/table/bronze,
+/obj/item/pai_card{
+ desc = "A real Nanotrasen success, these personal AIs provide all of the companionship of an AI without any law related red-tape.";
+ name = "\improper Nanotrasen-brand personal AI device exhibit";
+ pixel_y = 2
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"oZ" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"pj" = (
+/obj/structure/table/bronze,
+/obj/item/camera{
+ pixel_y = 12;
+ pixel_x = -10
+ },
+/obj/item/camera{
+ pixel_y = 4;
+ pixel_x = 1
+ },
+/obj/item/camera_film{
+ pixel_y = -11;
+ pixel_x = -10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"pq" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/suit/jacket/letterman_syndie,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"pv" = (
+/obj/machinery/light/directional/north,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"py" = (
+/turf/open/floor/iron/stairs,
+/area/virtual_domain/fullbright)
+"pz" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/under/costume/lobster,
+/obj/item/clothing/head/costume/lobsterhat,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"pC" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"pE" = (
+/obj/machinery/door/airlock/wood/glass{
+ name = "Rooms"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"pJ" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/suit/jacket/letterman_red,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"pV" = (
+/obj/item/stack/arcadeticket{
+ pixel_y = 5;
+ pixel_x = 13
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"pX" = (
+/obj/structure/chair/office{
+ dir = 8
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"qa" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"qb" = (
+/obj/machinery/button/door/directional/west{
+ id = "beach_room_1";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"qc" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/vending/clothing,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"qB" = (
+/obj/item/toy/seashell{
+ pixel_x = 5;
+ pixel_y = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"qH" = (
+/obj/structure/bed/medical/emergency,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"qR" = (
+/obj/structure/chair/office{
+ dir = 8
+ },
+/obj/item/cigbutt{
+ pixel_y = -6;
+ pixel_x = -12
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"qZ" = (
+/obj/effect/turf_decal/siding/dark_red/corner{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ra" = (
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = 11
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rj" = (
+/obj/machinery/grill,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rl" = (
+/obj/structure/rack,
+/obj/item/melee/skateboard/hoverboard{
+ pixel_x = -7
+ },
+/obj/item/melee/skateboard/hoverboard,
+/obj/item/melee/skateboard/hoverboard{
+ pixel_x = 7
+ },
+/turf/open/misc/beach/coast/corner{
+ dir = 4
+ },
+/area/virtual_domain/fullbright)
+"rn" = (
+/obj/machinery/computer/operating{
+ dir = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"ro" = (
+/obj/structure/closet/secure_closet/personal,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"rw" = (
+/obj/structure/table/bronze,
+/obj/machinery/button/door/directional/south{
+ id = "beach_room_4";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/storage/toolbox/fishing{
+ pixel_y = 2
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"rz" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rB" = (
+/obj/item/toy/seashell{
+ pixel_x = -10;
+ pixel_y = -4
+ },
+/obj/structure/fluff/beach_umbrella,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rD" = (
+/obj/structure/flora/coconuts,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rE" = (
+/obj/structure/table/bronze,
+/obj/machinery/button/door/directional/south{
+ id = "beach_room_11";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/storage/toolbox/fishing{
+ pixel_y = 2
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"rG" = (
+/obj/machinery/telecomms/allinone,
+/obj/item/wirecutters{
+ pixel_y = 9
+ },
+/obj/machinery/light/directional/south,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"rI" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 12";
+ id_tag = "beach_room_12"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"rK" = (
+/obj/machinery/vending/cigarette/beach,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rQ" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 7;
+ pixel_x = 9
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"rR" = (
+/obj/structure/table/bronze,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"rW" = (
+/obj/structure/chair{
+ dir = 8
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"sa" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/door/airlock/wood{
+ name = "Bathroom";
+ id_tag = "toilet3beach"
+ },
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"sh" = (
+/obj/structure/statue/sandstone/venus{
+ pixel_y = 9;
+ dir = 1;
+ anchored = 1
+ },
+/obj/structure/flora/bush/flowers_br/style_random,
+/turf/open/floor/grass,
+/area/virtual_domain)
+"si" = (
+/obj/structure/table/wood,
+/obj/item/reagent_containers/condiment/enzyme{
+ layer = 5;
+ pixel_x = 9;
+ pixel_y = 5
+ },
+/obj/item/food/seaweedsheet{
+ pixel_y = 6;
+ pixel_x = -4
+ },
+/obj/item/food/seaweedsheet{
+ pixel_x = -15;
+ pixel_y = 2
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"sl" = (
+/obj/effect/turf_decal/sand/plating,
+/obj/item/reagent_containers/cup/bucket/wooden{
+ pixel_y = 17;
+ pixel_x = -6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"st" = (
+/obj/structure/table/bronze,
+/obj/structure/sign/poster/random/directional/east,
+/obj/machinery/button/door/directional/south{
+ id = "beach_room_8";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/camera{
+ pixel_y = 5
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"sz" = (
+/obj/item/toy/seashell,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"sC" = (
+/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"sI" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_y = 2;
+ pixel_x = 5
+ },
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_y = 6;
+ pixel_x = -4
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"sO" = (
+/obj/structure/fluff/beach_umbrella/syndi,
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -8;
+ pixel_y = -6
+ },
+/obj/item/reagent_containers/cup/soda_cans/thirteenloko{
+ pixel_x = 15;
+ pixel_y = -11
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"sR" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"sV" = (
+/obj/structure/table,
+/obj/item/storage/belt/utility,
+/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{
+ pixel_y = 14;
+ pixel_x = -8
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"sW" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 5";
+ id_tag = "beach_room_5"
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"ta" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"tf" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/item/storage/box/lights/mixed{
+ pixel_x = -4;
+ pixel_y = 18
+ },
+/obj/item/storage/box/lights/mixed{
+ pixel_x = 6;
+ pixel_y = 12
+ },
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = -7;
+ pixel_y = 12
+ },
+/obj/structure/table,
+/obj/item/reagent_containers/cup/bucket{
+ pixel_x = 10;
+ pixel_y = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"th" = (
+/obj/structure/flora/tree/palm,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"tk" = (
+/turf/open/misc/beach/coast/corner{
+ dir = 4
+ },
+/area/virtual_domain/fullbright)
+"tw" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"ty" = (
+/obj/item/trash/boritos/purple{
+ pixel_y = -16;
+ pixel_x = -5
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"tI" = (
+/obj/structure/sign/departments/custodian/directional/north{
+ pixel_x = -32
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"tM" = (
+/obj/structure/table/wood,
+/obj/item/book/manual/chef_recipes{
+ pixel_x = 2;
+ pixel_y = 6
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"tQ" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"tW" = (
+/obj/structure/chair/plastic{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"tX" = (
+/obj/structure/table/bronze,
+/obj/item/reagent_containers/condiment/ketchup{
+ pixel_y = 14;
+ pixel_x = 1
+ },
+/obj/item/reagent_containers/condiment/mayonnaise{
+ pixel_y = 8;
+ pixel_x = 8
+ },
+/obj/machinery/light/directional/east,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"up" = (
+/obj/item/storage/box/syringes{
+ pixel_y = 14;
+ pixel_x = -5
+ },
+/obj/item/clothing/neck/stethoscope{
+ pixel_y = 3;
+ pixel_x = 4
+ },
+/obj/structure/table/glass,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"ut" = (
+/obj/structure/window/reinforced/spawner/directional/east,
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"uu" = (
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"uz" = (
+/obj/effect/turf_decal/siding/dark_red/corner{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"uC" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 14
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"uD" = (
+/obj/structure/table/wood,
+/obj/item/food/seaweedsheet,
+/obj/item/kitchen/rollingpin{
+ pixel_x = -12;
+ pixel_y = 3
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"uH" = (
+/obj/structure/bonfire,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"uI" = (
+/obj/structure/bed,
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"uX" = (
+/obj/effect/turf_decal/siding/dark_red{
+ dir = 4
+ },
+/obj/item/trash/can{
+ pixel_y = -9;
+ pixel_x = 10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"uY" = (
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"vx" = (
+/obj/structure/table/glass,
+/obj/item/storage/box/coffeepack{
+ pixel_x = 2;
+ pixel_y = 4
+ },
+/obj/item/storage/box/donkpockets{
+ pixel_y = 10;
+ pixel_x = 11
+ },
+/obj/item/storage/fancy/donut_box{
+ pixel_y = 18;
+ pixel_x = -11
+ },
+/obj/item/food/donut/berry{
+ pixel_y = 5;
+ pixel_x = -6
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"vF" = (
+/obj/structure/railing{
+ dir = 9
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"vM" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood{
+ dir = 9
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"vU" = (
+/obj/machinery/chem_master/condimaster{
+ name = "CondiMaster Neo"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"wb" = (
+/turf/open/misc/beach/coast{
+ dir = 5
+ },
+/area/virtual_domain/fullbright)
+"wf" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ww" = (
+/obj/structure/chair/stool/directional/south{
+ dir = 8
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"wx" = (
+/obj/structure/closet/crate/bin,
+/obj/structure/sign/clock/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"wz" = (
+/obj/structure/rack,
+/obj/item/mop,
+/obj/item/extinguisher,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"wC" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/structure/reagent_dispensers/fueltank/large,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"wH" = (
+/obj/structure/table/wood/fancy,
+/obj/effect/turf_decal/tile/dark_red/full,
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -5;
+ pixel_y = 14
+ },
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_y = 13;
+ pixel_x = 6
+ },
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_y = 10
+ },
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_y = 6;
+ pixel_x = 11
+ },
+/turf/open/floor/iron/smooth_large,
+/area/virtual_domain/fullbright)
+"wI" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/obj/machinery/shower/directional/south,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"wN" = (
+/obj/item/cigbutt{
+ pixel_y = 21;
+ pixel_x = -13
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"wO" = (
+/obj/structure/dresser,
+/obj/machinery/light/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"wT" = (
+/obj/effect/spawner/random/entertainment/arcade{
+ dir = 8
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"wZ" = (
+/obj/item/clothing/head/soft/green,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"xe" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/door/airlock/wood{
+ name = "Bathroom";
+ id_tag = "toiletfarbeach"
+ },
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"xg" = (
+/turf/open/misc/beach/sand,
+/area/virtual_domain)
+"xj" = (
+/obj/item/toy/seashell{
+ pixel_x = -8;
+ pixel_y = 9
+ },
+/turf/open/misc/beach/coast/corner{
+ dir = 1
+ },
+/area/virtual_domain/fullbright)
+"xk" = (
+/obj/structure/closet/crate/freezer,
+/obj/item/food/meat/slab/rawcrab,
+/obj/item/food/meat/slab/rawcrab,
+/obj/item/food/meat/slab/rawcrab,
+/obj/item/food/meat/slab/chicken,
+/obj/item/food/meat/slab/chicken,
+/obj/item/food/meat/slab/chicken,
+/obj/item/food/meat/slab,
+/obj/item/food/meat/slab,
+/obj/item/food/meat/slab,
+/obj/item/stack/sheet/mineral/coal/ten,
+/obj/item/stack/sheet/mineral/coal/ten,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"xw" = (
+/obj/item/kirbyplants/organic/applebush{
+ pixel_x = 7
+ },
+/obj/item/kirbyplants/organic/plant17{
+ pixel_y = 2;
+ pixel_x = -8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"xx" = (
+/obj/item/stack/arcadeticket{
+ pixel_y = 6;
+ pixel_x = -7
+ },
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"xJ" = (
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"xO" = (
+/obj/structure/chair/stool/directional/south,
+/obj/machinery/light/directional/north,
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"xP" = (
+/obj/structure/chair/plastic{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"xR" = (
+/obj/structure/railing{
+ dir = 5
+ },
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 3;
+ pixel_x = -2
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"xT" = (
+/obj/machinery/oven/range,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"yc" = (
+/obj/structure/closet/gmcloset,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"yg" = (
+/obj/machinery/light/directional/east,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"yy" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/carpet/red,
+/area/virtual_domain/fullbright)
+"yz" = (
+/obj/structure/table/bronze,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"yB" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 9
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_y = -1;
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"yG" = (
+/obj/effect/spawner/structure/window/reinforced,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"yI" = (
+/obj/structure/dresser,
+/obj/structure/sign/calendar/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"yJ" = (
+/obj/structure/closet/crate/hydroponics,
+/obj/item/popsicle_stick,
+/obj/item/popsicle_stick,
+/obj/item/popsicle_stick,
+/obj/item/reagent_containers/condiment/flour,
+/obj/item/reagent_containers/condiment/flour,
+/obj/item/reagent_containers/condiment/rice,
+/obj/item/reagent_containers/condiment/rice,
+/obj/item/food/grown/banana/bunch,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"yN" = (
+/obj/structure/chair/stool/bamboo{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"yQ" = (
+/obj/structure/table/bronze,
+/obj/structure/sign/poster/random/directional/east,
+/obj/machinery/button/door/directional/south{
+ id = "beach_room_10";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/table_clock{
+ pixel_y = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"ze" = (
+/obj/effect/turf_decal/tile/dark_red/full,
+/turf/open/floor/iron/smooth_large,
+/area/virtual_domain/fullbright)
+"zg" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_y = 6;
+ pixel_x = 4
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"zm" = (
+/obj/structure/table/reinforced,
+/obj/item/stack/medical/mesh{
+ pixel_y = 1;
+ pixel_x = 1
+ },
+/obj/item/clothing/suit/toggle/labcoat{
+ pixel_y = 9;
+ pixel_x = -8
+ },
+/obj/item/storage/box/bodybags{
+ pixel_y = 17;
+ pixel_x = 8
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"zn" = (
+/obj/structure/table/optable,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"zp" = (
+/obj/structure/chair{
+ dir = 8
+ },
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"zq" = (
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = -11;
+ pixel_y = -2
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"zH" = (
+/obj/item/reagent_containers/cup/soda_cans/lemon_lime{
+ pixel_x = -12;
+ pixel_y = 14
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"zK" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"zL" = (
+/obj/structure/table/bronze,
+/obj/item/paper/paperslip{
+ pixel_y = 6;
+ pixel_x = 10
+ },
+/obj/item/pen/fourcolor{
+ pixel_y = 7;
+ pixel_x = 1
+ },
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"zO" = (
+/obj/item/retractor{
+ pixel_y = 8;
+ pixel_x = -2
+ },
+/obj/item/cautery{
+ pixel_y = 10
+ },
+/obj/item/hemostat{
+ pixel_y = -11
+ },
+/obj/item/bonesetter{
+ pixel_y = -12
+ },
+/obj/structure/table/glass,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"zS" = (
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 18;
+ pixel_x = -8
+ },
+/obj/item/cigbutt{
+ pixel_y = -4;
+ pixel_x = 2
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Ac" = (
+/obj/machinery/chem_dispenser/drinks/beer/fullupgrade{
+ dir = 4
+ },
+/obj/structure/table/wood,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Ae" = (
+/obj/machinery/space_heater,
+/obj/machinery/light/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Ag" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 6
+ },
+/obj/machinery/light/directional/east,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"Ai" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"Aj" = (
+/obj/structure/railing/corner/end{
+ dir = 8
+ },
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"Al" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Aq" = (
+/obj/structure/table/wood/poker,
+/obj/item/storage/dice{
+ pixel_y = 3;
+ pixel_x = 5
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Ay" = (
+/obj/structure/table/reinforced,
+/obj/item/storage/medkit/brute{
+ pixel_y = 9;
+ pixel_x = 2
+ },
+/obj/item/storage/medkit/o2{
+ pixel_y = 15;
+ pixel_x = 2
+ },
+/obj/item/reagent_containers/cup/bottle/multiver{
+ pixel_x = -9;
+ pixel_y = 3
+ },
+/obj/item/reagent_containers/syringe{
+ pixel_y = -4;
+ pixel_x = 3
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"AG" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/dark/half{
+ pixel_x = 5;
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"AK" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"AX" = (
+/obj/vehicle/ridden/atv{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"AZ" = (
+/obj/effect/spawner/structure/window,
+/turf/open/floor/plating,
+/area/virtual_domain/fullbright)
+"Bc" = (
+/obj/item/reagent_containers/cup/bucket/wooden{
+ pixel_y = -5;
+ pixel_x = -11
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Bf" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Bk" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 2";
+ id_tag = "beach_room_2"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/structure/sign/poster/random/directional/east,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Bq" = (
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain)
+"Bx" = (
+/obj/item/reagent_containers/cup/soda_cans/starkist{
+ pixel_x = -12;
+ pixel_y = -6
+ },
+/obj/structure/fluff/beach_umbrella/cap,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Bz" = (
+/obj/structure/closet,
+/obj/item/key/atv{
+ pixel_x = -4
+ },
+/obj/item/key/atv{
+ pixel_x = 5;
+ pixel_y = 3
+ },
+/obj/item/key/atv{
+ pixel_x = 1;
+ pixel_y = 1
+ },
+/obj/item/clothing/head/soft/black,
+/obj/item/clothing/head/soft/black,
+/obj/item/clothing/head/soft/black,
+/obj/effect/decal/cleanable/oil,
+/obj/item/clothing/glasses/sunglasses,
+/obj/item/clothing/glasses/heat,
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"BB" = (
+/obj/item/toy/plush/moth{
+ pixel_y = 5
+ },
+/turf/open/floor/carpet/red,
+/area/virtual_domain/fullbright)
+"BD" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 19;
+ pixel_x = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"BI" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"BM" = (
+/obj/structure/closet/crate/bin,
+/obj/item/flashlight/glowstick/yellow,
+/obj/item/trash/candy,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"BU" = (
+/obj/item/storage/toolbox/fishing{
+ pixel_x = 10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"BV" = (
+/obj/structure/sign/directions/dorms/directional/north{
+ pixel_y = 35
+ },
+/obj/structure/sign/directions/medical/directional/north{
+ pixel_y = 29
+ },
+/obj/machinery/computer/slot_machine,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"BW" = (
+/obj/structure/dresser,
+/obj/structure/sign/clock/directional/east,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Co" = (
+/obj/machinery/processor,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Cw" = (
+/obj/structure/sign/poster/official/fruit_bowl/directional/north,
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"CA" = (
+/obj/item/reagent_containers/cup/soda_cans/sol_dry{
+ pixel_y = 18;
+ pixel_x = 9
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"CH" = (
+/obj/machinery/light/directional/north,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"CP" = (
+/obj/structure/table/reinforced,
+/obj/item/toy/plush/slimeplushie{
+ pixel_y = 8;
+ pixel_x = 4
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"CQ" = (
+/obj/structure/closet/crate/trashcart/laundry,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"CR" = (
+/obj/structure/fluff/beach_umbrella/syndi,
+/turf/open/misc/beach/coast/corner{
+ dir = 8
+ },
+/area/virtual_domain/fullbright)
+"CS" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 1";
+ id_tag = "beach_room_1"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"CU" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/machinery/button/door/directional/west{
+ id = "beach_room_6";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/clothing/suit/jacket/leather/biker,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"CV" = (
+/obj/item/toy/seashell{
+ pixel_x = 8;
+ pixel_y = 14
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Dg" = (
+/obj/item/toy/beach_ball,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Do" = (
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Dq" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/structure/railing{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"Dt" = (
+/obj/machinery/icecream_vat,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Dx" = (
+/obj/structure/chair/stool/bar/directional/east,
+/obj/machinery/light/directional/west,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"DA" = (
+/obj/item/cigbutt{
+ pixel_y = -7;
+ pixel_x = 14
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"DG" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/mapping_helpers/broken_floor,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"DL" = (
+/obj/structure/table,
+/obj/item/storage/toolbox/mechanical{
+ pixel_y = 12;
+ pixel_x = 3
+ },
+/obj/item/stock_parts/power_store/cell/emproof{
+ pixel_x = -4;
+ pixel_y = 6
+ },
+/obj/item/clothing/head/soft/mime{
+ pixel_y = 3;
+ pixel_x = 5
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"DP" = (
+/obj/effect/spawner/structure/window,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"DR" = (
+/turf/open/floor/carpet/blue,
+/area/virtual_domain/fullbright)
+"DS" = (
+/obj/machinery/door/airlock/wood{
+ name = "Changing Room"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"DT" = (
+/obj/structure/table/wood,
+/obj/item/knife/kitchen{
+ pixel_y = 12;
+ pixel_x = -13
+ },
+/obj/item/clothing/head/utility/chefhat,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"DU" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 10";
+ id_tag = "beach_room_10"
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Eb" = (
+/obj/item/reagent_containers/cup/soda_cans/cola{
+ pixel_x = -8;
+ pixel_y = -4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Ej" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 19;
+ pixel_x = 7
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Er" = (
+/obj/effect/turf_decal/sand,
+/obj/structure/bedsheetbin{
+ pixel_y = 3;
+ pixel_x = -1
+ },
+/obj/structure/table,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Et" = (
+/obj/item/toy/seashell,
+/turf/open/misc/beach/coast/corner{
+ dir = 8
+ },
+/area/virtual_domain/fullbright)
+"EA" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/button/door/directional/east{
+ id = "toiletfarbeach";
+ name = "restroom lock";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/structure/toilet{
+ pixel_y = 8
+ },
+/obj/structure/sink/directional/west,
+/obj/machinery/light/small/directional/west,
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"EI" = (
+/turf/open/misc/beach/coast{
+ dir = 8
+ },
+/area/virtual_domain/fullbright)
+"EP" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 3";
+ id_tag = "beach_room_3"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"EQ" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"ET" = (
+/obj/item/reagent_containers/cup/glass/bottle/beer/light{
+ pixel_x = -14;
+ pixel_y = 15
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"EY" = (
+/obj/structure/statue/sandstone/venus{
+ dir = 4;
+ pixel_y = 9;
+ anchored = 1
+ },
+/obj/structure/flora/bush/flowers_br/style_random,
+/turf/open/floor/grass,
+/area/virtual_domain)
+"Fk" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/item/storage/box/mousetraps{
+ pixel_x = -5;
+ pixel_y = 14
+ },
+/obj/structure/table,
+/obj/item/storage/box/mousetraps{
+ pixel_x = 12;
+ pixel_y = 15
+ },
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = -7;
+ pixel_y = 6
+ },
+/obj/item/grenade/chem_grenade/cleaner{
+ pixel_x = -1;
+ pixel_y = 3
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Fp" = (
+/obj/structure/closet/crate/bin,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Fx" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 6
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"FB" = (
+/obj/machinery/medical_kiosk,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"FE" = (
+/obj/machinery/washing_machine,
+/obj/machinery/light/directional/north,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"FO" = (
+/obj/structure/chair/plastic,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"FX" = (
+/turf/open/floor/carpet/green,
+/area/virtual_domain/fullbright)
+"Ga" = (
+/obj/item/stack/arcadeticket{
+ pixel_y = -1;
+ pixel_x = -6
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Gm" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain)
+"Go" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/suit/jacket/letterman_nanotrasen,
+/obj/item/clothing/glasses/salesman,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Gp" = (
+/obj/structure/no_effect_signpost{
+ pixel_y = 6;
+ desc = "Northwest: Hotel. South: Seaside Bar. East: Dressing Rooms."
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Gq" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain)
+"Gw" = (
+/turf/open/indestructible/binary,
+/area/virtual_domain/fullbright)
+"Gx" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/spawner/random/structure/closet_empty/crate,
+/obj/effect/spawner/random/maintenance/two,
+/obj/item/storage/toolbox/fishing{
+ pixel_y = 2
+ },
+/turf/open/floor/plating,
+/area/virtual_domain)
+"GD" = (
+/obj/effect/landmark/bitrunning/permanent_exit,
+/turf/open/floor/bitrunning_transport,
+/area/virtual_domain/protected_space/fullbright)
+"GI" = (
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"GK" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"GQ" = (
+/obj/item/toy/seashell{
+ pixel_y = 3;
+ pixel_x = -6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"GX" = (
+/obj/machinery/light/directional/west,
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"GY" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/machinery/shower/directional/south,
+/obj/structure/sink/directional/east,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"Hd" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/structure/railing/corner/end{
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain)
+"Ho" = (
+/obj/structure/table/wood,
+/obj/item/modular_computer/laptop{
+ pixel_y = 5
+ },
+/obj/item/multitool{
+ pixel_x = -8;
+ pixel_y = -8
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Hp" = (
+/obj/structure/table/wood,
+/obj/item/clothing/suit/apron/chef{
+ pixel_y = 5;
+ pixel_x = 2
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"HE" = (
+/obj/machinery/griddle,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"HH" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"HI" = (
+/obj/structure/statue/sandstone/venus{
+ dir = 4;
+ pixel_y = 9
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"HK" = (
+/obj/structure/closet/crate/bin,
+/obj/effect/spawner/random/trash/cigbutt,
+/obj/effect/spawner/random/trash/food_packaging,
+/obj/machinery/light/directional/north,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"HO" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 9";
+ id_tag = "beach_room_9"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"HP" = (
+/turf/open/water/beach,
+/area/virtual_domain)
+"HR" = (
+/obj/structure/sign/poster/official/tactical_game_cards/directional/west,
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"HT" = (
+/obj/structure/bed/pod{
+ desc = "An old medical bed, just waiting for replacement with something up to date.";
+ dir = 4;
+ name = "medical bed"
+ },
+/obj/machinery/defibrillator_mount/directional/east,
+/obj/machinery/iv_drip{
+ pixel_y = 21;
+ pixel_x = -4
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"HV" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"Ib" = (
+/obj/structure/tank_holder/extinguisher{
+ pixel_y = 11
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"If" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"In" = (
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 4;
+ pixel_x = 8
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"It" = (
+/obj/effect/turf_decal/siding/dark_red{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Iw" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/machinery/door/poddoor/shutters{
+ id = "BeachBoats"
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"IA" = (
+/obj/machinery/shower/directional/west,
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"IF" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"IG" = (
+/obj/machinery/door/poddoor/shutters{
+ dir = 4;
+ id = "BeachGarage"
+ },
+/turf/open/floor/plating,
+/area/virtual_domain/fullbright)
+"II" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"IJ" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/item/blood_filter{
+ pixel_y = 8;
+ pixel_x = -6
+ },
+/obj/item/surgical_drapes{
+ pixel_x = -1;
+ pixel_y = 2
+ },
+/obj/item/surgical_drapes{
+ pixel_x = 13;
+ pixel_y = 2
+ },
+/obj/structure/table/glass,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"IL" = (
+/obj/effect/turf_decal/siding/dark_red,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"IS" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"IX" = (
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 18;
+ pixel_x = -8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Jb" = (
+/obj/structure/table/glass,
+/obj/machinery/coffeemaker/impressa{
+ pixel_y = 13;
+ pixel_x = -1
+ },
+/obj/item/reagent_containers/cup/glass/mug{
+ pixel_x = -6;
+ pixel_y = 2
+ },
+/obj/item/reagent_containers/cup/glass/mug{
+ pixel_x = 11;
+ pixel_y = -1
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Jc" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 8
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Jd" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Je" = (
+/obj/structure/table/bronze,
+/obj/item/table_clock{
+ pixel_y = 13
+ },
+/obj/structure/sign/poster/random/directional/east,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Jp" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Jv" = (
+/obj/item/reagent_containers/cup/soda_cans/starkist{
+ pixel_x = -6
+ },
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Jw" = (
+/obj/item/toy/seashell{
+ pixel_x = 12;
+ pixel_y = 5
+ },
+/turf/open/misc/beach/coast{
+ dir = 4
+ },
+/area/virtual_domain/fullbright)
+"JF" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"JG" = (
+/obj/machinery/light/directional/west,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"JH" = (
+/obj/structure/marker_beacon/burgundy,
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"JJ" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 8";
+ id_tag = "beach_room_8"
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"JN" = (
+/obj/effect/turf_decal/sand,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"JU" = (
+/obj/item/instrument/guitar{
+ pixel_y = 4;
+ pixel_x = -1
+ },
+/turf/open/misc/beach/coast,
+/area/virtual_domain/fullbright)
+"Ka" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/machinery/button/door/directional/west{
+ id = "beach_room_7";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/item/clothing/suit/apron/overalls,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Ko" = (
+/obj/item/toy/beach_ball,
+/turf/open/misc/beach/coast/corner{
+ dir = 4
+ },
+/area/virtual_domain/fullbright)
+"Ks" = (
+/obj/structure/table/glass,
+/obj/machinery/microwave{
+ pixel_y = 15
+ },
+/obj/item/cigbutt{
+ pixel_y = 2;
+ pixel_x = -12
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"KH" = (
+/obj/structure/closet/athletic_mixed,
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"KI" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/effect/spawner/random/structure/crate,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"KJ" = (
+/obj/machinery/vending/coffee,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"KL" = (
+/obj/structure/closet/secure_closet/freezer/empty,
+/obj/item/food/popsicle/creamsicle_berry,
+/obj/item/food/popsicle/creamsicle_berry,
+/obj/item/food/popsicle/creamsicle_orange,
+/obj/item/food/popsicle/creamsicle_orange,
+/obj/item/food/popsicle/jumbo,
+/obj/item/food/popsicle/pineapple_pop,
+/obj/item/food/popsicle/pineapple_pop,
+/obj/item/food/fishmeat,
+/obj/item/food/fishmeat,
+/obj/item/food/fishmeat,
+/obj/item/food/fishmeat,
+/obj/item/food/fishmeat,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"KP" = (
+/obj/item/clothing/head/soft/black{
+ pixel_x = -1;
+ pixel_y = -3
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"KS" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/structure/railing{
+ dir = 1
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"KT" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"KZ" = (
+/obj/structure/railing{
+ dir = 1
+ },
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"La" = (
+/obj/machinery/light/directional/south,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Ld" = (
+/obj/structure/table/wood,
+/obj/item/cigarette/cigar{
+ pixel_y = 16;
+ pixel_x = -2
+ },
+/obj/item/reagent_containers/cup/glass/coffee{
+ pixel_x = 8;
+ pixel_y = 9
+ },
+/obj/machinery/cell_charger,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Lm" = (
+/obj/machinery/door/airlock/wood{
+ name = "Balcony";
+ id_tag = "beach_room_x"
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"LD" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/door/airlock/wood{
+ name = "Bathroom";
+ id_tag = "toilet1beach"
+ },
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"LN" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/carpet/blue,
+/area/virtual_domain/fullbright)
+"LR" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"LV" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"LY" = (
+/obj/effect/turf_decal/siding/blue{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Ma" = (
+/obj/machinery/vending/games,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"Mb" = (
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Md" = (
+/obj/structure/fluff/beach_umbrella/syndi,
+/obj/item/reagent_containers/cup/soda_cans/wellcheers{
+ pixel_y = -10;
+ pixel_x = -6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Mj" = (
+/obj/structure/table,
+/obj/item/weldingtool{
+ pixel_y = -7;
+ pixel_x = 4
+ },
+/obj/item/trash/can{
+ pixel_y = 10;
+ pixel_x = -5
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"Ml" = (
+/obj/machinery/washing_machine,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"Mo" = (
+/obj/machinery/door/airlock/wood{
+ name = "Docks"
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"Mr" = (
+/obj/structure/table/wood,
+/obj/item/stack/arcadeticket{
+ pixel_y = 6;
+ pixel_x = -7
+ },
+/obj/item/pen{
+ pixel_y = 5;
+ pixel_x = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Mx" = (
+/obj/structure/table/reinforced,
+/obj/machinery/cell_charger{
+ pixel_y = 13;
+ pixel_x = 21
+ },
+/obj/item/clothing/glasses/hud/health{
+ pixel_y = 1;
+ pixel_x = 18
+ },
+/obj/item/stack/medical/gauze{
+ pixel_x = -15;
+ pixel_y = 10
+ },
+/obj/item/storage/belt/medical{
+ pixel_y = 3;
+ pixel_x = -3
+ },
+/obj/machinery/light/directional/north,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"MA" = (
+/obj/effect/turf_decal/siding/dark_red/corner{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"MH" = (
+/obj/item/toy/seashell{
+ pixel_x = -7;
+ pixel_y = 5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"MO" = (
+/obj/structure/table/wood,
+/obj/machinery/recharger,
+/obj/item/reagent_containers/cup/glass/mug{
+ pixel_x = -12;
+ pixel_y = 9
+ },
+/obj/effect/spawner/random/bureaucracy/stamp{
+ pixel_y = 14;
+ pixel_x = 8
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"MR" = (
+/obj/effect/spawner/random/entertainment/arcade{
+ dir = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"MT" = (
+/turf/open/misc/beach/coast/corner{
+ dir = 8
+ },
+/area/virtual_domain/fullbright)
+"MV" = (
+/obj/item/radio/off{
+ pixel_y = 16;
+ pixel_x = -5
+ },
+/obj/item/storage/box/monkeycubes{
+ pixel_y = 10;
+ pixel_x = 4
+ },
+/obj/item/storage/toolbox/mechanical{
+ pixel_y = 2
+ },
+/obj/structure/table/glass,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"MX" = (
+/obj/effect/turf_decal/stripes/red/box,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"MZ" = (
+/obj/machinery/button/door/directional/north{
+ id = "beach_room_12";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Nc" = (
+/obj/item/tank/internals/anesthetic{
+ pixel_y = 4
+ },
+/obj/item/stack/medical/bone_gel{
+ pixel_y = 16;
+ pixel_x = -7
+ },
+/obj/item/clothing/mask/breath/medical{
+ pixel_y = 3;
+ pixel_x = 3
+ },
+/obj/structure/table/bronze,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"Ne" = (
+/obj/machinery/light/directional/east,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Nj" = (
+/obj/structure/fluff/beach_umbrella/cap,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Np" = (
+/obj/structure/chair/stool/bamboo{
+ dir = 4
+ },
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"Nt" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"NB" = (
+/obj/item/storage/box/fishing_hooks{
+ pixel_y = 14
+ },
+/obj/item/storage/box/fishing_lines{
+ pixel_y = 12;
+ pixel_x = 18
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"NC" = (
+/mob/living/basic/crab,
+/obj/effect/turf_decal/stripes/red/line{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"NH" = (
+/obj/structure/closet/crate/bin,
+/obj/item/trash/candy,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"NT" = (
+/obj/item/toy/seashell,
+/turf/open/misc/beach/coast,
+/area/virtual_domain/fullbright)
+"NU" = (
+/obj/machinery/vending/medical{
+ req_access = "201"
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"NZ" = (
+/obj/effect/turf_decal/sand,
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain/fullbright)
+"Of" = (
+/obj/item/reagent_containers/cup/soda_cans/space_mountain_wind{
+ pixel_x = -17;
+ pixel_y = 17
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Og" = (
+/obj/structure/table/bronze,
+/obj/item/reagent_containers/condiment/peppermill{
+ pixel_y = 12
+ },
+/obj/item/reagent_containers/condiment/saltshaker{
+ pixel_x = -5;
+ pixel_y = 9
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Ol" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/machinery/power/port_gen/pacman,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"Om" = (
+/obj/structure/bed/double,
+/obj/item/bedsheet/hop/double{
+ desc = "A blue bedsheet. Likely from the beach hotel.";
+ name = "blue bedsheet"
+ },
+/turf/open/floor/carpet/cyan,
+/area/virtual_domain)
+"Or" = (
+/obj/effect/turf_decal/siding/dark_red{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Oy" = (
+/mob/living/basic/crab,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"OA" = (
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"OK" = (
+/obj/item/storage/box/gloves{
+ pixel_y = 14;
+ pixel_x = 7
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"OM" = (
+/turf/open/floor/iron/stairs/old,
+/area/virtual_domain/fullbright)
+"OO" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 16;
+ pixel_x = 12
+ },
+/obj/structure/flora/coconuts,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"OV" = (
+/mob/living/basic/crab/kreb,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Po" = (
+/obj/structure/sink/kitchen/directional/east,
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"Pq" = (
+/obj/structure/table/bronze,
+/obj/item/reagent_containers/cup/rag{
+ pixel_y = 5
+ },
+/obj/item/reagent_containers/condiment/coconut_milk{
+ pixel_y = 14;
+ pixel_x = 5
+ },
+/obj/machinery/light/directional/east,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"PD" = (
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 9;
+ pixel_x = 6
+ },
+/obj/structure/railing{
+ dir = 10
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"PE" = (
+/obj/machinery/space_heater,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"PG" = (
+/obj/structure/table/bronze,
+/obj/item/food/grown/banana/bunch{
+ pixel_y = 10;
+ offset_at_init = 0
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"PH" = (
+/obj/item/toy/seashell{
+ pixel_x = 12;
+ pixel_y = 5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"PJ" = (
+/obj/item/cigbutt{
+ pixel_y = -11;
+ pixel_x = -15
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"PR" = (
+/obj/effect/turf_decal/siding/blue{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"PZ" = (
+/obj/structure/table/bronze,
+/obj/item/camera{
+ pixel_y = 12;
+ pixel_x = 6
+ },
+/obj/item/camera_film{
+ pixel_y = 4;
+ pixel_x = -2
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Qc" = (
+/obj/item/kirbyplants/organic/plant8{
+ pixel_y = 5
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Qj" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/iron/freezer,
+/area/virtual_domain)
+"Qk" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/button/door/directional/east{
+ id = "toilet2beach";
+ name = "restroom lock";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/structure/toilet{
+ pixel_y = 8
+ },
+/obj/structure/sink/directional/west,
+/obj/machinery/light/small/directional/west,
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"Qm" = (
+/obj/structure/sink/kitchen/directional/south,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Qq" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Qu" = (
+/obj/structure/tank_holder/extinguisher,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Qv" = (
+/obj/machinery/door/airlock/command/glass{
+ name = "Admin"
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/effect/mapping_helpers/airlock_note_placer{
+ note_info = "Dear IT: Please fix the fax machine"
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Qx" = (
+/obj/effect/spawner/random/entertainment/arcade{
+ dir = 4
+ },
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"QG" = (
+/obj/structure/railing/corner/end/flip{
+ dir = 4
+ },
+/obj/item/wrench{
+ pixel_y = -1;
+ pixel_x = 6
+ },
+/obj/item/storage/toolbox/fishing{
+ pixel_y = -8;
+ pixel_x = -3
+ },
+/obj/structure/railing/corner/end/flip{
+ dir = 4
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"QH" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/machinery/door/airlock/wood{
+ name = "Room 6";
+ id_tag = "beach_room_6"
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"QI" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"QN" = (
+/obj/item/cigbutt{
+ pixel_y = -6;
+ pixel_x = -12
+ },
+/obj/item/clothing/head/soft/black,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"QX" = (
+/obj/machinery/vending/boozeomat/all_access{
+ desc = "A technological marvel, supposedly able to mix just the mixture you'd like to drink the moment you ask for one. May not work for bartenders that don't have Nanotrasen bank accounts."
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"QY" = (
+/obj/structure/window/reinforced/spawner/directional/north,
+/obj/structure/window/reinforced/spawner/directional/west,
+/obj/structure/table/wood,
+/obj/item/storage/medkit/o2{
+ pixel_y = 4;
+ pixel_x = 1
+ },
+/obj/effect/turf_decal/siding/wood{
+ dir = 9
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"Rc" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 31
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Rd" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"Re" = (
+/obj/structure/table/wood,
+/obj/item/stack/arcadeticket{
+ pixel_y = 3;
+ pixel_x = -5
+ },
+/obj/item/reagent_containers/cup/soda_cans/pwr_game{
+ pixel_y = 12;
+ pixel_x = -8
+ },
+/obj/item/paper_bin/carbon{
+ pixel_y = 6;
+ pixel_x = 4
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Rf" = (
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Rk" = (
+/obj/structure/table/glass,
+/obj/machinery/fax{
+ fax_name = "Beach Hotel Fax";
+ name = "Beach Hotel's Fax Machine";
+ pixel_y = 8;
+ visible_to_network = 0
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Rs" = (
+/obj/machinery/door/airlock/wood{
+ name = "Garage"
+ },
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"Rw" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/obj/machinery/door/airlock/wood{
+ name = "Room 1"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Ry" = (
+/obj/structure/closet{
+ name = "Holding Cell Storage"
+ },
+/obj/item/taperecorder,
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Rz" = (
+/obj/item/kirbyplants/organic/plant21{
+ pixel_y = 3;
+ pixel_x = -6
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"RB" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"RF" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/closed/wall/mineral/wood,
+/area/virtual_domain/fullbright)
+"RJ" = (
+/obj/item/reagent_containers/cup/soda_cans/starkist{
+ pixel_y = 16;
+ pixel_x = 10
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"RM" = (
+/obj/effect/baseturf_helper/beach/water,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"RO" = (
+/obj/item/reagent_containers/cup/soda_cans/lemon_lime{
+ pixel_x = -12;
+ pixel_y = -7
+ },
+/obj/item/reagent_containers/cup/soda_cans/dr_gibb{
+ pixel_x = 13;
+ pixel_y = -7
+ },
+/obj/structure/fluff/beach_umbrella,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"RP" = (
+/obj/structure/table,
+/obj/item/book/manual/wiki/engineering_guide{
+ pixel_y = 7;
+ pixel_x = -6
+ },
+/obj/item/pen{
+ pixel_x = 7;
+ pixel_y = 6
+ },
+/obj/item/clothing/head/utility/welding{
+ pixel_x = -10;
+ pixel_y = -8
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"RS" = (
+/obj/structure/table/wood,
+/obj/item/food/donut/plain{
+ pixel_y = -2;
+ pixel_x = 14
+ },
+/obj/item/assembly/signaler{
+ pixel_x = -6;
+ pixel_y = -5
+ },
+/obj/effect/spawner/random/bureaucracy/folder{
+ pixel_y = 11;
+ pixel_x = 4
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Sb" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 19;
+ pixel_x = 10
+ },
+/obj/machinery/hydroponics/constructable,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Sc" = (
+/obj/structure/table/wood,
+/obj/item/storage/box/drinkingglasses{
+ pixel_y = 18;
+ pixel_x = -5
+ },
+/obj/item/reagent_containers/cup/glass/shaker{
+ pixel_y = 12;
+ pixel_x = -7
+ },
+/obj/item/clothing/head/hats/tophat{
+ pixel_y = 2;
+ pixel_x = 3
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Se" = (
+/obj/structure/table/wood,
+/obj/effect/spawner/random/entertainment/lighter,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Sf" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"So" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Sr" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/effect/decal/cleanable/dirt/dust,
+/obj/structure/rack,
+/obj/effect/spawner/random/maintenance/three,
+/obj/effect/decal/cleanable/cobweb,
+/obj/item/wheelchair,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"Su" = (
+/obj/machinery/door/airlock/wood{
+ name = "Room 4";
+ id_tag = "beach_room_4"
+ },
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Sx" = (
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"Sz" = (
+/obj/structure/chair/stool/bamboo{
+ dir = 1
+ },
+/obj/effect/turf_decal/siding/wood/corner,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"SJ" = (
+/obj/structure/rack,
+/obj/effect/turf_decal/sand,
+/obj/item/clothing/shoes/sandal{
+ pixel_y = 4;
+ pixel_x = 8
+ },
+/obj/item/clothing/shoes/sandal{
+ pixel_x = 4
+ },
+/obj/item/clothing/shoes/sandal{
+ pixel_y = -4
+ },
+/obj/item/clothing/shoes/sandal{
+ pixel_y = -7;
+ pixel_x = -3
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"SL" = (
+/obj/machinery/door/airlock/wood{
+ name = "Trash Disposal"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"SM" = (
+/obj/effect/turf_decal/siding/blue{
+ dir = 4
+ },
+/obj/structure/chair/plastic{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"SO" = (
+/obj/structure/table/bronze,
+/obj/structure/desk_bell{
+ pixel_x = 7;
+ pixel_y = 8
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"SR" = (
+/turf/closed/indestructible/binary,
+/area/virtual_domain/fullbright)
+"Ta" = (
+/obj/machinery/light/directional/south,
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"Tb" = (
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"Tq" = (
+/obj/machinery/light/small/directional/north,
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"Tr" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Tt" = (
+/obj/machinery/recharge_station,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Tw" = (
+/obj/effect/turf_decal/stripes/white/full,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Ty" = (
+/turf/open/floor/carpet,
+/area/virtual_domain/fullbright)
+"TB" = (
+/obj/effect/turf_decal/tile/dark_red/full,
+/obj/machinery/vending/cola/red,
+/turf/open/floor/iron/smooth_large,
+/area/virtual_domain/fullbright)
+"TC" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"TK" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_y = 1;
+ pixel_x = 7
+ },
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_x = -14
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"TM" = (
+/obj/effect/turf_decal/siding/blue/corner,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"TO" = (
+/obj/structure/closet/crate/bin,
+/obj/item/reagent_containers/syringe{
+ pixel_y = -4;
+ pixel_x = 3
+ },
+/obj/effect/spawner/random/trash/food_packaging,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"TR" = (
+/obj/effect/decal/cleanable/dirt,
+/turf/open/floor/plating,
+/area/virtual_domain)
+"TS" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/item/clothing/mask/breath/medical{
+ pixel_y = 7;
+ pixel_x = -9
+ },
+/obj/item/clothing/mask/breath/medical{
+ pixel_y = 4;
+ pixel_x = 3
+ },
+/obj/item/clothing/gloves/latex,
+/obj/structure/table/glass,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"TW" = (
+/obj/structure/table/bronze,
+/obj/item/clothing/suit/costume/hawaiian{
+ pixel_y = 7;
+ pixel_x = -3
+ },
+/obj/machinery/light/directional/west,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain/fullbright)
+"TY" = (
+/obj/machinery/door/airlock/medical/glass{
+ name = "Medbay Clinic"
+ },
+/obj/effect/turf_decal/siding/blue{
+ dir = 8
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"TZ" = (
+/obj/structure/fluff/beach_umbrella/science,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Ub" = (
+/obj/machinery/light/directional/west,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"Ud" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/item/cigbutt{
+ pixel_y = -9;
+ pixel_x = 13
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Uf" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/door/airlock/wood{
+ name = "Bathroom";
+ id_tag = "toilet2beach"
+ },
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"Ug" = (
+/obj/structure/chair/office{
+ dir = 4
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"Uk" = (
+/obj/machinery/vending/autodrobe/all_access,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Um" = (
+/obj/structure/closet/secure_closet/personal/cabinet,
+/obj/item/clothing/suit/jacket/miljacket,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Uy" = (
+/obj/machinery/door/airlock/medical/glass{
+ name = "Medbay Clinic"
+ },
+/obj/effect/turf_decal/siding/blue{
+ dir = 4
+ },
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"UE" = (
+/obj/effect/turf_decal/siding/wood,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"UI" = (
+/obj/machinery/door/airlock/wood{
+ name = "Janitorial"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"UJ" = (
+/obj/vehicle/ridden/atv{
+ dir = 4
+ },
+/obj/effect/decal/cleanable/oil,
+/turf/open/floor/iron/dark/herringbone,
+/area/virtual_domain)
+"UO" = (
+/obj/machinery/vending/cola/pwr_game,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"US" = (
+/obj/machinery/shower/directional/west,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"UW" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"UZ" = (
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = -8
+ },
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = 5
+ },
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = 1;
+ pixel_y = 7
+ },
+/obj/item/stack/sheet/mineral/sandstone{
+ pixel_x = -12;
+ pixel_y = 6
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Va" = (
+/obj/machinery/door/airlock/wood{
+ name = "Employees' Only"
+ },
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"Vs" = (
+/obj/structure/table/wood,
+/obj/item/pai_card{
+ desc = "A real Nanotrasen success, these personal AIs provide all of the companionship of an AI without any law related red-tape.";
+ name = "\improper Nanotrasen-brand personal AI device exhibit";
+ pixel_y = 3;
+ pixel_x = 10
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"VD" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"VI" = (
+/obj/machinery/vending/dinnerware,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"VK" = (
+/obj/machinery/door/airlock/wood/glass{
+ name = "Cabin"
+ },
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"VL" = (
+/turf/open/misc/beach/coast{
+ dir = 6
+ },
+/area/virtual_domain/fullbright)
+"We" = (
+/obj/structure/table/bronze,
+/obj/item/book/manual/wiki/barman_recipes{
+ pixel_x = 9;
+ pixel_y = 7;
+ name = "Tropical Mixing for Tropical Bartenders"
+ },
+/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{
+ pixel_y = 10;
+ pixel_x = -12
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Wg" = (
+/obj/structure/closet/crate/trashcart/filled,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"Wm" = (
+/obj/effect/landmark/bitrunning/curiosity_spawn,
+/turf/open/floor/iron/white/textured_large,
+/area/virtual_domain)
+"Ws" = (
+/obj/machinery/vending/cigarette/beach,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"WG" = (
+/obj/effect/turf_decal/siding/blue{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"WX" = (
+/obj/structure/marker_beacon/teal,
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Xe" = (
+/obj/structure/table/bronze,
+/obj/structure/sign/poster/random/directional/east,
+/obj/item/camera{
+ pixel_y = 5
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Xl" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 25
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Xt" = (
+/turf/open/floor/plastic,
+/area/virtual_domain)
+"Xu" = (
+/obj/effect/turf_decal/siding/blue{
+ dir = 8
+ },
+/obj/structure/chair/plastic{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Xx" = (
+/obj/machinery/door/airlock/wood/glass{
+ name = "Beach Access"
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"XJ" = (
+/obj/machinery/door/airlock/public/glass{
+ name = "Locker Room"
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"XO" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 25
+ },
+/obj/structure/chair/plastic{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"XP" = (
+/obj/structure/mop_bucket/janitorialcart{
+ dir = 8
+ },
+/obj/machinery/light/directional/south,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"XT" = (
+/obj/machinery/light/directional/west,
+/turf/open/floor/carpet/cyan,
+/area/virtual_domain)
+"XW" = (
+/obj/structure/fluff/beach_umbrella/syndi,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Yb" = (
+/obj/structure/sign/poster/contraband/pwr_game/directional/west,
+/turf/open/floor/eighties,
+/area/virtual_domain)
+"Yd" = (
+/obj/structure/flora/tree/palm/style_2{
+ pixel_y = 3;
+ pixel_x = -4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Yo" = (
+/turf/closed/wall/mineral/sandstone,
+/area/virtual_domain/fullbright)
+"Yr" = (
+/obj/item/reagent_containers/cup/watering_can{
+ pixel_y = 19;
+ pixel_x = -6
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Yz" = (
+/obj/item/trash/candy{
+ pixel_y = 9;
+ pixel_x = -9
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"YD" = (
+/obj/effect/turf_decal/sand,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"YI" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/button/door/directional/east{
+ id = "toilet1beach";
+ name = "restroom lock";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/structure/toilet{
+ pixel_y = 8
+ },
+/obj/structure/sink/directional/west,
+/obj/machinery/light/small/directional/west,
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"YM" = (
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander,
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"YN" = (
+/obj/item/toy/seashell{
+ pixel_x = 12;
+ pixel_y = -5
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"YP" = (
+/obj/structure/table/glass,
+/obj/item/paper{
+ pixel_y = 7;
+ pixel_x = 2
+ },
+/obj/item/screwdriver{
+ pixel_y = 13;
+ pixel_x = 3
+ },
+/obj/item/paper_bin/carbon{
+ pixel_y = 4;
+ pixel_x = -6
+ },
+/obj/effect/spawner/random/bureaucracy/pen{
+ pixel_x = 7
+ },
+/turf/open/floor/iron/dark/diagonal,
+/area/virtual_domain)
+"YR" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 10
+ },
+/obj/machinery/vending/cola/red,
+/turf/open/floor/wood/large,
+/area/virtual_domain/fullbright)
+"YW" = (
+/obj/structure/chair{
+ dir = 1
+ },
+/turf/open/floor/iron/dark/textured_large,
+/area/virtual_domain)
+"YZ" = (
+/obj/structure/railing/corner/end/flip{
+ dir = 4
+ },
+/turf/open/floor/wood/parquet,
+/area/virtual_domain)
+"Zd" = (
+/obj/structure/railing{
+ dir = 8
+ },
+/turf/open/floor/wood,
+/area/virtual_domain/fullbright)
+"Zj" = (
+/obj/structure/flora/tree/palm{
+ pixel_y = 16
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Zn" = (
+/obj/item/reagent_containers/cup/soda_cans/dr_gibb{
+ pixel_x = -9;
+ pixel_y = -9
+ },
+/obj/structure/fluff/beach_umbrella/engine,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"Zp" = (
+/obj/structure/dresser,
+/turf/open/floor/wood,
+/area/virtual_domain)
+"Zs" = (
+/obj/machinery/door/poddoor/shutters{
+ id = "BeachBoats"
+ },
+/turf/open/water/beach,
+/area/virtual_domain/fullbright)
+"Zy" = (
+/obj/structure/sign/chalkboard_menu{
+ pixel_y = 32
+ },
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"Zz" = (
+/obj/effect/turf_decal/siding/wood/corner{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ZB" = (
+/obj/effect/turf_decal/sand,
+/obj/machinery/button/door/directional/east{
+ id = "toilet3beach";
+ name = "restroom lock";
+ normaldoorcontrol = 1;
+ specialfunctions = 4
+ },
+/obj/structure/toilet{
+ pixel_y = 8
+ },
+/obj/structure/sink/directional/west,
+/obj/item/cigbutt{
+ pixel_y = -7;
+ pixel_x = -13
+ },
+/obj/machinery/light/small/directional/west,
+/obj/effect/baseturf_helper/virtual_domain,
+/turf/open/floor/iron/white,
+/area/virtual_domain)
+"ZE" = (
+/obj/structure/table/bronze,
+/turf/open/floor/carpet,
+/area/virtual_domain)
+"ZH" = (
+/obj/item/kirbyplants/organic/plant24{
+ pixel_x = 7;
+ pixel_y = 10
+ },
+/obj/item/reagent_containers/cup/watering_can{
+ pixel_x = -3;
+ pixel_y = 15
+ },
+/obj/structure/table,
+/turf/open/floor/wood/large,
+/area/virtual_domain)
+"ZI" = (
+/obj/effect/baseturf_helper/beach/sand,
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ZV" = (
+/obj/structure/chair/plastic,
+/obj/item/pai_card{
+ desc = "A real Nanotrasen success, these personal AIs provide all of the companionship of an AI without any law related red-tape.";
+ name = "\improper Nanotrasen-brand personal AI device exhibit";
+ pixel_y = 3;
+ pixel_x = -1
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+"ZX" = (
+/obj/structure/table/bronze,
+/obj/item/storage/toolbox/fishing{
+ pixel_y = 2
+ },
+/turf/open/floor/wood,
+/area/virtual_domain)
+"ZY" = (
+/obj/effect/turf_decal/siding/blue/corner{
+ dir = 4
+ },
+/turf/open/misc/beach/sand,
+/area/virtual_domain/fullbright)
+
+(1,1,1) = {"
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(2,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(3,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(4,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(5,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(6,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(7,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(8,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+LR
+Bf
+Bf
+Bf
+qa
+cO
+LR
+Bf
+Bf
+Bf
+HH
+Bf
+Bf
+Bf
+qa
+cO
+LR
+Bf
+Bf
+Bf
+qa
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(9,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+Jd
+vF
+Zd
+io
+tw
+cO
+Jd
+vF
+Zd
+io
+Jp
+vF
+Zd
+io
+tw
+cO
+Jd
+vF
+Zd
+PD
+tw
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(10,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Lm
+AZ
+AZ
+eK
+cO
+eK
+Lm
+AZ
+AZ
+eK
+Lm
+AZ
+AZ
+eK
+cO
+eK
+Lm
+AZ
+AZ
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(11,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+CH
+uY
+PE
+Bq
+eK
+Bq
+MZ
+gw
+PE
+Bq
+bE
+uY
+oE
+Bq
+eK
+Bq
+iQ
+gw
+jp
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(12,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+cB
+Rd
+bE
+db
+Mb
+rI
+bE
+cW
+aQ
+Bq
+jw
+Rd
+bE
+Su
+Mb
+EP
+bE
+cW
+La
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(13,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+yI
+gK
+rE
+Bq
+Mb
+Bq
+yI
+ch
+Xe
+Bq
+wO
+gK
+rw
+Bq
+Mb
+Bq
+Je
+Om
+Zp
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(14,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Bq
+Bq
+Bq
+Bq
+pv
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(15,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+vF
+nk
+bE
+XT
+PE
+Bq
+Mb
+Mb
+yg
+Mb
+Mb
+Mb
+Mb
+yg
+Mb
+Mb
+Mb
+Mb
+yg
+gH
+Bq
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(16,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+aw
+AZ
+Go
+cW
+bE
+DU
+Mb
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(17,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+xR
+AZ
+Zp
+Om
+yQ
+Bq
+Mb
+Bq
+cr
+uY
+dH
+Bq
+Um
+gw
+gf
+Bq
+pv
+Bq
+lc
+uY
+pq
+eK
+cO
+eH
+EI
+EI
+EI
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(18,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Bq
+Gm
+Bq
+Bq
+Mb
+HO
+bE
+Rd
+La
+Bq
+Ae
+cW
+bE
+sW
+Mb
+Bk
+bE
+Rd
+La
+eK
+eH
+tk
+qB
+ka
+MH
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+"}
+(19,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+vF
+dW
+bE
+GX
+dH
+Bq
+Mb
+Bq
+ik
+gK
+ZX
+Bq
+yI
+Om
+dS
+Bq
+Mb
+Bq
+ik
+gK
+ZX
+eK
+tk
+CV
+wZ
+QI
+gI
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eZ
+SR
+"}
+(20,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+KZ
+AZ
+pz
+Rd
+bE
+JJ
+Mb
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+eK
+BI
+ka
+mP
+rB
+bD
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(21,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+xR
+AZ
+BW
+gK
+st
+Bq
+Mb
+Mb
+yg
+Mb
+Bq
+xg
+Bq
+Mb
+Mb
+Mb
+Mb
+yg
+Mb
+Mb
+Xx
+TC
+JN
+ka
+ka
+ka
+ka
+ka
+rD
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(22,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Bq
+Bq
+Bq
+Bq
+Mb
+Bq
+Bq
+cH
+Bq
+Bq
+Bq
+QH
+Bq
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+eK
+NB
+rD
+ka
+ka
+ka
+BI
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(23,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+eK
+Bq
+Fk
+Yr
+wz
+Bq
+Mb
+Bq
+Ka
+gw
+PE
+Bq
+CU
+uY
+bE
+Bq
+Mb
+CS
+qb
+gw
+pJ
+eK
+ka
+ka
+eK
+Rw
+eK
+eK
+eK
+Ej
+nc
+EI
+EI
+EI
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(24,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+tf
+GK
+XP
+Bq
+pv
+Bq
+bE
+cW
+La
+Bq
+PE
+Rd
+La
+Bq
+Mb
+Bq
+wx
+cW
+La
+eK
+Sf
+eK
+Bq
+Mb
+Dx
+Mb
+Bq
+eK
+Ej
+ka
+ka
+ka
+nc
+EI
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(25,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+IX
+Mb
+Mb
+Bq
+pE
+Bq
+ik
+Om
+gc
+Bq
+yI
+gK
+ZX
+Bq
+pE
+Bq
+Zp
+Om
+eJ
+Bq
+eK
+Bq
+jb
+dY
+lI
+Aq
+MR
+Bq
+eK
+th
+ka
+ka
+ka
+ka
+nc
+EI
+EI
+EI
+EI
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(26,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+ow
+Bq
+UI
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+Mb
+Bq
+Bq
+Bq
+Bq
+Bq
+BV
+Mb
+Mb
+ho
+ho
+ho
+Mb
+Rz
+AZ
+ka
+sz
+ka
+ka
+yy
+ka
+ka
+ka
+ka
+ka
+nc
+EI
+ij
+cO
+cO
+cO
+cO
+eH
+EI
+EI
+EI
+EI
+EI
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(27,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+LR
+Bf
+eK
+Bq
+Bq
+tI
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+JG
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+JG
+Mb
+dj
+Mb
+Mb
+IS
+gN
+Al
+Mb
+Mb
+Mb
+xw
+AZ
+ka
+ka
+ka
+Md
+BB
+ka
+ka
+ka
+rD
+ka
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+oa
+sz
+th
+ka
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(28,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+LR
+lS
+wN
+xJ
+SL
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+Mb
+dj
+Mb
+Mb
+So
+EY
+UW
+Mb
+Mb
+ZH
+AZ
+AZ
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+DR
+ka
+ka
+BD
+ka
+sz
+nc
+EI
+EI
+EI
+tk
+ka
+ka
+ka
+ka
+ka
+sz
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(29,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+Jd
+Yz
+xJ
+eK
+Bq
+Bq
+yG
+yG
+Bq
+Qv
+Bq
+Bq
+Bq
+Bq
+Bq
+DP
+TY
+DP
+Bq
+Bq
+Bq
+Bq
+Bq
+Bq
+pv
+LV
+II
+Qq
+Mb
+Mb
+AZ
+AZ
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+TZ
+oC
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+Oy
+ka
+Dg
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(30,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+Jd
+mV
+xJ
+eK
+Jb
+zS
+lW
+lW
+PJ
+lW
+Qu
+Bq
+lF
+bx
+jL
+qH
+gP
+FB
+NU
+Bq
+CQ
+CQ
+Bq
+cK
+Mb
+dA
+Mb
+Mb
+Mb
+Mb
+eK
+sR
+JN
+de
+JN
+ka
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+eK
+AZ
+AZ
+eK
+ka
+eK
+AZ
+AZ
+eK
+uC
+ka
+ka
+Nj
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(31,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+Ud
+bT
+Wg
+eK
+vx
+lW
+Ug
+aY
+Ug
+lW
+YP
+Gq
+zm
+Wm
+gP
+gP
+gP
+gP
+gP
+Va
+Xt
+Xt
+Bq
+Cw
+uY
+zL
+uY
+uY
+uY
+uY
+VK
+Ty
+JN
+JN
+JN
+ka
+ka
+th
+ka
+ka
+ka
+ka
+eK
+Bq
+Qx
+Qx
+Bq
+AZ
+Bq
+BM
+gs
+Bq
+eK
+rD
+ka
+DR
+LN
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(32,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+Jc
+If
+Wg
+eK
+Ks
+lW
+Ho
+RS
+Ld
+lW
+Rk
+Bq
+Mx
+gP
+gP
+up
+gP
+gP
+TO
+Bq
+Ml
+Xt
+Bq
+uY
+Rd
+ZE
+uY
+uY
+uY
+Ta
+eK
+Ty
+Ty
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+eK
+UO
+en
+ty
+Yb
+en
+HR
+gi
+Ai
+Ga
+eK
+ka
+ka
+ka
+nR
+ka
+gL
+VL
+JH
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(33,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+Jc
+IF
+eK
+HK
+lW
+qR
+MO
+pX
+PJ
+rG
+Bq
+CP
+HT
+gP
+aD
+OK
+gP
+Ay
+Bq
+Ml
+Xt
+Bq
+Cw
+uY
+iF
+uY
+uY
+uY
+uY
+VK
+Ty
+Ty
+Ty
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+eK
+Bq
+Ma
+xx
+en
+pV
+Nt
+dB
+Mr
+Mb
+AZ
+ka
+ka
+ka
+rD
+ka
+cE
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(34,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Bq
+lW
+lW
+KT
+DA
+In
+Bq
+eK
+AZ
+Bq
+gP
+gP
+gP
+Bq
+Bq
+Bq
+FE
+Xt
+Bq
+PG
+Mb
+oQ
+Mb
+Mb
+Mb
+eK
+eK
+wf
+Ty
+Ty
+Ty
+ka
+ka
+ka
+rD
+ka
+ka
+sz
+ka
+eK
+AZ
+Bq
+wT
+wT
+Ag
+Mb
+Vs
+Mb
+eK
+ka
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(35,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+lW
+rW
+Ry
+MV
+Bq
+eK
+zO
+bb
+eK
+Uy
+Bq
+ee
+Bq
+Ml
+Po
+gB
+Xt
+Bq
+Bq
+Mb
+IS
+gN
+Al
+Mb
+AZ
+wf
+SJ
+JN
+Ty
+Ty
+Ty
+ka
+ka
+ka
+ka
+ka
+ka
+th
+ka
+JN
+eK
+AZ
+AZ
+Bq
+Mb
+Re
+fg
+eK
+as
+ka
+ka
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(36,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+lU
+yG
+yG
+Bq
+eK
+IJ
+xJ
+xJ
+xJ
+xJ
+eK
+AZ
+Bq
+Ml
+AK
+Xt
+Xt
+Xt
+Va
+Mb
+So
+sh
+UW
+Mb
+AZ
+AZ
+SJ
+JN
+JN
+Ty
+Ty
+Ty
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+JN
+eK
+mx
+AZ
+eK
+Ib
+JN
+ka
+ka
+ka
+Oy
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(37,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+GI
+GI
+YW
+eK
+cO
+TS
+mV
+xJ
+xJ
+xJ
+tw
+cO
+eK
+Bq
+yc
+yc
+yc
+Bq
+Bq
+Bq
+LV
+Ne
+Qq
+Mb
+Qc
+AZ
+SJ
+JN
+JN
+ka
+Ty
+Ty
+Ty
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+JN
+ka
+ka
+ta
+YD
+dp
+ct
+ka
+ka
+ka
+JN
+ka
+ka
+ka
+NT
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+SR
+"}
+(38,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+lx
+uI
+ba
+YW
+lx
+cO
+bp
+rn
+zn
+Nc
+yB
+pC
+cO
+cO
+eK
+Bq
+Bq
+Bq
+Bq
+Sr
+Bq
+kD
+Bq
+Mb
+Mb
+Tt
+AZ
+Er
+JN
+rD
+ka
+ka
+Ty
+Ty
+Ty
+ka
+ka
+ka
+rD
+ka
+JN
+JN
+JN
+ka
+JN
+ka
+JN
+ka
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(39,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Bq
+zp
+Bq
+eK
+cO
+Jc
+fe
+du
+AG
+pC
+cO
+cO
+cO
+eK
+hT
+lh
+TR
+jm
+TR
+TR
+TR
+Bq
+Ws
+KJ
+fg
+eK
+JN
+ka
+ka
+ka
+ka
+ka
+Ty
+Ty
+Ty
+ka
+ka
+ka
+JN
+JN
+JN
+ka
+JN
+ka
+JN
+JN
+ka
+ka
+ka
+JN
+ka
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+SR
+"}
+(40,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+eK
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+TR
+TR
+HV
+TR
+TR
+eP
+KI
+Bq
+eK
+eK
+eK
+ka
+ka
+Xl
+ka
+sz
+ka
+ka
+Gp
+Ty
+Ty
+JN
+JN
+JN
+JN
+JN
+ka
+ka
+JN
+JN
+ka
+ka
+JN
+ka
+ka
+ka
+ka
+ka
+RO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(41,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+Ol
+TR
+TR
+DG
+Gx
+Bq
+eK
+eK
+rD
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+th
+ka
+JN
+JN
+JN
+JN
+JN
+JN
+ka
+NH
+eK
+eK
+AZ
+AZ
+eK
+eK
+ky
+ka
+JN
+ka
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(42,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+eK
+Bq
+ce
+cC
+Bq
+eK
+mJ
+ka
+ka
+ka
+Yo
+Yo
+Yo
+ka
+ka
+ka
+ka
+ka
+rD
+JN
+JN
+JN
+ka
+ka
+JN
+JN
+yJ
+eK
+QX
+hA
+Ac
+Sc
+eK
+YR
+ka
+ka
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+SR
+"}
+(43,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eK
+eK
+eK
+eK
+bY
+Et
+ka
+ra
+Yo
+Yo
+bX
+Yo
+Yo
+sz
+ka
+ka
+ka
+ka
+JN
+JN
+jr
+ka
+ka
+ka
+JN
+eK
+Bq
+Qm
+Mb
+Mb
+Mb
+jK
+aA
+JF
+ka
+ka
+FO
+ka
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(44,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+UZ
+Yo
+bX
+hh
+bX
+Yo
+sz
+ka
+lA
+US
+IA
+JN
+JN
+ka
+ka
+ka
+ka
+JN
+mL
+Mb
+GK
+Se
+vU
+Mb
+rR
+yN
+UE
+ka
+ka
+Bx
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(45,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+zq
+Yo
+bX
+kN
+bX
+ev
+ka
+ka
+NZ
+NZ
+eK
+JN
+JN
+ka
+ka
+ka
+ka
+Sb
+eK
+Zy
+lJ
+tM
+Hp
+Mb
+rR
+yN
+UE
+ka
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+SR
+"}
+(46,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+Bc
+Yo
+sl
+bX
+bX
+Yo
+sz
+ka
+NZ
+YI
+LD
+JN
+JN
+rD
+ka
+ka
+ka
+eK
+eK
+pv
+uD
+DT
+Mb
+Mb
+We
+yN
+UE
+ka
+ka
+Eb
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(47,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+Yo
+Yo
+bX
+Yo
+Yo
+sz
+ka
+NZ
+kI
+eK
+JN
+JN
+ka
+ka
+ka
+GQ
+eK
+VI
+Mb
+si
+Co
+Mb
+Fp
+Pq
+Sz
+Fx
+ka
+ka
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(48,1,1) = {"
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+Yo
+Yo
+Yo
+ka
+ka
+ka
+NZ
+Qk
+Uf
+JN
+JN
+ka
+ka
+ka
+ka
+AZ
+HE
+Mb
+jW
+Mb
+Mb
+dl
+eK
+Fx
+ka
+ka
+ka
+th
+Zn
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(49,1,1) = {"
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+sz
+ka
+ka
+ka
+th
+ka
+eK
+kI
+kI
+eK
+JN
+JN
+ka
+ka
+ka
+ka
+AZ
+fL
+Mb
+Mb
+Mb
+hZ
+rR
+UE
+ka
+ka
+ka
+ka
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(50,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+ka
+NZ
+ZB
+sa
+JN
+JN
+ka
+th
+ka
+ka
+AZ
+xT
+Mb
+Mb
+Og
+SO
+Np
+Fx
+ka
+as
+ka
+ka
+ka
+sC
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+SR
+"}
+(51,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+th
+ka
+ka
+ka
+ka
+ka
+ka
+eK
+eK
+eK
+JN
+JN
+ka
+ka
+rD
+ka
+eK
+xT
+Do
+KL
+tX
+Np
+Fx
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(52,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+ka
+RM
+ka
+ka
+ka
+eK
+rK
+JN
+JN
+JN
+ka
+ka
+ka
+ka
+eK
+eK
+AZ
+AZ
+eK
+cc
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(53,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+ka
+ZI
+ka
+ka
+as
+ka
+cg
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+os
+ka
+eM
+ka
+rD
+ka
+ka
+ka
+ka
+ka
+rj
+ka
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(54,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+tW
+ka
+ka
+th
+ka
+ka
+ka
+ka
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+th
+ka
+BI
+ka
+ka
+as
+ka
+ka
+ka
+ka
+ka
+ka
+xk
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+SR
+"}
+(55,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+Rc
+Of
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+sz
+ka
+ka
+ka
+ka
+ka
+QY
+fY
+gA
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(56,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+JN
+JN
+JN
+lk
+Or
+uX
+qZ
+ka
+ka
+ka
+rD
+ka
+ka
+ka
+iy
+ut
+OM
+ka
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(57,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+XO
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+as
+JN
+JN
+kL
+TB
+ze
+mv
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+th
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(58,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ET
+tW
+ka
+XW
+CA
+ka
+ka
+ka
+JN
+JN
+IL
+wH
+ze
+mv
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+rD
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+SR
+"}
+(59,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+bY
+CR
+ka
+zH
+LN
+DR
+ka
+ka
+ka
+JN
+JN
+IL
+eh
+ze
+mv
+ka
+rD
+ka
+ka
+th
+ka
+ka
+th
+ka
+ka
+Oy
+ka
+ka
+BU
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(60,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+cO
+wb
+bY
+MT
+ka
+ka
+ka
+ka
+ka
+JN
+JN
+uz
+It
+It
+MA
+ka
+ka
+ka
+ka
+ka
+ka
+tW
+tW
+tW
+tW
+ka
+ka
+ka
+il
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(61,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+TZ
+RJ
+ka
+JN
+JN
+JN
+Yd
+ka
+ka
+ka
+ka
+dD
+ka
+ka
+ka
+TM
+SM
+SM
+SM
+SM
+LY
+ZY
+ka
+cp
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+cO
+SR
+"}
+(62,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+FX
+FX
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+sz
+ZV
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(63,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+ka
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+OO
+ka
+FO
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+ka
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(64,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+ka
+JN
+JN
+ka
+mi
+ka
+ka
+ka
+ka
+ka
+ka
+FO
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+th
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+cO
+SR
+"}
+(65,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+rD
+ka
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+rD
+ka
+JN
+ka
+ka
+ka
+dG
+ka
+Dg
+ka
+ka
+ka
+PR
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(66,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+ka
+JN
+JN
+JN
+JN
+JN
+ka
+ka
+ka
+fI
+jP
+fI
+lP
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+Oy
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(67,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+th
+ka
+ka
+JN
+JN
+JN
+ka
+JN
+JN
+ka
+JN
+GD
+ew
+fI
+sO
+dG
+Tw
+Tw
+Tw
+Tw
+Tw
+PR
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(68,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+Ko
+ka
+ka
+rD
+JN
+JN
+ka
+yz
+ka
+ka
+ka
+Gw
+fI
+jP
+hu
+lP
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(69,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+tk
+ka
+ka
+Dt
+ka
+JN
+JN
+ka
+ka
+ka
+ka
+JN
+ka
+ka
+th
+ka
+ka
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+WX
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(70,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+JH
+cO
+cO
+eH
+EI
+rl
+ka
+ka
+ka
+ka
+ka
+JN
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+ka
+rD
+FO
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+al
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(71,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+tk
+th
+ka
+ka
+eK
+eK
+eK
+eK
+qc
+JN
+JN
+ka
+ka
+ka
+ka
+ka
+JN
+ka
+FO
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+xj
+ij
+cO
+cO
+JH
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(72,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+Oy
+eK
+eK
+Bq
+ro
+ro
+fg
+eK
+oZ
+tQ
+ka
+ka
+eO
+PZ
+ka
+ka
+ka
+FO
+FO
+dG
+ka
+ka
+ka
+ka
+ka
+PR
+ka
+ka
+nc
+ij
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(73,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+tk
+ka
+eK
+Bq
+ro
+Ub
+Sx
+Sx
+Sx
+XJ
+bK
+ii
+tQ
+ka
+pj
+fH
+ka
+ka
+ka
+ka
+ka
+mW
+Xu
+Xu
+Xu
+Xu
+WG
+lz
+ka
+iP
+ka
+lG
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(74,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+tk
+ka
+ka
+eK
+ro
+Sx
+Sx
+Sx
+Sx
+Sx
+XJ
+bK
+bK
+TC
+ka
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+th
+iU
+iU
+iU
+iU
+ka
+ka
+ka
+hB
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(75,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+sz
+ka
+ka
+eK
+Bq
+DS
+Bq
+Bq
+ro
+Sx
+eK
+bK
+bK
+TC
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+ka
+rD
+ka
+FO
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(76,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+eH
+tk
+ka
+sz
+JN
+eK
+KH
+uu
+KH
+Bq
+ro
+Sx
+TW
+bK
+bK
+TC
+ka
+ka
+th
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+th
+ka
+ka
+ka
+gC
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(77,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+eK
+Rs
+Bq
+Bq
+uu
+uu
+Bq
+Bq
+Sx
+TK
+bK
+bK
+TC
+ka
+ka
+ka
+tW
+tW
+tW
+ka
+tW
+tW
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+FO
+ka
+dX
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(78,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+eK
+jV
+dv
+Bq
+KH
+uu
+Qj
+Bq
+Sx
+sI
+bK
+bK
+TC
+ka
+ka
+ka
+tW
+tW
+tW
+ka
+tW
+tW
+ka
+ka
+ka
+ka
+ka
+sR
+ka
+Jv
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(79,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+th
+ka
+eK
+Tq
+hD
+Bq
+Bq
+xO
+uu
+Bq
+Bq
+zg
+bK
+vM
+VD
+ka
+ka
+rD
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+tW
+ka
+ka
+ka
+Oy
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(80,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+eK
+Bz
+Tb
+UJ
+Bq
+aE
+uu
+KH
+Bq
+RF
+YD
+VD
+ka
+ka
+ka
+ka
+ka
+Rf
+Tr
+Tr
+Tr
+Zz
+ka
+ka
+FO
+uH
+xP
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+"}
+(81,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+eK
+eK
+jV
+ke
+Bq
+aE
+uu
+KH
+eK
+GY
+ka
+ka
+ka
+ka
+th
+ka
+Rf
+zK
+OA
+OA
+OA
+RB
+Zz
+Oy
+oJ
+iU
+ka
+ka
+ka
+YN
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+"}
+(82,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+sz
+AX
+eK
+IG
+IG
+eK
+Bq
+KH
+Bq
+eK
+wI
+ka
+ka
+ka
+ka
+ka
+ka
+rz
+jq
+OA
+OA
+OA
+OA
+ob
+ka
+ka
+ka
+ka
+Zj
+rD
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(83,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+ka
+ka
+ka
+ka
+eK
+eK
+eK
+kJ
+ka
+OV
+ka
+ka
+ka
+ka
+ka
+rQ
+ww
+OA
+OA
+OA
+OA
+py
+ka
+Dg
+ka
+ka
+ka
+ka
+cE
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(84,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+ka
+ka
+ka
+ka
+ka
+sR
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+KP
+eK
+eK
+eK
+eK
+eK
+eK
+eK
+Uk
+ka
+ka
+ka
+ka
+gL
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(85,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+Oy
+ka
+ka
+ka
+ka
+ka
+ka
+tW
+tW
+ka
+tW
+tW
+Rf
+eK
+Bq
+RP
+YM
+Ub
+Mj
+sV
+fg
+eK
+ka
+ka
+gL
+bY
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(86,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+th
+ka
+NZ
+NZ
+eK
+ka
+ka
+ka
+ka
+ka
+ka
+ka
+rz
+Mo
+Sx
+jn
+YZ
+YZ
+jn
+YZ
+QG
+Bq
+eK
+bY
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(87,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+ka
+NZ
+EA
+xe
+ka
+ka
+ef
+ef
+ef
+ef
+NC
+ta
+eK
+DL
+Dq
+Dq
+Dq
+Dq
+Dq
+KS
+QN
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(88,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+eK
+eK
+eK
+ka
+oq
+ka
+ka
+ka
+ka
+ka
+ka
+eK
+Bq
+Aj
+Aj
+Aj
+Aj
+Aj
+Hd
+hM
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(89,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+PH
+ka
+ka
+aZ
+iY
+ka
+ka
+ka
+MX
+ka
+JU
+eK
+fJ
+og
+HP
+HP
+HP
+HP
+wC
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(90,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+oa
+ka
+ka
+Oy
+ka
+ka
+ka
+ka
+nX
+gL
+Jw
+VL
+eK
+HI
+EQ
+HP
+HP
+HP
+HP
+Bq
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(91,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+MT
+gV
+ka
+ka
+fv
+gL
+bY
+bY
+VL
+cO
+cO
+eK
+eK
+Zs
+Iw
+Iw
+Iw
+eK
+eK
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(92,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+wb
+bY
+bY
+bY
+bY
+VL
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(93,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(94,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(95,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(96,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(97,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+cO
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
+(98,1,1) = {"
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+SR
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+ot
+"}
diff --git a/_maps/virtual_domains/psyker_shuffle.dmm b/_maps/virtual_domains/psyker_shuffle.dmm
index c744cecf0b43..d792c9382f21 100644
--- a/_maps/virtual_domains/psyker_shuffle.dmm
+++ b/_maps/virtual_domains/psyker_shuffle.dmm
@@ -246,7 +246,7 @@ Y
Q
Q
Q
-Q
+i
Y
o
o
diff --git a/bun.lock b/bun.lock
index d234ff9912a0..761ebb964bd3 100644
--- a/bun.lock
+++ b/bun.lock
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
+ "configVersion": 0,
"workspaces": {
"": {
"devDependencies": {
diff --git a/code/__DEFINES/_flags.dm b/code/__DEFINES/_flags.dm
index b1abfc0b54fe..298018a99a80 100644
--- a/code/__DEFINES/_flags.dm
+++ b/code/__DEFINES/_flags.dm
@@ -99,42 +99,58 @@ GLOBAL_LIST_INIT(bitflags, list(1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 204
#define IS_SOLID (1<<6)
/// This turf will never be cleared away by other objects on Initialize.
#define NO_CLEARING (1<<7)
+/// This atom is a pseudo-floor that blocks map generation's checkPlaceAtom() from placing things like trees ontop of it.
+#define TURF_BLOCKS_POPULATE_TERRAIN_FLORAFEATURES (1<<8)
////////////////Area flags\\\\\\\\\\\\\\
/// If it's a valid territory for cult summoning or the CRAB-17 phone to spawn
#define VALID_TERRITORY (1<<0)
/// If blobs can spawn there and if it counts towards their score.
#define BLOBS_ALLOWED (1<<1)
-/// If mining tunnel generation is allowed in this area
-#define CAVES_ALLOWED (1<<2)
-/// If flora are allowed to spawn in this area randomly through tunnel generation
-#define FLORA_ALLOWED (1<<3)
-/// If mobs can be spawned by natural random generation
-#define MOB_SPAWN_ALLOWED (1<<4)
-/// If megafauna can be spawned by natural random generation
-#define MEGAFAUNA_SPAWN_ALLOWED (1<<5)
/// Are you forbidden from teleporting to the area? (centcom, mobs, wizard, hand teleporter)
-#define NOTELEPORT (1<<6)
+#define NOTELEPORT (1<<2)
/// Hides area from player Teleport function.
-#define HIDDEN_AREA (1<<7)
-/// If false, loading multiple maps with this area type will create multiple instances.
-#define UNIQUE_AREA (1<<8)
+#define HIDDEN_AREA (1<<3)
/// If people are allowed to suicide in it. Mostly for OOC stuff like minigames
-#define BLOCK_SUICIDE (1<<9)
+#define BLOCK_SUICIDE (1<<5)
/// If set, this area will be innately traversable by Xenobiology camera consoles.
-#define XENOBIOLOGY_COMPATIBLE (1<<10)
+#define XENOBIOLOGY_COMPATIBLE (1<<6)
/// If blood cultists can draw runes or build structures on this AREA.
-#define CULT_PERMITTED (1<<11)
-/// If engravings are persistent in this area
-#define PERSISTENT_ENGRAVINGS (1<<12)
+#define CULT_PERMITTED (1<<7)
/// Mobs that die in this area don't produce a dead chat message
-#define NO_DEATH_MESSAGE (1<<13)
+#define NO_DEATH_MESSAGE (1<<8)
/// This area should have extra shielding from certain event effects
-#define EVENT_PROTECTED (1<<14)
-/// This area does not allow virtual entities to enter.
-#define VIRTUAL_SAFE_AREA (1<<16)
+#define EVENT_PROTECTED (1<<9)
+/// This Area Doesn't have Flood or Bomb Admin Messages, but will still log
+#define QUIET_LOGS (1<<10)
+/// This area does not allow the Binary channel
+#define BINARY_JAMMING (1<<11)
+/// This area prevents Bag of Holding rifts from being opened.
+#define NO_BOH (1<<12)
/// This area prevents fishing from removing unique/limited loot from sources that're also used outside of it.
-#define UNLIMITED_FISHING (1<<19)
+#define UNLIMITED_FISHING (1<<13)
+/// This area is prevented from having gravity (ie. space, nearstation, or outside solars)
+#define NO_GRAVITY (1<<14)
+/// This area can be teleported in, but -only- to locations within that same area.
+#define LOCAL_TELEPORT (1<<15)
+
+////////////////Area Mapping Flags\\\\\\\\\\\\\\
+/// If false, loading multiple maps with this area type will create multiple instances.
+#define UNIQUE_AREA (1<<0)
+/// If mining tunnel generation is allowed in this area
+#define CAVES_ALLOWED (1<<1)
+/// If flora are allowed to spawn in this area randomly through tunnel generation
+#define FLORA_ALLOWED (1<<2)
+/// If mobs can be spawned by natural random generation
+#define MOB_SPAWN_ALLOWED (1<<3)
+/// If megafauna can be spawned by natural random generation
+#define MEGAFAUNA_SPAWN_ALLOWED (1<<4)
+/// If engravings are persistent in this area
+#define PERSISTENT_ENGRAVINGS (1<<5)
+/// This is a virtual/bitrunning area
+#define VIRTUAL_AREA (1<<6)
+/// This area does not allow virtual entities to enter.
+#define VIRTUAL_SAFE_AREA (1<<7)
/*
These defines are used specifically with the atom/pass_flags bitmask
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index b784f5de90b6..de4123eaff0c 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -222,8 +222,11 @@ GLOBAL_LIST_INIT(ai_employers, list(
//Tells whether or not someone is a space ninja
#define IS_SPACE_NINJA(mob) (mob?.mind?.has_antag_datum(/datum/antagonist/ninja))
+// NON-MODULE CHANGE: original IS_HERETIC check wont be ported as it's error-prone, GET_HERETIC is therefore a copy
/// Checks if the given mob is a heretic.
#define IS_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
+/// Checks if the given mob is a heretic and is guaranteed to return the datum if possible - added in order to satisfy compatibility with other PRs
+#define GET_HERETIC(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic))
/// Check if the given mob is a heretic monster.
#define IS_HERETIC_MONSTER(mob) (mob.mind?.has_antag_datum(/datum/antagonist/heretic_monster))
/// Check if the given mob is a lunatic
diff --git a/code/__DEFINES/bitrunning.dm b/code/__DEFINES/bitrunning.dm
index 900182eb43d7..379a302fac22 100644
--- a/code/__DEFINES/bitrunning.dm
+++ b/code/__DEFINES/bitrunning.dm
@@ -4,6 +4,13 @@
#define BITRUNNER_COST_HIGH 3
#define BITRUNNER_COST_EXTREME 20
+#define BITRUNNING_GRADE_NONE "None"
+#define BITRUNNING_GRADE_D "D"
+#define BITRUNNING_GRADE_C "C"
+#define BITRUNNING_GRADE_B "B"
+#define BITRUNNING_GRADE_A "A"
+#define BITRUNNING_GRADE_S "S"
+
/// Yay you did it
#define BITRUNNER_REWARD_MIN 1
/// You faced some decent odds
diff --git a/code/__DEFINES/dcs/signals/signals_bitrunning.dm b/code/__DEFINES/dcs/signals/signals_bitrunning.dm
index fa7891e98156..5e49840d344e 100644
--- a/code/__DEFINES/dcs/signals/signals_bitrunning.dm
+++ b/code/__DEFINES/dcs/signals/signals_bitrunning.dm
@@ -1,9 +1,6 @@
/// from /atom/movable/screen/alert/bitrunning/qserver_domain_complete
#define COMSIG_BITRUNNER_ALERT_SEVER "bitrunner_alert_sever"
-/// from /obj/effect/bitrunning/loot_signal: (points)
-#define COMSIG_BITRUNNER_GOAL_POINT "bitrunner_goal_point"
-
// Netpods
/// from /obj/machinery/netpod/sever_connection()
@@ -45,6 +42,7 @@
#define COMSIG_BITRUNNER_STOCKING_GEAR "bitrunner_stocking_gear"
// Ladder
+
/// from /obj/structure/hololadder/disconnect()
#define COMSIG_BITRUNNER_LADDER_SEVER "bitrunner_ladder_sever"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
index 8de0872a7ea9..8903e2940a29 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
@@ -151,6 +151,8 @@
#define COMPONENT_LIVING_BLOCK_PRE_MOB_BUMP (1<<0)
///From base of mob/living/MobBump() (mob/living)
#define COMSIG_LIVING_MOB_BUMP "living_mob_bump"
+///From base of mob/living/MobBump() (mob/living)
+#define COMSIG_LIVING_MOB_BUMPED "living_mob_bumped"
///From base of mob/living/Bump() (turf/closed)
#define COMSIG_LIVING_WALL_BUMP "living_wall_bump"
///From base of turf/closed/Exited() (turf/closed)
diff --git a/code/__DEFINES/economy.dm b/code/__DEFINES/economy.dm
index ce8b47224d6c..344b575aa41d 100644
--- a/code/__DEFINES/economy.dm
+++ b/code/__DEFINES/economy.dm
@@ -58,7 +58,8 @@
#define CIV_JOB_MED 11
#define CIV_JOB_GROW 12
#define CIV_JOB_ATMOS 13
-#define CIV_JOB_RANDOM 14
+#define CIV_JOB_BITRUN 14
+#define CIV_JOB_RANDOM 15
//These defines are to be used to with the payment component, determines which lines will be used during a transaction. If in doubt, go with clinical.
#define PAYMENT_CLINICAL "clinical"
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index e66cf5ffdb0e..4f9d5fb3647e 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -323,3 +323,4 @@ GLOBAL_LIST_INIT(book_types, typecacheof(list(
#define isprojectilespell(thing) (istype(thing, /datum/action/cooldown/spell/pointed/projectile))
#define is_multi_tile_object(atom) (atom.bound_width > world.icon_size || atom.bound_height > world.icon_size)
+#define is_area_virtual(checked_area) (GLOB.virtual_areas && GLOB.virtual_areas[(checked_area).type])
diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm
index 0262ab084376..ae42022467b7 100644
--- a/code/__DEFINES/say.dm
+++ b/code/__DEFINES/say.dm
@@ -110,6 +110,7 @@
#define MAX_PLAQUE_LEN 144
#define MAX_LABEL_LEN 64
#define MAX_DESC_LEN 280
+#define MAX_AAS_LENGTH 168
// Audio/Visual Flags. Used to determine what sense are required to notice a message.
#define MSG_VISUAL (1<<0)
diff --git a/code/__HELPERS/fade_into_nothing.dm b/code/__HELPERS/fade_into_nothing.dm
new file mode 100644
index 000000000000..d8df8ced78eb
--- /dev/null
+++ b/code/__HELPERS/fade_into_nothing.dm
@@ -0,0 +1,9 @@
+/// Deletes the atom with a little fading out animation after a specified time
+/atom/proc/fade_into_nothing(life_time = 5 SECONDS, fade_time = 3 SECONDS)
+ QDEL_IN(src, life_time)
+ if (life_time > fade_time && fade_time > 0)
+ addtimer(CALLBACK(src, PROC_REF(fade_into_nothing_animate), fade_time), life_time - fade_time, TIMER_DELETE_ME)
+
+/// Actually does the fade out, used by fade_into_nothing()
+/atom/proc/fade_into_nothing_animate(fade_time)
+ animate(src, alpha = 0, time = fade_time, flags = ANIMATION_PARALLEL)
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index d8f81afe1cfa..5d85e285c5dc 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -252,13 +252,8 @@
return
var/area/player_area = get_area(character)
deadchat_broadcast(" has arrived at the station at [player_area.name].", "[character.real_name] ([job_title])", follow_target = character, message_type = DEADCHAT_ARRIVALRATTLE)
- if(!length(GLOB.announcement_systems))
- return
- if(!(character.mind?.assigned_role.job_flags & JOB_ANNOUNCE_ARRIVAL))
- return
-
- var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
- announcer.announce("ARRIVAL", character.real_name, job_title, list()) //make the list empty to make it announce it in common
+ if(character.mind && (character.mind.assigned_role.job_flags & JOB_ANNOUNCE_ARRIVAL))
+ aas_config_announce(/datum/aas_config_entry/arrival, list("PERSON" = character.real_name,"RANK" = job_title))
///Check if the turf pressure allows specialized equipment to work
/proc/lavaland_equipment_pressure_check(turf/turf_to_check)
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index b82120873c96..c6c51e899aaa 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -241,12 +241,7 @@
if(last_char_group == SPACES_DETECTED)
t_out = copytext_char(t_out, 1, -1) //removes the last character (in this case a space)
- for(var/bad_name in list("space","floor","wall","r-wall","monkey","unknown","inactive ai")) //prevents these common metagamey names
- if(cmptext(t_out,bad_name))
- return //(not case sensitive)
-
- // Protects against names containing IC chat prohibited words.
- if(is_ic_filtered(t_out) || is_soft_ic_filtered(t_out))
+ if(!filter_name_ic(t_out))
return
return t_out
@@ -257,6 +252,39 @@
#undef LETTERS_DETECTED
+/// Much more permissive version of reject_bad_name().
+/// Returns a trimmed string or null if the name is invalid.
+/// Allows most characters except for IC chat prohibited words.
+/proc/permissive_sanitize_name(value)
+ if(!istext(value)) // Not a string
+ return
+
+ var/name_length = length(value)
+ if(name_length < 3) // Too short
+ return
+
+ if(name_length > 3 * MAX_NAME_LEN) // Bad input
+ return
+
+ var/trimmed = trim(value, MAX_NAME_LEN)
+ if(!filter_name_ic(trimmed)) // Contains IC chat prohibited words
+ return
+
+ return trim_reduced(trimmed)
+
+
+/// Helper proc to check if a name is valid for the IC filter
+/proc/filter_name_ic(name)
+ for(var/bad_name in list("space", "floor", "wall", "r-wall", "monkey", "unknown", "inactive ai")) //prevents these common metagamey names
+ if(cmptext(name, bad_name))
+ return FALSE //(not case sensitive)
+
+ // Protects against names containing IC chat prohibited words.
+ if(is_ic_filtered(name) || is_soft_ic_filtered(name))
+ return FALSE
+
+ return TRUE
+
//html_encode helper proc that returns the smallest non null of two numbers
//or 0 if they're both null (needed because of findtext returning 0 when a value is not present)
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 867f22f4c773..18d355c07362 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -50,21 +50,32 @@ DEFINE_BITFIELD(appearance_flags, list(
))
DEFINE_BITFIELD(area_flags, list(
+ "VALID_TERRITORY" = VALID_TERRITORY,
"BLOBS_ALLOWED" = BLOBS_ALLOWED,
+ "NOTELEPORT" = NOTELEPORT,
+ "HIDDEN_AREA" = HIDDEN_AREA,
"BLOCK_SUICIDE" = BLOCK_SUICIDE,
- "CAVES_ALLOWED" = CAVES_ALLOWED,
+ "XENOBIOLOGY_COMPATIBLE" = XENOBIOLOGY_COMPATIBLE,
"CULT_PERMITTED" = CULT_PERMITTED,
+ "NO_DEATH_MESSAGE" = NO_DEATH_MESSAGE,
+ "EVENT_PROTECTED" = EVENT_PROTECTED,
+ "QUIET_LOGS" = QUIET_LOGS,
+ "BINARY_JAMMING" = BINARY_JAMMING,
+ "NO_BOH" = NO_BOH,
+ "UNLIMITED_FISHING" = UNLIMITED_FISHING,
+ "NO_GRAVITY" = NO_GRAVITY,
+ "LOCAL_TELEPORT" = LOCAL_TELEPORT,
+))
+
+DEFINE_BITFIELD(area_flags_mapping, list(
+ "UNIQUE_AREA" = UNIQUE_AREA,
+ "CAVES_ALLOWED" = CAVES_ALLOWED,
"FLORA_ALLOWED" = FLORA_ALLOWED,
- "HIDDEN_AREA" = HIDDEN_AREA,
- "MEGAFAUNA_SPAWN_ALLOWED" = MEGAFAUNA_SPAWN_ALLOWED,
"MOB_SPAWN_ALLOWED" = MOB_SPAWN_ALLOWED,
- "NOTELEPORT" = NOTELEPORT,
- "NO_DEATH_MESSAGE" = NO_DEATH_MESSAGE,
+ "MEGAFAUNA_SPAWN_ALLOWED" = MEGAFAUNA_SPAWN_ALLOWED,
"PERSISTENT_ENGRAVINGS" = PERSISTENT_ENGRAVINGS,
- "UNIQUE_AREA" = UNIQUE_AREA,
- "VALID_TERRITORY" = VALID_TERRITORY,
- "XENOBIOLOGY_COMPATIBLE" = XENOBIOLOGY_COMPATIBLE,
- "UNLIMITED_FISHING" = UNLIMITED_FISHING,
+ "VIRTUAL_AREA" = VIRTUAL_AREA,
+ "VIRTUAL_SAFE_AREA" = VIRTUAL_SAFE_AREA,
))
DEFINE_BITFIELD(turf_flags, list(
diff --git a/code/_globalvars/lists/bitrunning.dm b/code/_globalvars/lists/bitrunning.dm
new file mode 100644
index 000000000000..fe514c83f928
--- /dev/null
+++ b/code/_globalvars/lists/bitrunning.dm
@@ -0,0 +1,9 @@
+/// Assoc list of bitrunning grades in ascending order and their associated fontawesome icons.
+GLOBAL_LIST_INIT(bitrunning_grades, list(
+ BITRUNNING_GRADE_NONE = FA_ICON_MINUS,
+ BITRUNNING_GRADE_D = FA_ICON_D,
+ BITRUNNING_GRADE_C = FA_ICON_C,
+ BITRUNNING_GRADE_B = FA_ICON_B,
+ BITRUNNING_GRADE_A = FA_ICON_A,
+ BITRUNNING_GRADE_S = FA_ICON_S
+))
diff --git a/code/controllers/subsystem/bitrunning.dm b/code/controllers/subsystem/bitrunning.dm
index d08d9497ea1b..d47085223ad4 100644
--- a/code/controllers/subsystem/bitrunning.dm
+++ b/code/controllers/subsystem/bitrunning.dm
@@ -21,10 +21,13 @@ SUBSYSTEM_DEF(bitrunning)
for(var/datum/lazy_template/virtual_domain/domain as anything in all_domains)
if(domain.domain_flags & DOMAIN_TEST_ONLY)
continue
- var/can_view = domain.difficulty < scanner_tier && domain.cost <= points + 5
- var/can_view_reward = domain.difficulty < (scanner_tier + 1) && domain.cost <= points + 3
+ var/can_view = domain.can_view_name(scanner_tier, points)
+ var/can_view_reward = domain.can_view_reward(scanner_tier, points)
- levels += list(list(
+ var/grade_symbol = GLOB.bitrunning_grades[domain.best_grade]
+
+ UNTYPED_LIST_ADD(levels, list(
+ "announce_ghosts" = domain.announce_to_ghosts,
"cost" = domain.cost,
"desc" = can_view ? domain.desc : "Limited scanning capabilities. Cannot infer domain details.",
"difficulty" = domain.difficulty,
@@ -33,6 +36,7 @@ SUBSYSTEM_DEF(bitrunning)
"has_secondary_objectives" = counterlist_sum(domain.secondary_loot) ? TRUE : FALSE,
"name" = can_view ? domain.name : REDACTED,
"reward" = can_view_reward ? domain.reward_points : REDACTED,
+ "grade_symbol" = grade_symbol,
))
return levels
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 844adc95f57b..66b9df501e02 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -15,6 +15,7 @@ SUBSYSTEM_DEF(blackbox)
"round_end_stats" = 2,
"testmerged_prs" = 2,
"dynamic_threat" = 2,
+ "bitrunning_domain_loaded" = 2,
) //associative list of any feedback variables that have had their format changed since creation and their current version, remember to update this
/datum/controller/subsystem/blackbox/Initialize()
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index 39bbe6cb6d2b..66954fad4cc1 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -491,7 +491,7 @@ GLOBAL_LIST_EMPTY(the_station_areas)
/// Generates the global station area list, filling it with typepaths of unique areas found on the station Z.
/datum/controller/subsystem/mapping/proc/generate_station_area_list()
for(var/area/station/station_area in GLOB.areas)
- if (!(station_area.area_flags & UNIQUE_AREA))
+ if (!(station_area.area_flags_mapping & UNIQUE_AREA))
continue
if (is_station_level(station_area.z))
GLOB.the_station_areas += station_area.type
diff --git a/code/controllers/subsystem/modular_computers.dm b/code/controllers/subsystem/modular_computers.dm
index 4bb7f9f322fc..b08918d84cd0 100644
--- a/code/controllers/subsystem/modular_computers.dm
+++ b/code/controllers/subsystem/modular_computers.dm
@@ -41,9 +41,9 @@ SUBSYSTEM_DEF(modular_computers)
///Generate new coupon codes that can be redeemed with the Coupon Master App
/datum/controller/subsystem/modular_computers/proc/announce_coupon()
//If there's no way to announce the coupon, we may as well skip it.
- if(!length(GLOB.announcement_systems))
+ var/obj/machinery/announcement_system/announcement_system = get_announcement_system()
+ if(!announcement_system)
return
- var/obj/machinery/announcement_system/announcement_system = pick(GLOB.announcement_systems)
var/static/list/discounts = list("0.10" = 7, "0.15" = 16, "0.20" = 20, "0.25" = 16, "0.50" = 8, "0.66" = 1)
var/static/list/flash_discounts = list("0.30" = 3, "0.40" = 8, "0.50" = 8, "0.66" = 2, "0.75" = 1)
diff --git a/code/controllers/subsystem/persistence/engravings.dm b/code/controllers/subsystem/persistence/engravings.dm
index f47fc7fbba12..309f595b8c85 100644
--- a/code/controllers/subsystem/persistence/engravings.dm
+++ b/code/controllers/subsystem/persistence/engravings.dm
@@ -62,7 +62,7 @@
if(!engraving.persistent_save)
continue
var/area/engraved_area = get_area(engraving.parent)
- if(!(engraved_area.area_flags & PERSISTENT_ENGRAVINGS))
+ if(!(engraved_area.area_flags_mapping & PERSISTENT_ENGRAVINGS))
continue
saved_data["entries"] += engraving.save_persistent()
diff --git a/code/datums/components/holographic_nature.dm b/code/datums/components/holographic_nature.dm
index 9f9dace845be..0be1cc75aa28 100644
--- a/code/datums/components/holographic_nature.dm
+++ b/code/datums/components/holographic_nature.dm
@@ -19,6 +19,8 @@
/datum/component/holographic_nature/RegisterWithParent()
AddComponent(/datum/component/connect_loc_behalf, parent, loc_connections)
if(isliving(parent))
+ RegisterSignal(parent, COMSIG_LIVING_MOB_BUMP, PROC_REF(on_bumped))
+ RegisterSignal(parent, COMSIG_LIVING_MOB_BUMPED, PROC_REF(on_bumped))
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_mob_damaged))
return
@@ -44,6 +46,10 @@
if(isprojectile(thing) || thing.density)
apply_effects()
+/datum/component/holographic_nature/proc/on_bumped(atom/movable/source, mob/living/crossing_mob)
+ SIGNAL_HANDLER
+ apply_effects()
+
/datum/component/holographic_nature/proc/apply_effects()
if(!COOLDOWN_FINISHED(src, glitch_cooldown))
return
diff --git a/code/datums/components/ranged_attacks.dm b/code/datums/components/ranged_attacks.dm
index 2f9c6cb822da..618d240ac67f 100644
--- a/code/datums/components/ranged_attacks.dm
+++ b/code/datums/components/ranged_attacks.dm
@@ -84,7 +84,7 @@
target_zone = ran_zone()
casing.fire_casing(target, firer, null, null, null, target_zone, 0, firer)
casing.update_appearance()
- casing.AddElement(/datum/element/temporary_atom, 30 SECONDS)
+ casing.fade_into_nothing(30 SECONDS)
SEND_SIGNAL(parent, COMSIG_BASICMOB_POST_ATTACK_RANGED, target, modifiers)
return
diff --git a/code/datums/components/storm_hating.dm b/code/datums/components/storm_hating.dm
index ce43ba73276b..4060dc09a5e5 100644
--- a/code/datums/components/storm_hating.dm
+++ b/code/datums/components/storm_hating.dm
@@ -43,5 +43,5 @@
var/atom/parent_atom = parent
if (!isturf(parent_atom.loc))
return
- parent.AddElement(/datum/element/temporary_atom, life_time = 3 SECONDS, fade_time = 2 SECONDS)
+ parent_atom.fade_into_nothing(life_time = 3 SECONDS, fade_time = 2 SECONDS)
qdel(src)
diff --git a/code/datums/components/weatherannouncer.dm b/code/datums/components/weatherannouncer.dm
index 0eda6c47a324..4ac103a7758d 100644
--- a/code/datums/components/weatherannouncer.dm
+++ b/code/datums/components/weatherannouncer.dm
@@ -80,7 +80,15 @@
if(previous_level == warning_level && previous_danger == is_weather_dangerous)
return // No change
var/atom/movable/speaker = parent
- speaker.say(get_warning_message())
+ var/msg = get_warning_message()
+ var/obj/machinery/announcement_system/aas = get_announcement_system(/datum/aas_config_entry/weather, speaker)
+ // Active AAS will override default announcement lines
+ if (aas)
+ msg = aas.compile_config_message(/datum/aas_config_entry/weather, list(), !is_weather_dangerous ? 4 : warning_level + 1)
+ // Stop toggling on radios for it, please!
+ aas.broadcast(msg, list(RADIO_CHANNEL_SUPPLY))
+ // Still say it, because you can be not on our level
+ speaker.say(msg)
speaker.update_appearance(UPDATE_ICON)
update_light_color()
@@ -170,6 +178,17 @@
.=..()
UnregisterSignal(parent, COMSIG_ATOM_EXAMINE)
+/datum/aas_config_entry/weather
+ name = "Cargo Alert: Weather Forecast"
+ general_tooltip = "Allows the radio to announce incoming weather."
+ announcement_lines_map = list(
+ "Clear" = "All clear, no weather alerts to report.",
+ "Incoming" = "Weather front incoming, begin to seek shelter.",
+ "Imminent or Active" = "Weather front imminent, find shelter immediately.",
+ "Safe" = "No risk expected from incoming weather front.",
+ )
+
+
#undef WEATHER_ALERT_CLEAR
#undef WEATHER_ALERT_INCOMING
#undef WEATHER_ALERT_IMMINENT_OR_ACTIVE
diff --git a/code/datums/elements/death_drops.dm b/code/datums/elements/death_drops.dm
index 70543260707b..13cb8938b8e6 100644
--- a/code/datums/elements/death_drops.dm
+++ b/code/datums/elements/death_drops.dm
@@ -41,15 +41,18 @@
if (SEND_SIGNAL(target, COMSIG_LIVING_DROP_LOOT, spawn_loot, gibbed) & COMPONENT_NO_LOOT_DROP)
return
+ var/list/all_loot = list()
for(var/thing_to_spawn in spawn_loot)
for(var/i in 1 to (spawn_loot[thing_to_spawn] || 1))
- create_loot(thing_to_spawn, loot_loc, target, gibbed, spread_px = spawn_loot.len * 3)
+ all_loot += create_loot(thing_to_spawn, loot_loc, target, gibbed, spread_px = spawn_loot.len * 3)
+
+ list_clear_nulls(all_loot) // in case of gibbed corpses
+ SEND_SIGNAL(target, COMSIG_LIVING_DROPPED_LOOT, all_loot, gibbed)
/// Handles creating the loots
/datum/element/death_drops/proc/create_loot(typepath, atom/loot_loc, mob/living/dead, gibbed, spread_px = 4)
if(ispath(typepath, /obj/effect/mob_spawn/corpse))
- handle_corpse(typepath, loot_loc, dead, gibbed)
- return
+ return handle_corpse(typepath, loot_loc, dead, gibbed)
var/drop = new typepath(loot_loc)
if(isitem(drop) && spread_px)
@@ -57,6 +60,7 @@
var/clamped_px = clamp(spread_px, 0, 16)
dropped_item.pixel_x = rand(-clamped_px, clamped_px)
dropped_item.pixel_y = rand(-clamped_px, clamped_px)
+ return drop
/// Handles snowflake case of mob corpses
/datum/element/death_drops/proc/handle_corpse(typepath, atom/loot_loc, mob/living/dead, gibbed)
@@ -68,7 +72,8 @@
// if gibbed, dispose of the body
if(gibbed)
body.gib(DROP_ALL_REMAINS)
- return
+ return null
// otherwise continue with the rest of the damage types
body.setToxLoss(dead.getToxLoss())
body.setOxyLoss(dead.getOxyLoss())
+ return body
diff --git a/code/datums/elements/temporary_atom.dm b/code/datums/elements/temporary_atom.dm
deleted file mode 100644
index 6f91e8360b68..000000000000
--- a/code/datums/elements/temporary_atom.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-/// Deletes the atom with a little fading out animation after a specified time
-/datum/element/temporary_atom
-
-/datum/element/temporary_atom/Attach(datum/target, life_time = 5 SECONDS, fade_time = 3 SECONDS)
- . = ..()
- if (!isatom(target))
- return ELEMENT_INCOMPATIBLE
-
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(qdel), WEAKREF(target)), life_time, TIMER_DELETE_ME)
- if (life_time > fade_time && fade_time > 0)
- addtimer(CALLBACK(src, PROC_REF(fade_out), WEAKREF(target), fade_time), life_time - fade_time, TIMER_DELETE_ME)
-
-/datum/element/temporary_atom/proc/fade_out(datum/weakref/target_ref, fade_time)
- var/atom/target = target_ref?.resolve()
- if (isnull(target))
- return
- animate(target, alpha = 0, time = fade_time, flags = ANIMATION_PARALLEL)
diff --git a/code/datums/mapgen/CaveGenerator.dm b/code/datums/mapgen/CaveGenerator.dm
index 4a15770b0c42..14929e31f378 100644
--- a/code/datums/mapgen/CaveGenerator.dm
+++ b/code/datums/mapgen/CaveGenerator.dm
@@ -81,7 +81,7 @@
/datum/map_generator/cave_generator/generate_terrain(list/turfs, area/generate_in)
. = ..()
- if(!(generate_in.area_flags & CAVES_ALLOWED))
+ if(!(generate_in.area_flags_mapping & CAVES_ALLOWED))
return
var/start_time = REALTIMEOFDAY
@@ -105,10 +105,10 @@
/datum/map_generator/cave_generator/populate_terrain(list/turfs, area/generate_in)
// Area var pullouts to make accessing in the loop faster
- var/flora_allowed = (generate_in.area_flags & FLORA_ALLOWED) && length(flora_spawn_list)
- var/feature_allowed = (generate_in.area_flags & FLORA_ALLOWED) && length(feature_spawn_list)
- var/mobs_allowed = (generate_in.area_flags & MOB_SPAWN_ALLOWED) && length(mob_spawn_list)
- var/megas_allowed = (generate_in.area_flags & MEGAFAUNA_SPAWN_ALLOWED) && length(megafauna_spawn_list)
+ var/flora_allowed = (generate_in.area_flags_mapping & FLORA_ALLOWED) && length(flora_spawn_list)
+ var/feature_allowed = (generate_in.area_flags_mapping & FLORA_ALLOWED) && length(feature_spawn_list)
+ var/mobs_allowed = (generate_in.area_flags_mapping & MOB_SPAWN_ALLOWED) && length(mob_spawn_list)
+ var/megas_allowed = (generate_in.area_flags_mapping & MEGAFAUNA_SPAWN_ALLOWED) && length(megafauna_spawn_list)
SStitle.add_init_text("[type]fill", "> [name]: Population", "LOADING")
var/start_time = REALTIMEOFDAY
diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm
index 21dc711109a3..f3a0b9707213 100644
--- a/code/datums/records/manifest.dm
+++ b/code/datums/records/manifest.dm
@@ -181,6 +181,14 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
target.rank = assignment
target.trim = trim
+///Removes a record based on its name.
+/datum/manifest/proc/remove(name)
+ var/datum/record/crew/target = find_record(name)
+ if(!target)
+ return
+ general -= target
+ qdel(target)
+
/**
* Using the name to find the record, and person in reference to the body, we recreate photos for the manifest (and records).
* Args:
diff --git a/code/datums/request_message.dm b/code/datums/request_message.dm
index d9cf51bc5bed..18feada06cb9 100644
--- a/code/datums/request_message.dm
+++ b/code/datums/request_message.dm
@@ -12,8 +12,8 @@
var/message_stamped_by = ""
/// The priority of the message
var/priority = ""
- /// The radio frequency the message should be broadcasted on
- var/radio_freq = null
+ /// The radio channel the message should be broadcasted on
+ var/radio_channel = null
/// The type of the request
var/request_type = ""
/// A list to be appended after the message, for example, list of ores
@@ -26,7 +26,7 @@
message_verified_by = data["verified"]
message_stamped_by = data["stamped"]
priority = data["priority"]
- radio_freq = data["notify_freq"]
+ radio_channel = data["notify_channel"]
request_type = data["ore_update"] ? ORE_UPDATE_REQUEST : data["request_type"]
var/list/data_appended_list = data["appended_list"]
if(data_appended_list && data_appended_list.len)
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index c704bb187d35..914c912669b0 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -24,7 +24,10 @@
/// This uses the same nested list format as turfs_by_zlevel
var/list/list/turf/turfs_to_uncontain_by_zlevel = list()
- var/area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ /// General flag for area properties
+ var/area_flags = VALID_TERRITORY | BLOBS_ALLOWED | CULT_PERMITTED
+ /// Flag for mapping related area properties (such as cavegen)
+ var/area_flags_mapping = UNIQUE_AREA
///Do we have an active fire alarm?
var/fire = FALSE
@@ -160,7 +163,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
/area/New()
// This interacts with the map loader, so it needs to be set immediately
// rather than waiting for atoms to initialize.
- if (area_flags & UNIQUE_AREA)
+ if (area_flags_mapping & UNIQUE_AREA)
GLOB.areas_by_type[type] = src
GLOB.areas += src
energy_usage = new /list(AREA_USAGE_LEN) // Some atoms would like to use power in Initialize()
diff --git a/code/game/area/areas/away_content.dm b/code/game/area/areas/away_content.dm
index 5e2219ef857e..44f6854e105d 100644
--- a/code/game/area/areas/away_content.dm
+++ b/code/game/area/areas/away_content.dm
@@ -11,7 +11,6 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
has_gravity = STANDARD_GRAVITY
ambience_index = AMBIENCE_AWAY
sound_environment = SOUND_ENVIRONMENT_ROOM
- area_flags = UNIQUE_AREA
/area/awaymission/museum
name = "Nanotrasen Museum"
@@ -33,11 +32,11 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
name = "Super Secret Room"
static_lighting = FALSE
base_lighting_alpha = 255
- area_flags = UNIQUE_AREA|NOTELEPORT
+ area_flags = NOTELEPORT
has_gravity = STANDARD_GRAVITY
/area/awaymission/secret
- area_flags = UNIQUE_AREA|NOTELEPORT|HIDDEN_AREA
+ area_flags = NOTELEPORT|HIDDEN_AREA
/area/awaymission/secret/unpowered
always_unpowered = TRUE
diff --git a/code/game/area/areas/centcom.dm b/code/game/area/areas/centcom.dm
index 45abba7c1b2a..c67e45ca6f5e 100644
--- a/code/game/area/areas/centcom.dm
+++ b/code/game/area/areas/centcom.dm
@@ -7,8 +7,8 @@
icon_state = "centcom"
static_lighting = TRUE
requires_power = FALSE
+ area_flags = NOTELEPORT
has_gravity = STANDARD_GRAVITY
- area_flags = UNIQUE_AREA | NOTELEPORT
flags_1 = NONE
// This is just to define the category
@@ -142,7 +142,6 @@
name = "Thunderdome Observation"
icon_state = "thunder_observe"
-
// ENEMY
// Wizard
@@ -155,13 +154,12 @@
area_flags = UNIQUE_AREA | NOTELEPORT
flags_1 = NONE
-
//Abductors
/area/centcom/abductor_ship
name = "Abductor Ship"
icon_state = "abductor_ship"
requires_power = FALSE
- area_flags = UNIQUE_AREA | NOTELEPORT
+ area_flags = NOTELEPORT
static_lighting = FALSE
base_lighting_alpha = 255
has_gravity = STANDARD_GRAVITY
@@ -214,12 +212,11 @@
name = "Mafia Minigame"
icon_state = "mafia"
static_lighting = FALSE
-
base_lighting_alpha = 255
requires_power = FALSE
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
- area_flags = BLOCK_SUICIDE | UNIQUE_AREA
+ area_flags = BLOCK_SUICIDE
//CAPTURE THE FLAG
/area/centcom/ctf
@@ -230,7 +227,7 @@
base_lighting_alpha = 255
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
- area_flags = UNIQUE_AREA | NOTELEPORT | NO_DEATH_MESSAGE | BLOCK_SUICIDE
+ area_flags = NOTELEPORT | NO_DEATH_MESSAGE | BLOCK_SUICIDE
/area/centcom/ctf/control_room
name = "Control Room A"
@@ -284,7 +281,7 @@
ambience_index = AMBIENCE_RUINS
always_unpowered = FALSE
requires_power = TRUE
- area_flags = UNIQUE_AREA | BLOBS_ALLOWED
+ area_flags = BLOBS_ALLOWED
/area/centcom/asteroid/nearstation/bomb_site
name = "\improper Bomb Testing Asteroid"
diff --git a/code/game/area/areas/mining.dm b/code/game/area/areas/mining.dm
index 16b78dcd5a73..176ffecef0df 100644
--- a/code/game/area/areas/mining.dm
+++ b/code/game/area/areas/mining.dm
@@ -3,7 +3,8 @@
icon = 'icons/area/areas_station.dmi'
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
- area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED | CULT_PERMITTED
+ area_flags = VALID_TERRITORY | CULT_PERMITTED
+ area_flags_mapping = UNIQUE_AREA | FLORA_ALLOWED
ambient_buzz = 'sound/ambience/magma.ogg'
/area/mine/lobby
@@ -132,7 +133,7 @@
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
- area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED
+ area_flags = VALID_TERRITORY | FLORA_ALLOWED
sound_environment = SOUND_AREA_LAVALAND
ambient_buzz = 'sound/ambience/magma.ogg'
@@ -145,7 +146,7 @@
power_light = FALSE
requires_power = TRUE
ambience_index = AMBIENCE_MINING
- area_flags = VALID_TERRITORY | UNIQUE_AREA
+ area_flags = VALID_TERRITORY
/area/lavaland/underground
name = "Lavaland Caves"
@@ -156,7 +157,6 @@
power_equip = FALSE
power_light = FALSE
ambience_index = AMBIENCE_MINING
- area_flags = VALID_TERRITORY | UNIQUE_AREA | FLORA_ALLOWED
/area/lavaland/surface/outdoors
name = "Lavaland Wastes"
@@ -164,12 +164,14 @@
/area/lavaland/surface/outdoors/unexplored //monsters and ruins spawn here
icon_state = "unexplored"
- area_flags = VALID_TERRITORY | UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED
+ area_flags = VALID_TERRITORY
+ area_flags_mapping = UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED
map_generator = /datum/map_generator/cave_generator/lavaland
/area/lavaland/surface/outdoors/unexplored/danger //megafauna will also spawn here
icon_state = "danger"
- area_flags = VALID_TERRITORY | UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED
+ area_flags = VALID_TERRITORY
+ area_flags_mapping = parent_type::area_flags_mapping | MEGAFAUNA_SPAWN_ALLOWED
/// Same thing as parent, but uses a different map generator for the icemoon ruin that needs it.
/area/lavaland/surface/outdoors/unexplored/danger/no_ruins
@@ -177,9 +179,7 @@
/area/lavaland/surface/outdoors/explored
name = "Lavaland Labor Camp"
- area_flags = VALID_TERRITORY | UNIQUE_AREA
-
-
+ area_flags = VALID_TERRITORY
/**********************Ice Moon Areas**************************/
@@ -188,7 +188,7 @@
icon_state = "mining"
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
- area_flags = UNIQUE_AREA | FLORA_ALLOWED
+ area_flags_mapping = UNIQUE_AREA | FLORA_ALLOWED
ambience_index = AMBIENCE_ICEMOON
sound_environment = SOUND_AREA_ICEMOON
ambient_buzz = 'sound/ambience/magma.ogg'
@@ -201,7 +201,6 @@
power_equip = FALSE
power_light = FALSE
requires_power = TRUE
- area_flags = UNIQUE_AREA | FLORA_ALLOWED
/area/icemoon/surface/outdoors // parent that defines if something is on the exterior of the station.
name = "Icemoon Wastes"
@@ -216,20 +215,20 @@
area_flags = MOB_SPAWN_ALLOWED | FLORA_ALLOWED//flip this on, the generator has already disabled dangerous fauna
/area/icemoon/surface/outdoors/noteleport // for places like the cursed spring water
- area_flags = UNIQUE_AREA | FLORA_ALLOWED | NOTELEPORT
+ area_flags_mapping = parent_type::area_flags_mapping | NOTELEPORT
/area/icemoon/surface/outdoors/noruins // when you want random generation without the chance of getting ruins
icon_state = "noruins"
- area_flags = UNIQUE_AREA | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | CAVES_ALLOWED
- map_generator = /datum/map_generator/cave_generator/icemoon/surface/noruins
+ area_flags_mapping = parent_type::area_flags_mapping | MOB_SPAWN_ALLOWED | CAVES_ALLOWED
+ map_generator = /datum/map_generator/cave_generator/icemoon/surface/noruins
/area/icemoon/surface/outdoors/labor_camp
name = "Icemoon Labor Camp"
- area_flags = UNIQUE_AREA
+ area_flags_mapping = /area::area_flags_mapping
/area/icemoon/surface/outdoors/unexplored //monsters and ruins spawn here
icon_state = "unexplored"
- area_flags = UNIQUE_AREA | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | CAVES_ALLOWED
+ area_flags_mapping = parent_type::area_flags_mapping | MOB_SPAWN_ALLOWED | CAVES_ALLOWED
/area/icemoon/surface/outdoors/unexplored/rivers // rivers spawn here
icon_state = "danger"
@@ -239,10 +238,10 @@
. = ..()
if(HAS_TRAIT(SSstation, STATION_TRAIT_FORESTED))
map_generator = /datum/map_generator/cave_generator/icemoon/surface/forested
- area_flags |= MOB_SPAWN_ALLOWED //flip this on, the generator has already disabled dangerous fauna
+ area_flags_mapping |= MOB_SPAWN_ALLOWED //flip this on, the generator has already disabled dangerous fauna
/area/icemoon/surface/outdoors/unexplored/rivers/no_monsters
- area_flags = UNIQUE_AREA | FLORA_ALLOWED | CAVES_ALLOWED
+ area_flags_mapping = /area/icemoon/::area_flags_mapping | CAVES_ALLOWED
/area/icemoon/underground
name = "Icemoon Caves"
@@ -252,16 +251,15 @@
power_environ = FALSE
power_equip = FALSE
power_light = FALSE
- area_flags = UNIQUE_AREA | FLORA_ALLOWED
/area/icemoon/underground/unexplored // mobs and megafauna and ruins spawn here
name = "Icemoon Caves"
icon_state = "unexplored"
- area_flags = CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED
+ area_flags_mapping = CAVES_ALLOWED | FLORA_ALLOWED | MOB_SPAWN_ALLOWED | MEGAFAUNA_SPAWN_ALLOWED
/area/icemoon/underground/unexplored/no_rivers
icon_state = "norivers"
- area_flags = CAVES_ALLOWED | FLORA_ALLOWED // same rules as "shoreline" turfs since we might need this to pull double-duty
+ area_flags_mapping = CAVES_ALLOWED | FLORA_ALLOWED // same rules as "shoreline" turfs since we might need this to pull double-duty
map_generator = /datum/map_generator/cave_generator/icemoon
/area/icemoon/underground/unexplored/rivers // rivers spawn here
@@ -273,15 +271,15 @@
/area/icemoon/underground/unexplored/rivers/deep/shoreline //use this for when you don't want mobs to spawn in certain areas in the "deep" portions. Think adjacent to rivers or station structures.
icon_state = "shore"
- area_flags = UNIQUE_AREA | CAVES_ALLOWED | FLORA_ALLOWED
+ area_flags_mapping = /area/icemoon/::area_flags_mapping | CAVES_ALLOWED
/area/icemoon/underground/explored // ruins can't spawn here
name = "Icemoon Underground"
- area_flags = UNIQUE_AREA
+ area_flags_mapping = /area::area_flags_mapping
/area/icemoon/underground/explored/graveyard
name = "Graveyard"
- area_flags = UNIQUE_AREA
+ area_flags_mapping = /area::area_flags_mapping
ambience_index = AMBIENCE_SPOOKY
icon = 'icons/area/areas_station.dmi'
icon_state = "graveyard"
diff --git a/code/game/area/areas/misc.dm b/code/game/area/areas/misc.dm
index 75896f784618..6be58235d488 100644
--- a/code/game/area/areas/misc.dm
+++ b/code/game/area/areas/misc.dm
@@ -11,7 +11,7 @@
power_light = FALSE
power_equip = FALSE
power_environ = FALSE
- area_flags = UNIQUE_AREA
+ area_flags = NO_GRAVITY
outdoors = TRUE
ambience_index = AMBIENCE_SPACE
flags_1 = CAN_BE_DIRTY_1
diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm
index 69e17d365caf..0cbee32b4715 100644
--- a/code/game/area/areas/ruins/_ruins.dm
+++ b/code/game/area/areas/ruins/_ruins.dm
@@ -5,7 +5,7 @@
icon = 'icons/area/areas_ruins.dmi'
icon_state = "ruins"
has_gravity = STANDARD_GRAVITY
- area_flags = HIDDEN_AREA | BLOBS_ALLOWED | UNIQUE_AREA
+ area_flags = HIDDEN_AREA | BLOBS_ALLOWED
ambience_index = AMBIENCE_RUINS
flags_1 = CAN_BE_DIRTY_1
sound_environment = SOUND_ENVIRONMENT_STONEROOM
diff --git a/code/game/area/areas/ruins/icemoon.dm b/code/game/area/areas/ruins/icemoon.dm
index 8afa3fae2d08..7ef689c61d91 100644
--- a/code/game/area/areas/ruins/icemoon.dm
+++ b/code/game/area/areas/ruins/icemoon.dm
@@ -45,6 +45,13 @@
/area/ruin/pizzeria/kitchen
name = "\improper Moffuchi's Kitchen"
+/area/ruin/syndibiodome
+ name = "\improper Syndicate Biodome"
+ sound_environment = SOUND_AREA_SMALL_ENCLOSED
+ ambience_index = AMBIENCE_DANGER
+ area_flags = NOTELEPORT
+ area_flags_mapping = NONE
+
/area/ruin/planetengi
name = "\improper Engineering Outpost"
@@ -66,3 +73,46 @@
/area/ruin/powered/hermit
name = "\improper Hermit's Cabin"
+/area/ruin/syndielab
+ name = "\improper Syndicate Lab"
+ ambience_index = AMBIENCE_DANGER
+ sound_environment = SOUND_ENVIRONMENT_CAVE
+
+/area/ruin/outpost31
+ name = "\improper Outpost 31"
+ sound_environment = SOUND_AREA_SMALL_ENCLOSED
+ mood_bonus = -10
+ mood_message = "Something very bad happened here..."
+
+/area/ruin/outpost31/medical
+ name = "\improper Outpost 31 Medical"
+
+/area/ruin/outpost31/kitchendiningroom
+ name = "\improper Outpost 31 Kitchen-Dining Room"
+
+/area/ruin/outpost31/kennel
+ name = "\improper Outpost 31 Kennel"
+
+/area/ruin/outpost31/radiomap
+ name = "\improper Outpost 31 Radio-Map Room"
+
+/area/ruin/outpost31/lab
+ name = "\improper Outpost 31 Lab"
+ area_flags = NOTELEPORT //megafauna arena
+ area_flags_mapping = NONE
+ requires_power = FALSE
+
+/area/ruin/outpost31/lootroom
+ name = "\improper Outpost 31 Secondary Storage"
+ area_flags = NOTELEPORT //megafauna loot room
+ area_flags_mapping = NONE
+ requires_power = FALSE
+
+/area/ruin/outpost31/recroom
+ name = "\improper Outpost 31 Rec Room"
+
+/area/ruin/outpost31/crewquarters
+ name = "\improper Outpost 31 Sleeping Quarters"
+
+/area/ruin/outpost31/commander_room
+ name = "\improper Outpost 31 Station Commander Office"
diff --git a/code/game/area/areas/ruins/lavaland.dm b/code/game/area/areas/ruins/lavaland.dm
index 8a95cf2ba006..047f5cdc9e65 100644
--- a/code/game/area/areas/ruins/lavaland.dm
+++ b/code/game/area/areas/ruins/lavaland.dm
@@ -43,6 +43,7 @@
/area/ruin/unpowered/cultaltar
name = "\improper Cult Altar"
area_flags = CULT_PERMITTED
+ area_flags_mapping = NONE
ambience_index = AMBIENCE_SPOOKY
//Syndicate lavaland base
diff --git a/code/game/area/areas/ruins/space.dm b/code/game/area/areas/ruins/space.dm
index f0bd865c2097..db16c71940b2 100644
--- a/code/game/area/areas/ruins/space.dm
+++ b/code/game/area/areas/ruins/space.dm
@@ -2,7 +2,8 @@
/area/ruin/space
has_gravity = FALSE
- area_flags = UNIQUE_AREA
+ area_flags = NONE
+ area_flags_mapping = UNIQUE_AREA
/area/ruin/space/unpowered
always_unpowered = TRUE
@@ -16,11 +17,10 @@
/area/ruin/space/has_grav/powered
requires_power = FALSE
-
// Ruin solars define, /area/solars was moved to /area/station/solars, causing the solars specific areas to lose their properties
/area/ruin/space/solars
requires_power = FALSE
- area_flags = UNIQUE_AREA
+ area_flags = NONE
flags_1 = NONE
ambience_index = AMBIENCE_ENGI
airlock_wires = /datum/wires/airlock/engineering
@@ -310,7 +310,7 @@
icon = 'icons/area/areas_ruins.dmi' // Solars inheriet areas_misc.dmi, not areas_ruin.dmi
icon_state = "os_charlie_solars"
requires_power = FALSE
- area_flags = UNIQUE_AREA
+ area_flags = NONE
sound_environment = SOUND_AREA_SPACE
/area/ruin/space/ancientstation/charlie/storage
@@ -534,8 +534,8 @@
/area/ruin/space/djstation/solars
name = "\improper DJ Station Solars"
icon_state = "DJ"
- area_flags = UNIQUE_AREA
- has_gravity = STANDARD_GRAVITY
+ area_flags = NONE
+ has_gravity = FALSE
/area/ruin/space/djstation/service
name = "\improper DJ Station Service"
@@ -582,7 +582,7 @@
/area/ruin/space/has_grav/hellfactoryoffice
name = "\improper Hell Factory Office"
- area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | NOTELEPORT
+ area_flags = VALID_TERRITORY | BLOBS_ALLOWED | NOTELEPORT
//Ruin of Spinward Smoothies
@@ -600,7 +600,7 @@
/area/ruin/space/has_grav/powered/biooutpost
name = "\improper Bioresearch Outpost"
- area_flags = UNIQUE_AREA | NOTELEPORT
+ area_flags = NOTELEPORT
/area/ruin/space/has_grav/powered/biooutpost/vault
name = "\improper Bioresearch Outpost Secure Testing"
diff --git a/code/game/area/areas/shuttles.dm b/code/game/area/areas/shuttles.dm
index 286398dd7acc..5854f6ebf045 100644
--- a/code/game/area/areas/shuttles.dm
+++ b/code/game/area/areas/shuttles.dm
@@ -10,6 +10,7 @@
always_unpowered = FALSE
// Loading the same shuttle map at a different time will produce distinct area instances.
area_flags = NONE
+ area_flags_mapping = NONE
icon = 'icons/area/areas_station.dmi'
icon_state = "shuttle"
flags_1 = CAN_BE_DIRTY_1
@@ -108,11 +109,9 @@
static_lighting = FALSE
base_lighting_alpha = 255
-
/area/shuttle/arrival
name = "Arrival Shuttle"
- area_flags = UNIQUE_AREA// SSjob refers to this area for latejoiners
-
+ area_flags_mapping = UNIQUE_AREA // SSjob refers to this area for latejoiners
/area/shuttle/arrival/on_joining_game(mob/living/boarder)
if(SSshuttle.arrivals?.mode == SHUTTLE_CALL)
@@ -121,22 +120,17 @@
boarder.playsound_local(get_turf(boarder), 'sound/voice/ApproachingTG.ogg', 25)
boarder.update_parallax_teleport()
-
/area/shuttle/pod_1
name = "Escape Pod One"
- area_flags = NONE
/area/shuttle/pod_2
name = "Escape Pod Two"
- area_flags = NONE
/area/shuttle/pod_3
name = "Escape Pod Three"
- area_flags = NONE
/area/shuttle/pod_4
name = "Escape Pod Four"
- area_flags = NONE
/area/shuttle/mining
name = "Mining Shuttle"
@@ -154,10 +148,9 @@
/area/shuttle/escape
name = "Emergency Shuttle"
- area_flags = BLOBS_ALLOWED
+ area_flags = CULT_PERMITTED
area_limited_icon_smoothing = /area/shuttle/escape
flags_1 = CAN_BE_DIRTY_1
- area_flags = CULT_PERMITTED
/area/shuttle/escape/backup
name = "Backup Emergency Shuttle"
diff --git a/code/game/area/areas/station/common.dm b/code/game/area/areas/station/common.dm
index 2280215ab6ee..1b6eba4dc25e 100644
--- a/code/game/area/areas/station/common.dm
+++ b/code/game/area/areas/station/common.dm
@@ -2,7 +2,7 @@
name = "\improper Crew Facilities"
icon_state = "commons"
sound_environment = SOUND_AREA_STANDARD_STATION
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
/*
* Dorm Areas
diff --git a/code/game/area/areas/station/engineering.dm b/code/game/area/areas/station/engineering.dm
index abd10c78f579..e34487a81823 100644
--- a/code/game/area/areas/station/engineering.dm
+++ b/code/game/area/areas/station/engineering.dm
@@ -54,7 +54,7 @@
/area/station/engineering/atmospherics_engine
name = "\improper Atmospherics Engine"
icon_state = "atmos_engine"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
/area/station/engineering/lobby
name = "\improper Engineering Lobby"
@@ -63,7 +63,7 @@
/area/station/engineering/supermatter
name = "\improper Supermatter Engine"
icon_state = "engine_sm"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
sound_environment = SOUND_AREA_SMALL_ENCLOSED
/area/station/engineering/supermatter/waste
@@ -110,7 +110,7 @@
/area/station/engineering/storage/tcomms
name = "Telecomms Storage"
icon_state = "tcom_storage"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
/*
* Construction Areas
diff --git a/code/game/area/areas/station/hallway.dm b/code/game/area/areas/station/hallway.dm
index 2283614ade06..15b23b057618 100644
--- a/code/game/area/areas/station/hallway.dm
+++ b/code/game/area/areas/station/hallway.dm
@@ -84,7 +84,7 @@
/area/station/hallway/secondary/entry
name = "\improper Arrival Shuttle Hallway"
icon_state = "entry"
- area_flags = UNIQUE_AREA | EVENT_PROTECTED
+ area_flags = EVENT_PROTECTED
ambience_index = AMBIENCE_ARRIVALS
/area/station/hallway/secondary/dock
diff --git a/code/game/area/areas/station/maintenance.dm b/code/game/area/areas/station/maintenance.dm
index 5e636719e7a0..93919536c58b 100644
--- a/code/game/area/areas/station/maintenance.dm
+++ b/code/game/area/areas/station/maintenance.dm
@@ -1,7 +1,7 @@
/area/station/maintenance
name = "Generic Maintenance"
ambience_index = AMBIENCE_MAINT
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED | PERSISTENT_ENGRAVINGS
airlock_wires = /datum/wires/airlock/maint
sound_environment = SOUND_AREA_TUNNEL_ENCLOSED
forced_ambience = TRUE
@@ -94,7 +94,7 @@
/area/station/maintenance/department/science/xenobiology
name = "Xenobiology Maintenance"
icon_state = "xenomaint"
- area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | XENOBIOLOGY_COMPATIBLE | CULT_PERMITTED
+ area_flags = VALID_TERRITORY | BLOBS_ALLOWED | XENOBIOLOGY_COMPATIBLE | CULT_PERMITTED
/*
* Generic Maintenance Tunnels
diff --git a/code/game/area/areas/station/misc.dm b/code/game/area/areas/station/misc.dm
index fbbe0e8a5120..6dae32737a51 100644
--- a/code/game/area/areas/station/misc.dm
+++ b/code/game/area/areas/station/misc.dm
@@ -30,5 +30,5 @@
power_light = FALSE
requires_power = TRUE
ambience_index = AMBIENCE_MINING
- area_flags = UNIQUE_AREA
+ area_flags = NONE
outdoors = TRUE
diff --git a/code/game/area/areas/station/science.dm b/code/game/area/areas/station/science.dm
index 2787a4ff87fe..74da9b6eccbe 100644
--- a/code/game/area/areas/station/science.dm
+++ b/code/game/area/areas/station/science.dm
@@ -110,20 +110,20 @@
/area/station/science/ordnance/burnchamber
name = "\improper Ordnance Burn Chamber"
icon_state = "ord_burn"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
/area/station/science/ordnance/freezerchamber
name = "\improper Ordnance Freezer Chamber"
icon_state = "ord_freeze"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
// Room for equipments and such
/area/station/science/ordnance/testlab
name = "\improper Ordnance Testing Lab"
icon_state = "ord_test"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED | CULT_PERMITTED
/area/station/science/ordnance/bomb
name = "\improper Ordnance Bomb Site"
icon_state = "ord_boom"
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED
+ area_flags = BLOBS_ALLOWED| CULT_PERMITTED | NO_GRAVITY
diff --git a/code/game/area/areas/station/security.dm b/code/game/area/areas/station/security.dm
index 5a871e3e90c9..a1232e503f14 100644
--- a/code/game/area/areas/station/security.dm
+++ b/code/game/area/areas/station/security.dm
@@ -185,7 +185,7 @@
/area/station/security/prison
name = "\improper Prison Wing"
icon_state = "sec_prison"
- area_flags = VALID_TERRITORY | BLOBS_ALLOWED | UNIQUE_AREA | CULT_PERMITTED | PERSISTENT_ENGRAVINGS
+ area_flags = VALID_TERRITORY | BLOBS_ALLOWED | CULT_PERMITTED | PERSISTENT_ENGRAVINGS
//Rad proof
/area/station/security/prison/toilet
diff --git a/code/game/area/areas/station/service.dm b/code/game/area/areas/station/service.dm
index 23fe166616d4..355406563264 100644
--- a/code/game/area/areas/station/service.dm
+++ b/code/game/area/areas/station/service.dm
@@ -77,7 +77,7 @@
mood_bonus = 5
mood_message = "I love being in the library!"
mood_trait = TRAIT_INTROVERT
- area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA
+ area_flags = CULT_PERMITTED | BLOBS_ALLOWED
sound_environment = SOUND_AREA_LARGE_SOFTFLOOR
/area/station/service/library/garden
@@ -180,7 +180,7 @@
/area/station/service/janitor
name = "\improper Custodial Closet"
icon_state = "janitor"
- area_flags = CULT_PERMITTED | BLOBS_ALLOWED | UNIQUE_AREA
+ area_flags = CULT_PERMITTED | BLOBS_ALLOWED
sound_environment = SOUND_AREA_SMALL_ENCLOSED
/area/station/service/barber
diff --git a/code/game/area/areas/station/solars.dm b/code/game/area/areas/station/solars.dm
index 57376e2fb17b..2b0bffc8b503 100644
--- a/code/game/area/areas/station/solars.dm
+++ b/code/game/area/areas/station/solars.dm
@@ -5,7 +5,7 @@
/area/station/solars
icon_state = "panels"
requires_power = FALSE
- area_flags = UNIQUE_AREA
+ area_flags = NO_GRAVITY
flags_1 = NONE
ambience_index = AMBIENCE_ENGI
airlock_wires = /datum/wires/airlock/engineering
@@ -40,10 +40,20 @@
name = "\improper Starboard Bow Solar Array"
icon_state = "panelsFS"
+/area/station/solars/starboard/fore/asteriod
+ name = "\improper Starboard Bow Asteriod Solar Array"
+ icon_state = "panelsFS"
+ area_flags = NONE // solar areas directly on asteriod have gravity
+
/area/station/solars/port
name = "\improper Port Solar Array"
icon_state = "panelsP"
+/area/station/solars/port/asteriod
+ name = "\improper Port Asteriod Solar Array"
+ icon_state = "panelsP"
+ area_flags = NONE // solar areas directly on asteriod have gravity
+
/area/station/solars/port/aft
name = "\improper Port Quarter Solar Array"
icon_state = "panelsAP"
diff --git a/code/game/machinery/announcement_system.dm b/code/game/machinery/announcement_system.dm
index ce2ff2a1d1ab..550a26b7cd94 100644
--- a/code/game/machinery/announcement_system.dm
+++ b/code/game/machinery/announcement_system.dm
@@ -17,11 +17,13 @@ GLOBAL_LIST_EMPTY(announcement_systems)
circuit = /obj/item/circuitboard/machine/announcement_system
+ ///All possible announcements and their local configurations
+ var/list/datum/aas_config_entry/config_entries = list()
+
+ ///The headset that we use for broadcasting
var/obj/item/radio/headset/radio
- var/arrival = "%PERSON has signed up as %RANK"
- var/arrivalToggle = 1
- var/newhead = "%PERSON, %RANK, is the department head."
- var/newheadToggle = 1
+ ///AIs headset support all stations channels, but it may require an override for away site or syndie AASs.
+ var/radio_type = /obj/item/radio/headset/silicon/ai
var/greenlight = "Light_Green"
var/pinklight = "Light_Pink"
@@ -30,87 +32,76 @@ GLOBAL_LIST_EMPTY(announcement_systems)
/obj/machinery/announcement_system/Initialize(mapload)
. = ..()
GLOB.announcement_systems += src
- radio = new /obj/item/radio/headset/silicon/ai(src)
+ radio = new radio_type(src)
+ config_entries = init_subtypes(/datum/aas_config_entry, list())
update_appearance()
/obj/machinery/announcement_system/randomize_language_if_on_station()
return
/obj/machinery/announcement_system/update_icon_state()
- icon_state = "[base_icon_state]_[is_operational ? "On" : "Off"][panel_open ? "_Open" : null]"
+ icon_state = "[base_icon_state]_[is_operational && !(machine_stat & EMPED) ? "On" : "Off"][panel_open ? "_Open" : null]"
return ..()
/obj/machinery/announcement_system/update_overlays()
. = ..()
- if(arrivalToggle)
+ var/datum/aas_config_entry/entry = locate(/datum/aas_config_entry/arrival) in config_entries
+ if(entry && entry.enabled)
. += greenlight
- if(newheadToggle)
+ entry = locate(/datum/aas_config_entry/newhead) in config_entries
+ if(entry && entry.enabled)
. += pinklight
- if(machine_stat & BROKEN)
+ if(machine_stat & EMPED)
. += errorlight
/obj/machinery/announcement_system/Destroy()
QDEL_NULL(radio)
+ QDEL_LAZYLIST(config_entries)
GLOB.announcement_systems -= src //"OH GOD WHY ARE THERE 100,000 LISTED ANNOUNCEMENT SYSTEMS?!!"
return ..()
/obj/machinery/announcement_system/screwdriver_act(mob/living/user, obj/item/tool)
- tool.play_tool_sound(src)
- toggle_panel_open()
- to_chat(user, span_notice("You [panel_open ? "open" : "close"] the maintenance hatch of [src]."))
- update_appearance()
- return TRUE
+ var/icon_state_assemble = "[base_icon_state]_[is_operational && !(machine_stat & EMPED) ? "On" : "Off"]"
+ if(default_deconstruction_screwdriver(user, "[icon_state_assemble]_Open", icon_state_assemble, tool))
+ return ITEM_INTERACT_SUCCESS
+ return ITEM_INTERACT_BLOCKING
/obj/machinery/announcement_system/crowbar_act(mob/living/user, obj/item/tool)
+ . = ..()
if(default_deconstruction_crowbar(tool))
- return TRUE
+ return ITEM_INTERACT_SUCCESS
/obj/machinery/announcement_system/multitool_act(mob/living/user, obj/item/tool)
- if(!panel_open || !(machine_stat & BROKEN))
- return FALSE
+ if(!panel_open || !(machine_stat & EMPED))
+ return ITEM_INTERACT_BLOCKING
to_chat(user, span_notice("You reset [src]'s firmware."))
- set_machine_stat(machine_stat & ~BROKEN)
+ set_machine_stat(machine_stat & ~EMPED)
update_appearance()
+ return ITEM_INTERACT_SUCCESS
-/obj/machinery/announcement_system/proc/CompileText(str, user, rank) //replaces user-given variables with actual thingies.
- str = replacetext(str, "%PERSON", "[user]")
- str = replacetext(str, "%RANK", "[rank]")
- return str
-
-/obj/machinery/announcement_system/proc/announce(message_type, user, rank, list/channels)
- if(!is_operational)
- return
-
- var/message
-
- if(message_type == "ARRIVAL" && arrivalToggle)
- message = CompileText(arrival, user, rank)
- else if(message_type == "NEWHEAD" && newheadToggle)
- message = CompileText(newhead, user, rank)
- else if(message_type == "ARRIVALS_BROKEN")
- message = "The arrivals shuttle has been damaged. Docking for repairs..."
- else if(message_type == "DESPAWN")
- message = CompileText("%PERSON, %RANK, has entered long-term crew storage.", user, rank)
-
- broadcast(message, channels)
-
-/// Announces a new security officer joining over the radio
-/obj/machinery/announcement_system/proc/announce_officer(mob/officer, department)
- if (!is_operational)
+/// Does funny breakage stuff
+/obj/machinery/announcement_system/proc/act_up()
+ if (machine_stat & EMPED)
return
+ set_machine_stat(machine_stat | EMPED)
+ update_appearance()
+ for (var/datum/aas_config_entry/config in config_entries)
+ config.act_up()
- broadcast("Officer [officer.real_name] has been assigned to [department].", list(RADIO_CHANNEL_SECURITY))
+/obj/machinery/announcement_system/emp_act(severity)
+ . = ..()
+ if(!(machine_stat & (NOPOWER|EMPED|BROKEN)) && !(. & EMP_PROTECT_SELF))
+ act_up()
-/// Sends a message to the appropriate channels.
-/obj/machinery/announcement_system/proc/broadcast(message, list/channels)
- use_energy(active_power_usage)
- if(channels.len == 0)
- radio.talk_into(src, message, null)
- else
- for(var/channel in channels)
- radio.talk_into(src, message, channel)
+/obj/machinery/announcement_system/emag_act(mob/user, obj/item/card/emag/emag_card)
+ if(obj_flags & EMAGGED)
+ return FALSE
+ obj_flags |= EMAGGED
+ act_up()
+ balloon_alert(user, "announcement strings corrupted")
+ return TRUE
/obj/machinery/announcement_system/ui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
@@ -119,73 +110,225 @@ GLOBAL_LIST_EMPTY(announcement_systems)
ui.open()
/obj/machinery/announcement_system/ui_data()
+ var/list/configs = list()
+ for(var/datum/aas_config_entry/config in config_entries)
+ configs += list(list(
+ name = config.name,
+ entryRef = REF(config),
+ enabled = config.enabled,
+ modifiable = config.modifiable,
+ announcementLinesMap = config.announcement_lines_map,
+ generalTooltip = config.general_tooltip,
+ varsAndTooltipsMap = config.vars_and_tooltips_map
+ ))
+ return list("config_entries" = configs)
+
+/obj/machinery/announcement_system/ui_static_data(mob/user)
var/list/data = list()
- data["arrival"] = arrival
- data["arrivalToggle"] = arrivalToggle
- data["newhead"] = newhead
- data["newheadToggle"] = newheadToggle
+
+ data["max_announcement_len"] = MAX_AAS_LENGTH
+
return data
-/obj/machinery/announcement_system/ui_act(action, param)
+/obj/machinery/announcement_system/ui_act(action, params)
. = ..()
if(.)
return
if(!usr.can_perform_action(src, ALLOW_SILICON_REACH))
return
- if(machine_stat & BROKEN)
+ if(machine_stat & EMPED)
visible_message(span_warning("[src] buzzes."), span_hear("You hear a faint buzz."))
playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, TRUE)
return
- switch(action)
- if("ArrivalText")
- var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN)
- if(!usr.can_perform_action(src, ALLOW_SILICON_REACH))
- return
- if(NewMessage)
- arrival = NewMessage
- usr.log_message("updated the arrivals announcement to: [NewMessage]", LOG_GAME)
- if("NewheadText")
- var/NewMessage = trim(html_encode(param["newText"]), MAX_MESSAGE_LEN)
- if(!usr.can_perform_action(src, ALLOW_SILICON_REACH))
- return
- if(NewMessage)
- newhead = NewMessage
- usr.log_message("updated the head announcement to: [NewMessage]", LOG_GAME)
- if("NewheadToggle")
- newheadToggle = !newheadToggle
- update_appearance()
- if("ArrivalToggle")
- arrivalToggle = !arrivalToggle
- update_appearance()
+
add_fingerprint(usr)
+ var/datum/aas_config_entry/config = locate(params["entryRef"]) in config_entries
+ if(!config || !config.modifiable)
+ return
-/obj/machinery/announcement_system/attack_robot(mob/living/silicon/user)
- . = attack_ai(user)
+ switch(action)
+ if("Toggle")
+ config.enabled = !config.enabled
+ if (config.type in list(/datum/aas_config_entry/arrival, /datum/aas_config_entry/newhead))
+ update_appearance()
+ if("Text")
+ if(!(params["lineKey"] in config.announcement_lines_map))
+ message_admins("[ADMIN_LOOKUPFLW(usr)] tried to set announcement line for nonexisting line in the [config.name] for AAS. Probably href injection. Received line: [params["lineKey"]]")
+ log_game("[key_name(usr)] tried to mess with AAS. For [config.name] he tried to edit nonexistend [params["lineKey"]]")
+ return
+ var/new_message = trim(html_encode(params["newText"]), MAX_AAS_LENGTH)
+ if(new_message)
+ config.announcement_lines_map[params["lineKey"]] = new_message
+ usr.log_message("updated [params["lineKey"]] line in the [config.name] to: [new_message]", LOG_GAME)
-/obj/machinery/announcement_system/attack_ai(mob/user)
- if(!user.can_perform_action(src, ALLOW_SILICON_REACH))
+/obj/machinery/announcement_system/can_interact(mob/user)
+ . = ..()
+ if (!.)
return
- if(machine_stat & BROKEN)
+
+ if (machine_stat & EMPED)
to_chat(user, span_warning("[src]'s firmware appears to be malfunctioning!"))
+ if (!isAI(user)) // Deus Ex Machina goes without multitool in his default complectation.
+ to_chat(user, span_warning("However, you can reset it with [EXAMINE_HINT("multitool")], while its [EXAMINE_HINT("panel is open")]!"))
+ return FALSE
+
+/// If AAS can't broadcast message, it shouldn't be picked by randomizer.
+/obj/machinery/announcement_system/proc/has_supported_channels(list/channels)
+ if (!LAZYLEN(channels) || (RADIO_CHANNEL_COMMON in channels))
+ // Okay, I am not proud of this, but I don't want CentCom or Syndie AASs to broadcast on Common.
+ return src.type == /obj/machinery/announcement_system
+ for(var/channel in channels)
+ if(radio.channels[channel])
+ return TRUE
+ return FALSE
+
+/// Can AAS receive request for broadcast from you?
+/obj/machinery/announcement_system/proc/can_be_reached_from(atom/source)
+ if(!source || !istype(source))
+ return TRUE
+ var/turf/source_turf = get_turf(source)
+ if (!source_turf)
+ return TRUE
+ // Keep updated with broadcasting.dm (/datum/signal/subspace/vocal/New)
+ return z in SSmapping.get_connected_levels(source_turf)
+
+/// Compiles the announcement message with the provided variables. Announcement line is optional.
+/obj/machinery/announcement_system/proc/compile_config_message(aas_config_entry_type, list/variables_map, announcement_line, fail_if_disabled=FALSE)
+ var/datum/aas_config_entry/config = locate(aas_config_entry_type) in config_entries
+ if (!config || (fail_if_disabled && !config.enabled))
return
- interact(user)
+ return config.compile_announce(variables_map, announcement_line)
-/obj/machinery/announcement_system/proc/act_up() //does funny breakage stuff
- if(!atom_break()) // if badmins flag this unbreakable or its already broken
+/// Sends a message to the appropriate channels.
+/obj/machinery/announcement_system/proc/broadcast(message, list/channels, command_span = FALSE)
+ use_energy(active_power_usage)
+ if(!LAZYLEN(channels))
+ radio.talk_into(src, message, null, command_span ? list(speech_span, SPAN_COMMAND) : null)
return
- arrival = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!", "CRITICAL ERROR 99.", "ERR)#: DA#AB@#E NOT F(*ND!")
- newhead = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!", "ER)#R - B*@ TEXT F*O(ND!", "AAS.exe is not responding. NanoOS is searching for a solution to the problem.")
+ // For some reasons, radio can't recognize RADIO_CHANNEL_COMMON in channels, so we need to handle it separately.
+ if (RADIO_CHANNEL_COMMON in channels)
+ radio.talk_into(src, message, null, command_span ? list(speech_span, SPAN_COMMAND) : null)
+ channels -= RADIO_CHANNEL_COMMON
+ for(var/channel in channels)
+ radio.talk_into(src, message, channel, command_span ? list(speech_span, SPAN_COMMAND) : null)
+
+/// Announces configs entry message with the provided variables. Channels and announcement_line are optional.
+/obj/machinery/announcement_system/proc/announce(aas_config_entry_type, list/variables_map, list/channels, announcement_line, command_span)
+ var/msg = compile_config_message(aas_config_entry_type, variables_map, announcement_line, TRUE)
+ if (msg)
+ broadcast(msg, channels, command_span)
+
+/// Returns a random announcement system that is operational, has the specified config entry, signal can reach source and radio supports any channel in list. Config entry, source and channels are optional.
+/proc/get_announcement_system(aas_config_entry_type, source, list/channels)
+ if (!GLOB.announcement_systems.len)
+ return null
+ var/list/intact_aass = list()
+ for(var/obj/machinery/announcement_system/announce as anything in GLOB.announcement_systems)
+ if(!QDELETED(announce) && announce.is_operational && announce.has_supported_channels(channels) && announce.can_be_reached_from(source))
+ if(aas_config_entry_type)
+ var/datum/aas_config_entry/entry = locate(aas_config_entry_type) in announce.config_entries
+ if(!entry || !entry.enabled)
+ continue
+ intact_aass += announce
+ return intact_aass.len ? pick(intact_aass) : null
+
+/// Announces the provided message with the provided variables and config entry type. Channels, announcement_line, command_span and source are optional.
+/proc/aas_config_announce(aas_config_entry_type, list/variables_map, source, list/channels, announcement_line, command_span)
+ var/obj/machinery/announcement_system/announcer = get_announcement_system(aas_config_entry_type, source, channels)
+ if (!announcer)
+ return
+ announcer.announce(aas_config_entry_type, variables_map, channels, announcement_line, command_span)
+
+/datum/aas_config_entry
+ var/name = "AAS configurable entry"
+ // Should we broadcast this announcement?
+ var/enabled = TRUE
+ // The announcement message. Key will be displayed in the UI.
+ var/list/announcement_lines_map = list("Message" = "This is a default announcement line.")
+ // Goes before tooltips for vars, mainly used if announcement has no replacable vars
+ var/general_tooltip
+ // Contains all replacable vars and their tooltips
+ var/list/vars_and_tooltips_map = list()
+ // Can be changed or disabled by players
+ var/modifiable = TRUE
+
+/// Compiles the announcement message with the provided variables. Announcement line is optional.
+/datum/aas_config_entry/proc/compile_announce(list/variables_map, announcement_line)
+ var/announcement_message = LAZYACCESS(announcement_lines_map, announcement_line)
+ // If index was provided LAZYACCESS will return us a key, not value
+ if (isnum(announcement_line))
+ announcement_message = announcement_lines_map[announcement_message]
+ // Fallback - first line
+ if (!announcement_message)
+ announcement_message = announcement_lines_map[announcement_lines_map[1]]
+ // Replace variables with their value
+ for(var/variable in vars_and_tooltips_map)
+ announcement_message = replacetext_char(announcement_message, "%[variable]", variables_map[variable] || "\[NO DATA\]")
+ return announcement_message
+
+/// Called when the announcement system is emagged or EMPed.
+/datum/aas_config_entry/proc/act_up()
+ SHOULD_CALL_PARENT(TRUE)
+
+ // Please do not mess with entries, that players can't fix.
+ if(!modifiable)
+ return TRUE
+ return FALSE
+
+/*
+ Global config entries for the announcement system.
+*/
+
+/datum/aas_config_entry/arrival
+ name = "Arrival Announcement"
+ announcement_lines_map = list(
+ "Message" = "%PERSON has signed up as %RANK")
+ vars_and_tooltips_map = list(
+ "PERSON" = "will be replaced with their name.",
+ "RANK" = "with their job."
+ )
+
+/datum/aas_config_entry/arrival/act_up()
+ . = ..()
+ if (.)
+ return
-/obj/machinery/announcement_system/emp_act(severity)
+ announcement_lines_map["Message"] = pick("#!@%ERR-34%2 CANNOT LOCAT@# JO# F*LE!",
+ "CRITICAL ERROR 99.",
+ "ERR)#: DA#AB@#E NOT F(*ND!")
+
+/datum/aas_config_entry/newhead
+ name = "Departmental Head Announcement"
+ announcement_lines_map = list(
+ "Message" = "%PERSON, %RANK, is the department head.")
+ vars_and_tooltips_map = list(
+ "PERSON" = "will be replaced with their name.",
+ "RANK" = "with their job."
+ )
+
+/datum/aas_config_entry/newhead/act_up()
. = ..()
- if(!(machine_stat & (NOPOWER|BROKEN)) && !(. & EMP_PROTECT_SELF))
- act_up()
+ if (.)
+ return
-/obj/machinery/announcement_system/emag_act(mob/user, obj/item/card/emag/emag_card)
- if(obj_flags & EMAGGED)
- return FALSE
- obj_flags |= EMAGGED
- act_up()
- balloon_alert(user, "announcement strings corrupted")
- return TRUE
+ announcement_lines_map["Message"] = pick("OV#RL()D: \[UNKNOWN??\] DET*#CT)D!",
+ "ER)#R - B*@ TEXT F*O(ND!",
+ "AAS.exe is not responding. NanoOS is searching for a solution to the problem.")
+
+/datum/aas_config_entry/arrivals_broken
+ name = "Arrivals Shuttle Malfunction Announcement"
+ announcement_lines_map = list(
+ "Message" = "The arrivals shuttle has been damaged. Docking for repairs...")
+ general_tooltip = "Broadcasted, when arrivals shuttle docks for repairs. No replacable variables provided."
+ modifiable = FALSE
+
+/datum/aas_config_entry/announce_officer
+ name = "Security Alert: Officer Arrival Announcement"
+ announcement_lines_map = list(
+ "Message" = "Officer %OFFICER has been assigned to %DEPARTMENT.")
+ vars_and_tooltips_map = list(
+ "OFFICER" = "will be replaced with the officer's name.",
+ "DEPARTMENT" = "with the department they were assigned to."
+ )
+ modifiable = FALSE
diff --git a/code/game/machinery/civilian_bounties.dm b/code/game/machinery/civilian_bounties.dm
index c1a73764e35f..4e24f05b055c 100644
--- a/code/game/machinery/civilian_bounties.dm
+++ b/code/game/machinery/civilian_bounties.dm
@@ -287,25 +287,10 @@
var/datum/bank_account/bounty_holder_account
///Bank account of the person who receives the handling tip.
var/datum/bank_account/bounty_handler_account
- ///Our internal radio.
- var/obj/item/radio/radio
- ///The key our internal radio uses.
- var/radio_key = /obj/item/encryptionkey/headset_cargo
/obj/item/bounty_cube/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NO_BARCODES, INNATE_TRAIT) // Don't allow anyone to override our pricetag component with a barcode
- radio = new(src)
- radio.keyslot = new radio_key
- radio.set_listening(FALSE)
- radio.recalculateChannels()
- RegisterSignal(radio, COMSIG_ITEM_PRE_EXPORT, PROC_REF(on_export))
-
-/obj/item/bounty_cube/Destroy()
- if(radio)
- UnregisterSignal(radio, COMSIG_ITEM_PRE_EXPORT)
- QDEL_NULL(radio)
- return ..()
/obj/item/bounty_cube/examine()
. = ..()
@@ -314,29 +299,20 @@
if(handler_tip && !bounty_handler_account)
. += span_notice("Scan this in the cargo shuttle with an export scanner to register your bank account for the [bounty_value * handler_tip] credit handling tip.")
-/*
- * Signal proc for [COMSIG_ITEM_EXPORTED], registered on the internal radio.
- *
- * Deletes the internal radio before being exported,
- * to stop it from bring counted as an export.
- *
- * No 4 free credits for you!
- */
-/obj/item/bounty_cube/proc/on_export(datum/source)
- SIGNAL_HANDLER
-
- QDEL_NULL(radio)
- return COMPONENT_STOP_EXPORT // stops the radio from exporting, not the cube
-
/obj/item/bounty_cube/process(seconds_per_tick)
//if our nag cooldown has finished and we aren't on Centcom or in transit, then nag
if(COOLDOWN_FINISHED(src, next_nag_time) && !is_centcom_level(z) && !is_reserved_level(z))
- //set up our nag message
+ //set up our fallback message, in case of AAS being broken it will be sent to card holders
var/nag_message = "[src] is unsent in [get_area(src)]."
//nag on Supply channel and reduce the speed bonus multiplier to nothing
- var/speed_bonus_lost = "[speed_bonus ? " Speedy delivery bonus of [bounty_value * speed_bonus] credit\s lost." : ""]"
- radio.talk_into(src, "[nag_message][speed_bonus_lost]", RADIO_CHANNEL_SUPPLY)
+ var/obj/machinery/announcement_system/aas = get_announcement_system(/datum/aas_config_entry/bounty_cube_unsent, src)
+ if (aas)
+ nag_message = aas.compile_config_message(/datum/aas_config_entry/bounty_cube_unsent, list("LOCATION" = get_area_name(src), "COST" = bounty_value), "Regular Message")
+ if (speed_bonus)
+ aas.announce(/datum/aas_config_entry/bounty_cube_unsent, list("LOCATION" = get_area_name(src), "COST" = bounty_value, "BONUSLOST" = bounty_value * speed_bonus), list(RADIO_CHANNEL_SUPPLY), "When Bonus Lost")
+ else
+ aas.broadcast("[nag_message]", list(RADIO_CHANNEL_SUPPLY))
speed_bonus = 0
//alert the holder
@@ -361,7 +337,13 @@
AddComponent(/datum/component/gps, "[src]")
START_PROCESSING(SSobj, src)
COOLDOWN_START(src, next_nag_time, nag_cooldown)
- radio.talk_into(src,"Created in [get_area(src)] by [bounty_holder] ([bounty_holder_job]). Speedy delivery bonus lost in [time2text(next_nag_time - world.time,"mm:ss")].", RADIO_CHANNEL_SUPPLY)
+ aas_config_announce(/datum/aas_config_entry/bounty_cube_created, list(
+ "LOCATION" = get_area_name(src),
+ "PERSON" = bounty_holder,
+ "RANK" = bounty_holder_job,
+ "BONUSTIME" = time2text(next_nag_time - world.time,"mm:ss"),
+ "COST" = bounty_value
+ ), src, list(RADIO_CHANNEL_SUPPLY))
//for when you need a REAL bounty cube to test with and don't want to do a bounty each time your code changes
/obj/item/bounty_cube/debug_cube
@@ -407,4 +389,27 @@
qdel(src)
uses--
+/datum/aas_config_entry/bounty_cube_created
+ name = "Cargo Alert: Bounty Cube Created"
+ announcement_lines_map = list(
+ "Message" = "A %COST cr bounty cube has been created in %LOCATION by %PERSON (%RANK). Speedy delivery bonus lost in %BONUSTIME.")
+ vars_and_tooltips_map = list(
+ "LOCATION" = "will be replaced with the location of the cube.",
+ "PERSON" = "with who created the cube.",
+ "RANK" = "with their job.",
+ "BONUSTIME" = "with the time left for speedy delivery tip.",
+ "COST" = "with the cost of the cube.",
+ )
+
+/datum/aas_config_entry/bounty_cube_unsent
+ name = "Cargo Alert: Bounty Cube Unsent"
+ announcement_lines_map = list(
+ "Regular Message" = "The %COST cr bounty cube is unsent in %LOCATION.",
+ "When Bonus Lost" = "The %COST cr bounty cube is unsent in %LOCATION. Speedy delivery bonus of %BONUSLOST credits lost.")
+ vars_and_tooltips_map = list(
+ "LOCATION" = "will be replaced with the location of the cube.",
+ "COST" = "with the cost of the cube.",
+ "BONUSLOST" = "with the lost bonus tip, it will be sent just for When Bonus Lost message!",
+ )
+
#undef CIV_BOUNTY_SPLIT
diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm
index 002bbf578b31..3a270bbc099e 100644
--- a/code/game/machinery/computer/arcade/orion.dm
+++ b/code/game/machinery/computer/arcade/orion.dm
@@ -28,7 +28,6 @@
var/spaceport_raided = FALSE
var/gameStatus = ORION_STATUS_START
- var/obj/item/radio/radio
var/list/gamers = list()
var/killed_crew = 0
@@ -40,15 +39,12 @@
var/datum/orion_event/new_event = new path(src)
events[new_event] = new_event.weight
orion_events = events
- radio = new /obj/item/radio(src)
- radio.set_listening(FALSE)
setup_events()
/obj/machinery/computer/arcade/orion_trail/proc/setup_events()
events = orion_events.Copy()
/obj/machinery/computer/arcade/orion_trail/Destroy()
- QDEL_NULL(radio)
events = null
return ..()
@@ -123,14 +119,15 @@
gamers[gamer]++ // How many times the player has 'prestiged' (massacred their crew)
if(gamers[gamer] > ORION_GAMER_REPORT_THRESHOLD && prob(20 * gamers[gamer]))
+ aas_config_announce(/datum/aas_config_entry/orion_violent_behavior_alert, list(
+ "PERSON" = gamer.name,
+ "LOCATION" = get_area_name(src),
+ "SOURCE" = name), src, list(RADIO_CHANNEL_SECURITY), RADIO_CHANNEL_SECURITY)
- radio.set_frequency(FREQ_SECURITY)
- radio.talk_into(src, "SECURITY ALERT: Crewmember [gamer] recorded displaying antisocial tendencies in [get_area(src)]. Please watch for violent behavior.", FREQ_SECURITY)
-
- radio.set_frequency(FREQ_MEDICAL)
- radio.talk_into(src, "PSYCH ALERT: Crewmember [gamer] recorded displaying antisocial tendencies in [get_area(src)]. Please schedule psych evaluation.", FREQ_MEDICAL)
-
- remove_radio_all(radio)//so we dont keep transmitting sec and medical comms
+ aas_config_announce(/datum/aas_config_entry/orion_violent_behavior_alert, list(
+ "PERSON" = gamer.name,
+ "LOCATION" = get_area_name(src),
+ "SOURCE" = name), src, list(RADIO_CHANNEL_MEDICAL), RADIO_CHANNEL_MEDICAL)
gamers[gamer] = ORION_GAMER_PAMPHLET //next report send a pamph
@@ -547,4 +544,17 @@
dialogue_level++
addtimer(CALLBACK(src, PROC_REF(commit_explosion), dialogue_level), time_for_next_level)
+/datum/aas_config_entry/orion_violent_behavior_alert
+ // Well we don't want to show that only Orion Trails reports violent behavior, eh-h?
+ name = "Violent Behavior Alert"
+ announcement_lines_map = list(
+ RADIO_CHANNEL_SECURITY = "SECURITY ALERT: Crewmember %PERSON recorded displaying antisocial tendencies in %LOCATION by %SOURCE. Please watch for violent behavior.",
+ RADIO_CHANNEL_MEDICAL = "PSYCH ALERT: Crewmember %PERSON recorded displaying antisocial tendencies in %LOCATION by %SOURCE. Please schedule psych evaluation.",
+ )
+ vars_and_tooltips_map = list(
+ "PERSON" = "will be replaced with the crewmember reported",
+ "LOCATION" = "with the area of violent behavior",
+ "SOURCE" = "with the reporter",
+ )
+
#undef ORION_TRAIL_WINTURN
diff --git a/code/game/machinery/computer/orders/order_computer/cook_order.dm b/code/game/machinery/computer/orders/order_computer/cook_order.dm
index 3ac23770d3e2..7518be414e82 100644
--- a/code/game/machinery/computer/orders/order_computer/cook_order.dm
+++ b/code/game/machinery/computer/orders/order_computer/cook_order.dm
@@ -8,10 +8,11 @@
CATEGORY_SAUCES_REAGENTS,
)
blackbox_key = "chef"
+ announcement_line = "The kitchen has ordered groceries which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!"
/obj/machinery/computer/order_console/cook/order_groceries(mob/living/purchaser, obj/item/card/id/card, list/groceries)
say("Thank you for your purchase! It will arrive on the next cargo shuttle!")
- radio.talk_into(src, "The kitchen has ordered groceries which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!", radio_channel)
+ aas_config_announce(/datum/aas_config_entry/order_console, list(), src, list(radio_channel), capitalize(blackbox_key))
for(var/datum/orderable_item/ordered_item in groceries)
if(!(ordered_item.category_index in order_categories))
groceries.Remove(ordered_item)
diff --git a/code/game/machinery/computer/orders/order_computer/mining_order.dm b/code/game/machinery/computer/orders/order_computer/mining_order.dm
index 54946f8afeec..c83468eede70 100644
--- a/code/game/machinery/computer/orders/order_computer/mining_order.dm
+++ b/code/game/machinery/computer/orders/order_computer/mining_order.dm
@@ -24,6 +24,7 @@
CATEGORY_PKA,
)
blackbox_key = "mining"
+ announcement_line = "A shaft miner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!"
/obj/machinery/computer/order_console/mining/subtract_points(final_cost, obj/item/card/id/card)
if(final_cost <= card.registered_account.mining_points)
@@ -56,7 +57,7 @@
can_be_cancelled = FALSE,
)
say("Thank you for your purchase! It will arrive on the next cargo shuttle!")
- radio.talk_into(src, "A shaft miner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!", radio_channel)
+ aas_config_announce(/datum/aas_config_entry/order_console, list(), src, list(radio_channel), capitalize(blackbox_key))
SSshuttle.shopping_list += new_order
/obj/machinery/computer/order_console/mining/retrieve_points(obj/item/card/id/id_card)
diff --git a/code/game/machinery/computer/orders/order_computer/order_computer.dm b/code/game/machinery/computer/orders/order_computer/order_computer.dm
index 7f675924e92c..687fa21f1b89 100644
--- a/code/game/machinery/computer/orders/order_computer/order_computer.dm
+++ b/code/game/machinery/computer/orders/order_computer/order_computer.dm
@@ -19,10 +19,10 @@ GLOBAL_LIST_EMPTY(order_console_products)
COOLDOWN_DECLARE(order_cooldown)
///Cooldown time between uses, express console will have extra time depending on express_cost_multiplier.
var/cooldown_time = 60 SECONDS
- ///The radio the console can speak into
- var/obj/item/radio/radio
///The channel we will attempt to speak into through our radio.
var/radio_channel = RADIO_CHANNEL_SUPPLY
+ ///What line we should announce on ordering_groceries
+ var/announcement_line
///The kind of cash does the console use.
var/credit_type = CREDIT_TYPE_CREDIT
@@ -41,11 +41,6 @@ GLOBAL_LIST_EMPTY(order_console_products)
/obj/machinery/computer/order_console/Initialize(mapload)
. = ..()
- radio = new(src)
- radio.set_frequency(FREQ_SUPPLY)
- radio.subspace_transmission = TRUE
- radio.canhear_range = 0
- radio.recalculateChannels()
if(GLOB.order_console_products.len)
return
@@ -54,10 +49,6 @@ GLOBAL_LIST_EMPTY(order_console_products)
continue
GLOB.order_console_products += new path
-/obj/machinery/computer/order_console/Destroy()
- QDEL_NULL(radio)
- return ..()
-
/obj/machinery/computer/order_console/proc/get_total_cost()
var/cost = 0
for(var/datum/orderable_item/item as anything in grocery_list)
@@ -243,4 +234,21 @@ GLOBAL_LIST_EMPTY(order_console_products)
/obj/machinery/computer/order_console/proc/order_groceries(mob/living/purchaser, obj/item/card/id/card, list/groceries)
return
+/datum/aas_config_entry/order_console
+ name = "Local Ordering Console Announcements"
+ announcement_lines_map = list()
+ general_tooltip = "Used to make announces, when consoles listed here placing new order"
+
+/datum/aas_config_entry/order_console/New()
+ . = ..()
+ for(var/obj/machinery/computer/order_console/subconsole as anything in subtypesof(/obj/machinery/computer/order_console))
+ if(subconsole.blackbox_key)
+ announcement_lines_map[capitalize(subconsole.blackbox_key)] = subconsole.announcement_line
+
+/datum/aas_config_entry/order_console/compile_announce(list/variables_map, announcement_line)
+ if (!announcement_lines_map.len)
+ announcement_lines_map["Error"] = "Unknown Error happened, while we tried to procceed an order, please report this to Nanotrasen."
+ . = ..()
+
+
#undef CREDIT_TYPE_CREDIT
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index 6c1470279312..f3b69dab2cee 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -29,15 +29,12 @@
var/list/flashers = list()
///List of weakrefs to nearby closets
var/list/closets = list()
- ///needed to send messages to sec radio
- var/obj/item/radio/sec_radio
+ ///Channel to report prisoneer's release
+ var/broadcast_channel = RADIO_CHANNEL_SECURITY
/obj/machinery/status_display/door_timer/Initialize(mapload)
. = ..()
- sec_radio = new/obj/item/radio(src)
- sec_radio.set_listening(FALSE)
-
if(id != null)
for(var/obj/machinery/door/window/brigdoor/M in urange(20, src))
if (M.id == id)
@@ -130,8 +127,7 @@
return 0
if(!forced)
- sec_radio.set_frequency(FREQ_SECURITY)
- sec_radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY)
+ aas_config_announce(/datum/aas_config_entry/brig_cell_release_announcement, list("CELL" = name), src, list(broadcast_channel))
timing = FALSE
activation_time = null
@@ -274,6 +270,15 @@
continue
timer_end(forced = TRUE)
+/datum/aas_config_entry/brig_cell_release_announcement
+ name = "Security Alert: Cell Timer Expired"
+ announcement_lines_map = list(
+ "Message" = "Timer for %CELL has expired. Releasing prisoner.",
+ )
+ vars_and_tooltips_map = list(
+ "CELL" = "will be replaced with the cell name.",
+ )
+
#undef PRESET_SHORT
#undef PRESET_MEDIUM
#undef PRESET_LONG
diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm
index f4b9402e6ad5..a63802829d40 100644
--- a/code/game/machinery/requests_console.dm
+++ b/code/game/machinery/requests_console.dm
@@ -44,8 +44,6 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
var/message_verified_by = ""
/// If a message is stamped, this will contain the stamp name
var/message_stamped_by = ""
- /// Reference to the internal radio
- var/obj/item/radio/radio
///If an emergency has been called by this device. Acts as both a cooldown and lets the responder know where it the emergency was triggered from
var/emergency
/// If ore redemption machines will send an update when it receives new ores.
@@ -125,13 +123,9 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
GLOB.req_console_all += src
GLOB.req_console_ckey_departments[ckey(department)] = department // and then we set ourselves a listed name
-
- radio = new /obj/item/radio(src)
- radio.set_listening(FALSE)
find_and_hang_on_wall()
/obj/machinery/requests_console/Destroy()
- QDEL_NULL(radio)
QDEL_LIST(messages)
GLOB.req_console_all -= src
return ..()
@@ -169,20 +163,15 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
if("set_emergency")
if(emergency)
return
- var/radio_freq
switch(params["emergency"])
if(REQ_EMERGENCY_SECURITY) //Security
- radio_freq = FREQ_SECURITY
+ aas_config_announce(/datum/aas_config_entry/rc_emergency, list("LOCATION" = department), null, list(RADIO_CHANNEL_SECURITY), REQ_EMERGENCY_SECURITY)
if(REQ_EMERGENCY_ENGINEERING) //Engineering
- radio_freq = FREQ_ENGINEERING
+ aas_config_announce(/datum/aas_config_entry/rc_emergency, list("LOCATION" = department), null, list(RADIO_CHANNEL_ENGINEERING), REQ_EMERGENCY_ENGINEERING)
if(REQ_EMERGENCY_MEDICAL) //Medical
- radio_freq = FREQ_MEDICAL
- if(radio_freq)
- emergency = params["emergency"]
- radio.set_frequency(radio_freq)
- radio.talk_into(src,"[emergency] emergency in [department]!!",radio_freq)
- update_appearance()
- addtimer(CALLBACK(src, PROC_REF(clear_emergency)), 5 MINUTES)
+ aas_config_announce(/datum/aas_config_entry/rc_emergency, list("LOCATION" = department), null, list(RADIO_CHANNEL_MEDICAL), REQ_EMERGENCY_MEDICAL)
+ update_appearance()
+ addtimer(CALLBACK(src, PROC_REF(clear_emergency)), 5 MINUTES)
return TRUE
if("send_announcement")
if(!COOLDOWN_FINISHED(src, announcement_cooldown))
@@ -246,20 +235,22 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
///Sends the message from the request console
/obj/machinery/requests_console/proc/send_message(recipient, message, priority, request_type)
- var/radio_freq
+ var/radio_channel
+ // They all naming them wrong, all the time... I'll probably rewrite this later in separate PR.
+ // Automatically from areas or via mapping helpers. (ther is no "Cargobay Request Console" in any map)
switch(ckey(recipient))
if("bridge")
- radio_freq = FREQ_COMMAND
+ radio_channel = RADIO_CHANNEL_COMMAND
if("medbay")
- radio_freq = FREQ_MEDICAL
+ radio_channel = RADIO_CHANNEL_MEDICAL
if("science")
- radio_freq = FREQ_SCIENCE
+ radio_channel = RADIO_CHANNEL_SCIENCE
if("engineering")
- radio_freq = FREQ_ENGINEERING
+ radio_channel = RADIO_CHANNEL_ENGINEERING
if("security")
- radio_freq = FREQ_SECURITY
+ radio_channel = RADIO_CHANNEL_SECURITY
if("cargobay", "mining")
- radio_freq = FREQ_SUPPLY
+ radio_channel = RADIO_CHANNEL_SUPPLY
var/datum/signal/subspace/messaging/rc/signal = new(src, list(
"sender_department" = department,
@@ -268,7 +259,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
"verified" = message_verified_by,
"stamped" = message_stamped_by,
"priority" = priority,
- "notify_freq" = radio_freq,
+ "notify_channel" = radio_channel,
"request_type" = request_type,
))
signal.send_to_receivers()
@@ -351,15 +342,26 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments)
SStgui.update_uis(src)
- var/alert = new_message.get_alert()
-
if(!silent)
playsound(src, 'sound/machines/twobeep_high.ogg', 50, TRUE)
- say(alert)
-
- if(new_message.radio_freq)
- radio.set_frequency(new_message.radio_freq)
- radio.talk_into(src, "[alert]: [new_message.content]", new_message.radio_freq)
+ say(new_message.get_alert())
+
+ if(new_message.radio_channel)
+ var/authentication
+ var/announcement_line = "Unauthenticated"
+ if (new_message.message_verified_by)
+ authentication = new_message.message_verified_by
+ announcement_line = "Verified with ID"
+ else if (new_message.message_stamped_by)
+ authentication = new_message.message_stamped_by
+ announcement_line = "Stamped with stamp"
+
+ aas_config_announce(/datum/aas_config_entry/rc_new_message, list(
+ "AUTHENTICATION" = authentication,
+ "SENDER" = new_message.sender_department,
+ "RECEIVER" = department,
+ "MESSAGE" = new_message.content
+ ), null, list(new_message.radio_channel), announcement_line, new_message.priority == REQ_EXTREME_MESSAGE_PRIORITY)
/obj/machinery/requests_console/crowbar_act(mob/living/user, obj/item/tool)
tool.play_tool_sound(src, 50)
@@ -416,6 +418,32 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/requests_console/auto_name, 30)
result_path = /obj/machinery/requests_console/auto_name
pixel_shift = 30
+/datum/aas_config_entry/rc_emergency
+ name = "RC Alert: Emergency"
+ announcement_lines_map = list(
+ "Security" = "Security emergency in %LOCATION!!!",
+ "Engineering" = "Engineering emergency in %LOCATION!!!",
+ "Medical" = "Medical emergency in %LOCATION!!!",
+ )
+ vars_and_tooltips_map = list(
+ "LOCATION" = "will be replaced with the department name",
+ )
+
+/datum/aas_config_entry/rc_new_message
+ name = "RC Alert: New Message "
+ // Yes, players can't use html tags, however they can use speech mods like | or +, but sh-sh-sh, don't tell them!
+ announcement_lines_map = list(
+ "Unauthenticated" = "Message from %SENDER to %RECEIVER: %MESSAGE",
+ "Verified with ID" = "Message from %SENDER to %RECEIVER, Verified by %AUTHENTICATION (Authenticated): %MESSAGE",
+ "Stamped with stamp" = "Message from %SENDER to %RECEIVER, Stamped by %AUTHENTICATION (Authenticated): %MESSAGE",
+ )
+ vars_and_tooltips_map = list(
+ "AUTHENTICATION" = "will be replaced with ID or stamp, if present",
+ "SENDER" = "with the sender department ",
+ "RECEIVER" = "with the receiver department",
+ "MESSAGE" = "with the message content",
+ )
+
#undef REQ_EMERGENCY_SECURITY
#undef REQ_EMERGENCY_ENGINEERING
#undef REQ_EMERGENCY_MEDICAL
diff --git a/code/game/objects/effects/spiderwebs.dm b/code/game/objects/effects/spiderwebs.dm
index 60190ce8014b..f543f19a75a7 100644
--- a/code/game/objects/effects/spiderwebs.dm
+++ b/code/game/objects/effects/spiderwebs.dm
@@ -276,6 +276,6 @@
/obj/structure/spider/effigy/Initialize(mapload)
. = ..()
- AddElement(/datum/element/temporary_atom, 1 MINUTES)
+ fade_into_nothing(1 MINUTES)
#undef SPIDER_WEB_TINT
diff --git a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
index 6ffd7b467d9a..1d6e75eb6097 100644
--- a/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
+++ b/code/game/objects/items/circuitboards/machines/machine_circuitboards.dm
@@ -1699,3 +1699,35 @@
/datum/stock_part/water_recycler = 1,
/datum/stock_part/servo = 1,
)
+
+/obj/item/circuitboard/machine/quantum_server
+ name = "Quantum Server"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/quantum_server
+ req_components = list(
+ /datum/stock_part/servo = 2,
+ /datum/stock_part/scanning_module = 1,
+ /datum/stock_part/capacitor = 1,
+ )
+
+/obj/item/circuitboard/machine/netpod
+ name = "Netpod"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/netpod
+ req_components = list(
+ /datum/stock_part/servo = 1,
+ /datum/stock_part/matter_bin = 2,
+ )
+
+/obj/item/circuitboard/computer/quantum_console
+ name = "Quantum Console"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/computer/quantum_console
+
+/obj/item/circuitboard/machine/byteforge
+ name = "Byteforge"
+ greyscale_colors = CIRCUIT_COLOR_SUPPLY
+ build_path = /obj/machinery/byteforge
+ req_components = list(
+ /datum/stock_part/micro_laser = 1,
+ )
diff --git a/code/game/objects/items/food/pizza.dm b/code/game/objects/items/food/pizza.dm
index 3700bf09ee47..ef88427d4dfe 100644
--- a/code/game/objects/items/food/pizza.dm
+++ b/code/game/objects/items/food/pizza.dm
@@ -124,6 +124,13 @@
foodtypes = GRAIN | VEGETABLES | DAIRY | MEAT
crafting_complexity = FOOD_COMPLEXITY_3
+/obj/item/food/pizzaslice/meat/pizzeria //Reward for pizzeria bitrunning domain
+ name = "pizzeria meatpizza slice"
+ desc = "An ostensibly nutritious slice of meatpizza from a long-closed pizzeria."
+ food_reagents = null
+ tastes = list("crust" = 1, "ketchup" = 1, "'cheese'" = 1, "mystery meat" = 1, "glue" = 1)
+ foodtypes = null
+
/obj/item/food/pizza/mushroom
name = "mushroom pizza"
desc = "Very special pizza."
diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm
index bc49f8ea781f..2a9e6d0d14ba 100644
--- a/code/game/objects/items/storage/briefcase.dm
+++ b/code/game/objects/items/storage/briefcase.dm
@@ -93,6 +93,17 @@
atom_storage.max_specific_storage = WEIGHT_CLASS_NORMAL
AddComponent(/datum/component/lockable_storage)
+/// Base container used for gimmick disks.
+/obj/item/storage/briefcase/secure/digital_storage
+ name = "digi-case"
+ desc = "It's made of AUTHENTIC digital leather and has a price-tag still attached. Its owner must be a real professional."
+ icon_state = "secure"
+ base_icon_state = "secure"
+ inhand_icon_state = "sec-case"
+
+/obj/item/storage/briefcase/secure/digital_storage/PopulateContents()
+ return
+
///Syndie variant of Secure Briefcase. Contains space cash, slightly more robust.
/obj/item/storage/briefcase/secure/syndie
force = 15
diff --git a/code/game/objects/structures/outfit_wardrobe.dm b/code/game/objects/structures/outfit_wardrobe.dm
new file mode 100644
index 000000000000..e6cedb2fdc94
--- /dev/null
+++ b/code/game/objects/structures/outfit_wardrobe.dm
@@ -0,0 +1,87 @@
+// if you need to access this elsewhere you already fucked up
+#define TRAIT_WARDROBE_USED "wardrobe_used"
+
+/obj/structure/outfit_wardrobe
+ name = "outfit wardrobe"
+ desc = "Peek in and select one of several snazzy outfits. Narnia not included."
+ icon = 'icons/obj/storage/closet.dmi'
+ icon_state = "fullcabinet"
+ base_icon_state = "fullcabinet"
+ obj_flags = INDESTRUCTIBLE
+ density = TRUE
+ anchored = TRUE
+ /**
+ * Assoc list of outfits to how many charges left.
+ * If value is INFINITY, the amount is infinite. Otherwise, it decreases by one per use.
+ * At zero it can't be picked.
+ * Value is unique per wardrobe.
+ */
+ var/list/selectable_outfits_to_amount = list(
+ /datum/outfit/cat_butcher = INFINITY,
+ /datum/outfit/job/clown = 2,
+ )
+ /// Adds a trait with the source of wardrobe_id if this is TRUE, which is checked to prevent reuse.
+ var/one_use = TRUE
+ /// All wardrobes that share this id, share the one use restriction. If one_use is FALSE, it effectively does nothing.
+ var/wardrobe_id = "asparagus"
+ /// Humanize species that need unique environments to survive.
+ var/humanize_plasmamen = TRUE
+
+/obj/structure/outfit_wardrobe/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/living/carbon/human/human_user = user
+ if(!ishuman(human_user))
+ return
+
+ if(one_use && HAS_TRAIT_FROM(human_user, TRAIT_WARDROBE_USED, wardrobe_id))
+ to_chat(human_user, span_notice("You already picked an outfit!"))
+ return
+
+ var/list/display_classes = list()
+ var/datum/outfit/chosen_class
+
+ for(var/datum/outfit/dressup as anything in selectable_outfits_to_amount)
+ if(selectable_outfits_to_amount[dressup] == 0)
+ continue
+ var/datum/radial_menu_choice/option = new(src)
+ // We take the type of either the suit storage or head item (Likely to be relevant) or barring that the uniform
+ var/obj/item/sprite_path = initial(dressup.suit_store) || initial(dressup.head) || initial(dressup.uniform)
+ if(!sprite_path)
+ stack_trace("[dressup] outfit got no god damn items to use for sprite")
+ sprite_path = /obj/item/food/grown/citrus/orange_3d
+ option.image = image(icon = initial(sprite_path.icon), icon_state = initial(sprite_path.icon_state))
+ option.info = span_boldnotice("[initial(dressup.name)]") // no desc..
+ display_classes[dressup] = option
+
+ if(!length(display_classes))
+ to_chat(human_user, span_warning("There are no available outfits!"))
+ return
+
+ sort_list(display_classes)
+ var/choice = show_radial_menu(human_user, src, display_classes, radius = 38, require_near = TRUE)
+ if(!choice)
+ return
+
+ chosen_class = choice
+
+ human_user.balloon_alert(human_user, LOWER_TEXT(chosen_class.name))
+ playsound(human_user, 'sound/items/un_zip.ogg', 33)
+ playsound(src, 'sound/machines/wooden_closet_open.ogg', 25)
+ icon_state = "fullcabinet_open"
+ if(!do_after(human_user, 3 SECONDS) || selectable_outfits_to_amount[choice] == 0)
+ playsound(src, 'sound/machines/wooden_closet_close.ogg', 50)
+ icon_state = base_icon_state
+ return
+ selectable_outfits_to_amount[choice]--
+ playsound(src, 'sound/machines/wooden_closet_close.ogg', 50)
+ icon_state = base_icon_state
+ playsound(human_user, 'sound/items/zip_up.ogg', 33)
+
+ human_user.drop_everything()
+ human_user.equipOutfit(chosen_class)
+ ADD_TRAIT(human_user, TRAIT_WARDROBE_USED, wardrobe_id)
+
+#undef TRAIT_WARDROBE_USED
diff --git a/code/modules/admin/smites/smite.dm b/code/modules/admin/smites/_smite.dm
similarity index 100%
rename from code/modules/admin/smites/smite.dm
rename to code/modules/admin/smites/_smite.dm
diff --git a/code/modules/admin/smites/retcon.dm b/code/modules/admin/smites/retcon.dm
new file mode 100644
index 000000000000..461b7b330bbf
--- /dev/null
+++ b/code/modules/admin/smites/retcon.dm
@@ -0,0 +1,39 @@
+/datum/smite/retcon
+ name = "Retcon"
+ /// how long until the thing attacked by this smite gets deleted
+ var/timer
+ /// the time it takes to actually do the fade out animation, the victim will always have some time still fully visible
+ var/fade_out_timer
+
+/datum/smite/retcon/configure(client/user)
+ timer = tgui_input_number(user, "How long should it take before the target disappears, in seconds?", "Retcon", 5)
+
+ if (isnull(timer))
+ return FALSE
+
+ fade_out_timer = timer*3*0.2
+
+/datum/smite/retcon/effect(client/user, mob/living/target)
+ . = ..()
+ target.fade_into_nothing(timer SECONDS,fade_out_timer SECONDS)
+ if(ishuman(target))
+ delete_record(target)
+ delete_bank_account(target)
+ reopen_job_slot(target)
+
+/datum/smite/retcon/proc/delete_record(mob/living/target)
+ var/name = target.real_name
+ GLOB.manifest.remove(name)
+
+/datum/smite/retcon/proc/delete_bank_account(mob/living/target)
+ var/name = target.real_name
+ var/account_list = flatten_list(SSeconomy.bank_accounts_by_id)
+ for(var/datum/bank_account/account in account_list)
+ if(account.account_holder == name)
+ qdel(account)
+ return
+
+/datum/smite/retcon/proc/reopen_job_slot(mob/living/target)
+ var/datum/job/target_job = target.mind?.assigned_role
+ if(target_job)
+ target_job.total_positions += 1
diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm
index 22212e944690..9062a0e081eb 100644
--- a/code/modules/antagonists/heretic/items/heretic_blades.dm
+++ b/code/modules/antagonists/heretic/items/heretic_blades.dm
@@ -39,6 +39,13 @@
SEND_SIGNAL(user, COMSIG_HERETIC_BLADE_ATTACK, target, src)
/obj/item/melee/sickly_blade/attack_self(mob/user)
+ if(HAS_TRAIT(user, TRAIT_NO_TELEPORT))
+ user.balloon_alert(user, "can't break!")
+ return
+ seek_safety(user)
+
+/// Attempts to teleport the passed mob to somewhere safe on the station, if they can use the blade.
+/obj/item/melee/sickly_blade/proc/seek_safety(mob/user)
var/turf/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE)
if(IS_HERETIC_OR_MONSTER(user))
if(do_teleport(user, safe_turf, channel = TELEPORT_CHANNEL_MAGIC))
diff --git a/code/modules/antagonists/heretic/items/madness_mask.dm b/code/modules/antagonists/heretic/items/madness_mask.dm
index f421aaefbc30..eee0cb231391 100644
--- a/code/modules/antagonists/heretic/items/madness_mask.dm
+++ b/code/modules/antagonists/heretic/items/madness_mask.dm
@@ -56,6 +56,9 @@
if(IS_HERETIC_OR_MONSTER(human_in_range) || human_in_range.stat > SOFT_CRIT || human_in_range.is_blind())
continue
+ if(human_in_range.can_block_magic(MAGIC_RESISTANCE|MAGIC_RESISTANCE_MIND))
+ continue
+
human_in_range.mob_mood.direct_sanity_drain(rand(-2, -20) * seconds_per_tick)
if(SPT_PROB(60, seconds_per_tick))
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm
index bc6cb750b219..6782dba73af6 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_map.dm
@@ -87,7 +87,7 @@ GLOBAL_LIST_EMPTY(heretic_sacrifice_landmarks)
has_gravity = STANDARD_GRAVITY
ambience_index = AMBIENCE_SPOOKY
sound_environment = SOUND_ENVIRONMENT_CAVE
- area_flags = UNIQUE_AREA | NOTELEPORT | HIDDEN_AREA | BLOCK_SUICIDE
+ area_flags = NOTELEPORT | HIDDEN_AREA | BLOCK_SUICIDE | NO_BOH
/area/centcom/heretic_sacrifice/Initialize(mapload)
if(!ambientsounds)
diff --git a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
index 57d2f91615be..28a6de3a1d8e 100644
--- a/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
+++ b/code/modules/atmospherics/machinery/components/unary_devices/cryo.dm
@@ -98,8 +98,6 @@
var/conduction_coefficient = 0.3
///The beaker usually contains cryoxadone that is pumped into the mob
var/obj/item/reagent_containers/cup/beaker = null
- ///Inform medical about cryo status over this radio
- var/obj/item/radio/radio
/// Visual content - Occupant
var/atom/movable/visual/cryo_occupant/occupant_vis
/// tracks everything the machine is currently treating
@@ -110,6 +108,8 @@
var/on = FALSE
/// The sound loop that can be heard when the generator is processing.
var/datum/looping_sound/cryo_cell/soundloop
+ /// For away sites, custom or admin events
+ var/broadcast_channel = RADIO_CHANNEL_MEDICAL
/datum/armor/unary_cryo_cell
energy = 100
@@ -119,12 +119,6 @@
/obj/machinery/cryo_cell/Initialize(mapload)
. = ..()
- radio = new(src)
- radio.keyslot = new /obj/item/encryptionkey/headset_med
- radio.subspace_transmission = TRUE
- radio.canhear_range = 0
- radio.recalculateChannels()
-
occupant_vis = new(mapload, src)
vis_contents += occupant_vis
internal_connector = new(loc, src, dir, TANK_STANDARD_VOLUME * 4)
@@ -137,7 +131,6 @@
vis_contents.Cut()
QDEL_NULL(occupant_vis)
- QDEL_NULL(radio)
QDEL_NULL(beaker)
QDEL_NULL(internal_connector)
QDEL_NULL(soundloop)
@@ -430,12 +423,10 @@
mob_occupant.extinguish_mob()
if(mob_occupant.stat == DEAD) // Notify doctors and potentially eject if the patient is dead
set_on(FALSE)
- var/msg = "Patient is deceased."
+ aas_config_announce(/datum/aas_config_entry/medical_cryo_announcements, list("EJECTING" = autoeject), src, list(broadcast_channel), "Deceased")
if(autoeject) // Eject if configured.
- msg += " Auto ejecting patient now."
open_machine()
playsound(src, 'sound/machines/cryo_warning.ogg', 100)
- radio.talk_into(src, msg, RADIO_CHANNEL_MEDICAL)
return PROCESS_KILL
// Don't bother with fully healed people.
@@ -464,11 +455,9 @@
if(!ongoing_treatment)
set_on(FALSE)
playsound(src, 'sound/machines/cryo_warning.ogg', 100) // Bug the doctors.
- var/msg = "Patient fully restored."
+ aas_config_announce(/datum/aas_config_entry/medical_cryo_announcements, list("EJECTING" = autoeject), src, list(broadcast_channel), "Fully Recovered")
if(autoeject) // Eject if configured.
- msg += " Auto ejecting patient now."
open_machine()
- radio.talk_into(src, msg, RADIO_CHANNEL_MEDICAL)
return PROCESS_KILL
var/datum/gas_mixture/air1 = internal_connector.gas_connector.airs[1]
@@ -494,11 +483,9 @@
//check for workable conditions
if(!internal_connector.gas_connector.nodes[1] || !air1 || !air1.gases.len || air1.total_moles() < CRYO_MIN_GAS_MOLES) // Turn off if the machine won't work.
set_on(FALSE)
- var/msg = "Insufficient cryogenic gas, shutting down."
+ aas_config_announce(/datum/aas_config_entry/medical_cryo_announcements, list("EJECTING" = autoeject), src, list(broadcast_channel), "Insufficient Gas")
if(autoeject) // Eject if configured.
- msg += " Auto ejecting patient now."
open_machine()
- radio.talk_into(src, msg, RADIO_CHANNEL_MEDICAL)
return PROCESS_KILL
//take damage from high temperatures
@@ -707,6 +694,26 @@
/obj/machinery/cryo_cell/get_remote_view_fullscreens(mob/user)
user.overlay_fullscreen("remote_view", /atom/movable/screen/fullscreen/impaired, 1)
+/datum/aas_config_entry/medical_cryo_announcements
+ name = "Medical Alert: Cryogenics Reports"
+ announcement_lines_map = list(
+ "Autoejecting" = "Auto ejecting patient now.",
+ "Deceased" = "Cryogenics report: Patient is deceased. %AUTOEJECTING",
+ "Fully Recovered" = "Cryogenics report: Patient fully restored. %AUTOEJECTING",
+ "Insufficient Gas" = "Cryogenics report: Insufficient cryogenic gas, shutting down. %AUTOEJECTING",
+ "Wound Treatment" = "Cryogenics report: Patient vitals fully recovered, continuing automated wound treatment."
+ )
+ vars_and_tooltips_map = list(
+ "AUTOEJECTING" = "will be replaced with Autoejecting line, if system reports it's necessity"
+ )
+
+/datum/aas_config_entry/medical_cryo_announcements/compile_announce(list/variables_map, announcement_line)
+ variables_map["AUTOEJECTING"] = variables_map["EJECTING"] ? announcement_lines_map["Autoejecting"] : ""
+ . = ..()
+ // Why double replacetext_char? Well, to handle cases where variable in the middle of sentence like "also %AUTOEJECTING this", so there will be no double spaces
+ // Yeah I am bad, at this, sorry (it should be a perfect place for regex usage, but I am weak)
+ . = trim(replacetext_char(replacetext_char(., "\[NO DATA\] ", ""), "\[NO DATA\]", ""))
+
#undef MAX_TEMPERATURE
#undef CRYO_MULTIPLY_FACTOR
#undef CRYO_TX_QTY
diff --git a/code/modules/awaymissions/cordon.dm b/code/modules/awaymissions/cordon.dm
index 285d0d49e105..15e418afbf2c 100644
--- a/code/modules/awaymissions/cordon.dm
+++ b/code/modules/awaymissions/cordon.dm
@@ -58,7 +58,7 @@
icon_state = "cordon"
static_lighting = FALSE
base_lighting_alpha = 255
- area_flags = UNIQUE_AREA|NOTELEPORT|HIDDEN_AREA
+ area_flags = NOTELEPORT|HIDDEN_AREA
requires_power = FALSE
/area/misc/cordon/Entered(atom/movable/arrived, area/old_area)
diff --git a/code/modules/basketball/basketball_map_loading.dm b/code/modules/basketball/basketball_map_loading.dm
index 469167367c0f..18022004f08b 100644
--- a/code/modules/basketball/basketball_map_loading.dm
+++ b/code/modules/basketball/basketball_map_loading.dm
@@ -33,7 +33,7 @@
base_lighting_alpha = 255
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
- area_flags = UNIQUE_AREA | NOTELEPORT | NO_DEATH_MESSAGE | BLOCK_SUICIDE
+ area_flags = NOTELEPORT | NO_DEATH_MESSAGE | BLOCK_SUICIDE
/datum/map_template/basketball
should_place_on_top = FALSE
diff --git a/code/modules/bitrunning/areas.dm b/code/modules/bitrunning/areas.dm
index 0656f9d65b38..aa196e95be16 100644
--- a/code/modules/bitrunning/areas.dm
+++ b/code/modules/bitrunning/areas.dm
@@ -14,7 +14,8 @@
name = "Virtual Domain Ruins"
icon_state = "bit_ruin"
icon = 'icons/area/areas_station.dmi'
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags = LOCAL_TELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags_mapping = VIRTUAL_AREA
has_gravity = STANDARD_GRAVITY
requires_power = FALSE
@@ -26,7 +27,8 @@
/area/virtual_domain/safehouse
name = "Virtual Domain Safehouse"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | VIRTUAL_SAFE_AREA | UNLIMITED_FISHING
+ area_flags = LOCAL_TELEPORT | EVENT_PROTECTED | UNLIMITED_FISHING
+ area_flags_mapping = UNIQUE_AREA | VIRTUAL_AREA | VIRTUAL_SAFE_AREA
icon_state = "bit_safe"
requires_power = FALSE
sound_environment = SOUND_ENVIRONMENT_ROOM
@@ -36,32 +38,47 @@
/area/lavaland/surface/outdoors/virtual_domain
name = "Virtual Domain Lava Ruins"
icon_state = "bit_ruin"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags = /area/virtual_domain::area_flags
+ area_flags_mapping = /area/virtual_domain::area_flags_mapping
/area/icemoon/underground/explored/virtual_domain
name = "Virtual Domain Ice Ruins"
icon_state = "bit_ice"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags = /area/virtual_domain::area_flags
+ area_flags_mapping = /area/virtual_domain::area_flags_mapping
/area/ruin/space/virtual_domain
name = "Virtual Domain Unexplored Location"
icon = 'icons/area/areas_station.dmi'
icon_state = "bit_ruin"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA
/area/space/virtual_domain
name = "Virtual Domain Space"
icon = 'icons/area/areas_station.dmi'
icon_state = "bit_space"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA | UNLIMITED_FISHING
+ area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | HIDDEN_AREA
///Areas that virtual entities should not be in
/area/virtual_domain/protected_space
name = "Virtual Domain Safe Zone"
- area_flags = UNIQUE_AREA | NOTELEPORT | EVENT_PROTECTED | VIRTUAL_SAFE_AREA | UNLIMITED_FISHING
+ area_flags = /area/virtual_domain/safehouse::area_flags
+ area_flags_mapping = /area/virtual_domain/safehouse::area_flags_mapping
icon_state = "bit_safe"
/area/virtual_domain/protected_space/fullbright
static_lighting = FALSE
base_lighting_alpha = 255
+
+/// A hash lookup list of all the virtual area types
+GLOBAL_LIST_INIT_TYPED(virtual_areas, /area, populate_virtual_areas())
+
+/// Constructs the list of virtual areas
+/proc/populate_virtual_areas()
+ RETURN_TYPE(/list/area)
+ var/list/area/virtual_areas = list()
+ for(var/area/area_type as anything in subtypesof(/area))
+ if (area_type::area_flags_mapping & VIRTUAL_AREA)
+ virtual_areas[area_type] = TRUE
+ return virtual_areas
diff --git a/code/modules/bitrunning/components/avatar_connection.dm b/code/modules/bitrunning/components/avatar_connection.dm
index 1891a4689974..54e07bda7dd8 100644
--- a/code/modules/bitrunning/components/avatar_connection.dm
+++ b/code/modules/bitrunning/components/avatar_connection.dm
@@ -20,6 +20,7 @@
obj/machinery/quantum_server/server,
obj/machinery/netpod/pod,
help_text,
+ copy_body,
)
if(!isliving(parent) || !isliving(old_body) || !server.is_operational || !pod.is_operational)
@@ -67,6 +68,15 @@
if(alias && avatar.real_name != alias)
avatar.fully_replace_character_name(newname = alias)
+ avatar.voice = old_body.voice
+ avatar.voice_filter = old_body.voice_filter
+ if(ishuman(avatar) && ishuman(old_body) && copy_body)
+ var/mob/living/carbon/human/human_avatar = avatar
+ var/mob/living/carbon/human/human_old_body = old_body
+ human_avatar.dna.unique_identity = human_old_body.dna.unique_identity
+ human_avatar.physique = human_old_body.physique
+ human_avatar.updateappearance(mutcolor_update = TRUE)
+
update_avatar_id()
avatar.mind.set_assigned_role(SSjob.get_job_type(/datum/job/bit_avatar))
@@ -100,7 +110,7 @@
*/
RegisterSignals(parent, list(COMSIG_BITRUNNER_ALERT_SEVER, COMSIG_BITRUNNER_CACHE_SEVER, COMSIG_BITRUNNER_LADDER_SEVER), PROC_REF(on_safe_disconnect))
RegisterSignal(parent, COMSIG_LIVING_PILL_CONSUMED, PROC_REF(disconnect_if_red_pill))
- RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_sever_connection))
+ RegisterSignals(parent, list(COMSIG_LIVING_DEATH, COMSIG_QDELETING), PROC_REF(on_sever_connection))
RegisterSignal(parent, COMSIG_MOB_APPLY_DAMAGE, PROC_REF(on_linked_damage))
@@ -174,7 +184,11 @@
if(damage > 30 && prob(30))
INVOKE_ASYNC(old_body, TYPE_PROC_REF(/mob/living, emote), "scream")
- old_body.apply_damage(damage, damage_type, def_zone, blocked, wound_bonus = CANT_WOUND)
+ var/zone = def_zone
+ if(isbodypart(def_zone)) // If the defined zone is a bodypart, then it is the bodypart of the domain avatar. We don't want that bodypart, we want the real body's bodypart, so we go back to zone.
+ zone = astype(def_zone, /obj/item/bodypart).body_zone
+
+ old_body.apply_damage(damage, damage_type, zone, blocked, wound_bonus = CANT_WOUND)
if(old_body.stat > SOFT_CRIT) // KO!
full_avatar_disconnect(cause_damage = TRUE)
diff --git a/code/modules/bitrunning/components/bitrunning_points.dm b/code/modules/bitrunning/components/bitrunning_points.dm
deleted file mode 100644
index 328a70679e65..000000000000
--- a/code/modules/bitrunning/components/bitrunning_points.dm
+++ /dev/null
@@ -1,37 +0,0 @@
-/// Attaches to a turf so it spawns a crate when a certain amount of points are added to it.
-/datum/component/bitrunning_points
- /// The amount required to spawn a crate
- var/points_goal = 10
- /// A special condition limits this from spawning a crate
- var/points_received = 0
-
-/datum/component/bitrunning_points/Initialize(datum/lazy_template/virtual_domain/domain)
- . = ..()
- if(!isturf(parent))
- return COMPONENT_INCOMPATIBLE
-
- RegisterSignal(domain, COMSIG_BITRUNNER_GOAL_POINT, PROC_REF(on_add_points))
-
-/// Listens for points to be added which will eventually spawn a crate.
-/datum/component/bitrunning_points/proc/on_add_points(datum/source, points_to_add)
- SIGNAL_HANDLER
-
- points_received += points_to_add
-
- if(points_received < points_goal)
- return
-
- reveal()
-
-/// Spawns the crate with some effects
-/datum/component/bitrunning_points/proc/reveal()
- playsound(src, 'sound/magic/blink.ogg', 50, TRUE)
-
- var/turf/tile = parent
- new /obj/structure/closet/crate/secure/bitrunning/encrypted(tile)
-
- var/datum/effect_system/spark_spread/quantum/sparks = new(tile)
- sparks.set_up(number = 5, location = tile)
- sparks.start()
-
- qdel(src)
diff --git a/code/modules/bitrunning/components/glitch.dm b/code/modules/bitrunning/components/glitch.dm
index f2e13c80b0d7..df42fb4eaf66 100644
--- a/code/modules/bitrunning/components/glitch.dm
+++ b/code/modules/bitrunning/components/glitch.dm
@@ -1,35 +1,36 @@
/datum/component/glitch
/// Ref of the spawning forge
var/datum/weakref/forge_ref
+ var/datum/weakref/distort_component
/datum/component/glitch/Initialize(obj/machinery/quantum_server/server, obj/machinery/byteforge/forge)
if(!isliving(parent))
return COMPONENT_INCOMPATIBLE
- RegisterSignal(forge, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(on_forge_power_restored))
- RegisterSignals(forge, list(COMSIG_MACHINERY_BROKEN, COMSIG_MACHINERY_POWER_LOST), PROC_REF(on_forge_broken))
- forge_ref = WEAKREF(forge)
-
var/mob/living/owner = parent
- server.remove_threat(owner) // so the server doesn't dust us
+ var/health_boost = 0
+
+ if (forge)
+ RegisterSignal(forge, COMSIG_MACHINERY_POWER_RESTORED, PROC_REF(on_forge_power_restored))
+ RegisterSignals(forge, list(COMSIG_MACHINERY_BROKEN, COMSIG_MACHINERY_POWER_LOST), PROC_REF(on_forge_broken))
+ forge_ref = WEAKREF(forge)
+ server.remove_threat(owner) // so the server doesn't dust us
+ health_boost = ROUND_UP(server.threat * 0.2)
owner.faction.Cut()
owner.faction += list(ROLE_GLITCH)
- var/current_max = owner.maxHealth + ROUND_UP(server.threat * 0.2)
- owner.maxHealth = clamp(current_max, 200, 500)
+ owner.maxHealth = clamp(owner.maxHealth + health_boost, 200, 500)
owner.fully_heal()
+ owner.create_digital_aura()
- var/atom/thing = owner
- thing.create_digital_aura()
-
-/// Sakujo
-/datum/component/glitch/proc/dust_mob()
- if(QDELETED(parent))
- return
+/datum/component/glitch/RegisterWithParent()
+ RegisterSignal(parent, COMSIG_LIVING_DEATH, PROC_REF(on_death))
+ distort_component = WEAKREF(parent.AddComponent(/datum/component/holographic_nature))
- var/mob/living/owner = parent
- owner.dust()
+/datum/component/glitch/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_LIVING_DEATH)
+ QDEL_NULL(distort_component)
/// We don't want digital entities just lingering around as corpses.
/datum/component/glitch/proc/on_death()
@@ -41,10 +42,10 @@
var/mob/living/owner = parent
to_chat(owner, span_userdanger("You feel a strange sensation..."))
- var/obj/machinery/byteforge/forge = forge_ref.resolve()
+ var/obj/machinery/byteforge/forge = forge_ref?.resolve()
forge?.setup_particles()
- addtimer(CALLBACK(src, PROC_REF(dust_mob)), 2 SECONDS, TIMER_UNIQUE|TIMER_DELETE_ME|TIMER_STOPPABLE)
+ owner.fade_into_nothing(3 SECONDS, 2 SECONDS)
/// If the forge breaks, we take a massive slowdown
/datum/component/glitch/proc/on_forge_broken(datum/source)
diff --git a/code/modules/bitrunning/components/virtual_entity.dm b/code/modules/bitrunning/components/virtual_entity.dm
index db81f376a809..83e8141db43e 100644
--- a/code/modules/bitrunning/components/virtual_entity.dm
+++ b/code/modules/bitrunning/components/virtual_entity.dm
@@ -22,7 +22,7 @@
stack_trace("Virtual entity entered a location with no area!")
return
- if(location_area.area_flags & VIRTUAL_SAFE_AREA)
+ if(location_area.area_flags_mapping & VIRTUAL_SAFE_AREA)
source.balloon_alert(source, "out of bounds!")
COOLDOWN_START(src, OOB_cooldown, 2 SECONDS)
return COMPONENT_MOVABLE_BLOCK_PRE_MOVE
diff --git a/code/modules/bitrunning/designs.dm b/code/modules/bitrunning/designs.dm
deleted file mode 100644
index 96ae65d41e99..000000000000
--- a/code/modules/bitrunning/designs.dm
+++ /dev/null
@@ -1,74 +0,0 @@
-// Quantum server
-
-/obj/item/circuitboard/machine/quantum_server
- name = "Quantum Server"
- greyscale_colors = CIRCUIT_COLOR_SUPPLY
- build_path = /obj/machinery/quantum_server
- req_components = list(
- /datum/stock_part/servo = 2,
- /datum/stock_part/scanning_module = 1,
- /datum/stock_part/capacitor = 1,
- )
-
-/**
- * quantum server design
- * are you absolutely sure??
- */
-
-// Netpod
-
-/obj/item/circuitboard/machine/netpod
- name = "Netpod"
- greyscale_colors = CIRCUIT_COLOR_SUPPLY
- build_path = /obj/machinery/netpod
- req_components = list(
- /datum/stock_part/servo = 1,
- /datum/stock_part/matter_bin = 2,
- )
-
-/datum/design/board/netpod
- name = "Netpod Board"
- desc = "The circuit board for a netpod."
- id = "netpod"
- build_path = /obj/item/circuitboard/machine/netpod
- category = list(
- RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO
- )
- departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
-
-// Quantum console
-
-/obj/item/circuitboard/computer/quantum_console
- name = "Quantum Console"
- greyscale_colors = CIRCUIT_COLOR_SUPPLY
- build_path = /obj/machinery/computer/quantum_console
-
-/datum/design/board/quantum_console
- name = "Quantum Console Board"
- desc = "Allows for the construction of circuit boards used to build a Quantum Console."
- id = "quantum_console"
- build_path = /obj/item/circuitboard/computer/quantum_console
- category = list(
- RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_CARGO
- )
- departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
-
-// Byteforge
-
-/obj/item/circuitboard/machine/byteforge
- name = "Byteforge"
- greyscale_colors = CIRCUIT_COLOR_SUPPLY
- build_path = /obj/machinery/byteforge
- req_components = list(
- /datum/stock_part/micro_laser = 1,
- )
-
-/datum/design/board/byteforge
- name = "Byteforge Board"
- desc = "Allows for the construction of circuit boards used to build a Byteforge."
- id = "byteforge"
- build_path = /obj/item/circuitboard/machine/byteforge
- category = list(
- RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_CARGO
- )
- departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
diff --git a/code/modules/bitrunning/event.dm b/code/modules/bitrunning/event.dm
index c50ef016a515..f3c3d0e0cc20 100644
--- a/code/modules/bitrunning/event.dm
+++ b/code/modules/bitrunning/event.dm
@@ -29,7 +29,7 @@
/datum/round_event_control/bitrunning_glitch/proc/validate_servers()
active_servers.Cut()
for(var/obj/machinery/quantum_server/server in SSmachines.get_machines_by_type(/obj/machinery/quantum_server))
- if(server.validate_mutation_candidates())
+ if(server.validate_mutation_candidates() && server.generated_domain.difficulty != BITRUNNER_DIFFICULTY_NONE)
active_servers.Add(WEAKREF(server))
return length(active_servers) > 0
diff --git a/code/modules/bitrunning/job.dm b/code/modules/bitrunning/job.dm
index a45578affa44..e59c4c82c53d 100644
--- a/code/modules/bitrunning/job.dm
+++ b/code/modules/bitrunning/job.dm
@@ -13,7 +13,7 @@
paycheck = PAYCHECK_CREW
paycheck_department = ACCOUNT_CAR
display_order = JOB_DISPLAY_ORDER_BITRUNNER
- bounty_types = CIV_JOB_RANDOM
+ bounty_types = CIV_JOB_BITRUN
departments_list = list(
/datum/job_department/cargo,
)
diff --git a/code/modules/bitrunning/netpod/_netpod.dm b/code/modules/bitrunning/netpod/_netpod.dm
new file mode 100644
index 000000000000..80c3bfc5b211
--- /dev/null
+++ b/code/modules/bitrunning/netpod/_netpod.dm
@@ -0,0 +1,169 @@
+#define BASE_DISCONNECT_DAMAGE 40
+#define SCANNING_TOGGLE_COOLDOWN 5
+
+/obj/machinery/netpod
+ name = "netpod"
+
+ base_icon_state = "netpod"
+ circuit = /obj/item/circuitboard/machine/netpod
+ desc = "A link to the netverse. It has an assortment of cables to connect yourself to a virtual domain."
+ icon = 'icons/obj/machines/bitrunning.dmi'
+ icon_state = "netpod"
+ max_integrity = 300
+ obj_flags = BLOCKS_CONSTRUCTION
+ state_open = TRUE
+ interaction_flags_mouse_drop = NEED_HANDS | NEED_DEXTERITY
+
+ /// Whether we have an ongoing connection
+ var/connected = FALSE
+ /// A player selected outfit by clicking the netpod
+ var/datum/outfit/netsuit = /datum/outfit/job/bitrunner
+ /// Holds this to see if it needs to generate a new one
+ var/datum/weakref/avatar_ref
+ /// The linked quantum server
+ var/datum/weakref/server_ref
+ /// The amount of brain damage done from force disconnects
+ var/disconnect_damage
+ /// Static list of outfits to select from
+ var/list/cached_outfits = list()
+ /// Whether bit avatars become visually similar to their bitrunner on first creation
+ var/copy_body = FALSE
+ /// The next time copy_body can be toggled
+ var/scanning_can_toggle = 0
+
+
+/obj/machinery/netpod/post_machine_initialize()
+ . = ..()
+
+ disconnect_damage = BASE_DISCONNECT_DAMAGE
+ find_server()
+
+ RegisterSignal(src, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(on_damage_taken))
+ RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_loss))
+ RegisterSignals(src, list(COMSIG_QDELETING, COMSIG_MACHINERY_BROKEN),PROC_REF(on_broken))
+
+ register_context()
+ update_appearance()
+
+
+/obj/machinery/netpod/Destroy()
+ . = ..()
+
+ QDEL_LIST(cached_outfits)
+
+
+/obj/machinery/netpod/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = ..()
+
+ if(isnull(held_item))
+ context[SCREENTIP_CONTEXT_LMB] = "Select Outfit"
+ else
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER && !occupant && !state_open)
+ context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel"
+
+ if(held_item.tool_behaviour == TOOL_CROWBAR)
+ if(isnull(occupant))
+ if(panel_open)
+ context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
+ else
+ context[SCREENTIP_CONTEXT_LMB] = "[state_open ? "Close" : "Open"] Cover"
+ else
+ context[SCREENTIP_CONTEXT_LMB] = "Break out"
+
+ context[SCREENTIP_CONTEXT_ALT_LMB] = "[copy_body ? "Disable" : "Enable"] Scan"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/machinery/netpod/examine(mob/user)
+ . = ..()
+
+ . += span_notice("Its maintainance panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"].")
+ if(isnull(occupant))
+ if(panel_open)
+ . += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
+ else
+ . += span_notice("Its hatch can be [EXAMINE_HINT("pried")] [state_open ? "closed" : "open"]")
+
+ if(isnull(server_ref?.resolve()))
+ . += span_infoplain("It's not connected to anything.")
+ . += span_infoplain("Netpods must be built within 4 tiles of a server.")
+ return
+
+ if(!isobserver(user))
+ . += span_infoplain("Drag yourself into the pod to engage the link.")
+ . += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.")
+ . += span_infoplain("It has a security system that will alert the occupant if it is tampered with.")
+ if(copy_body)
+ . += span_infoplain("Occupant scanning is currently enabled, which will cause bit avatars to look like the occupant when first created.")
+ . += span_infoplain("Alt-click to [copy_body ? "disable" : "enable"] occupant scanning.")
+
+ if(isnull(occupant))
+ . += span_infoplain("It's currently unoccupied.")
+ return
+
+ . += span_infoplain("It's currently occupied by [occupant].")
+
+ if(isobserver(user))
+ . += span_notice("As an observer, you can click this netpod to jump to its avatar.")
+ return
+
+ . += span_notice("It can be pried open with a crowbar, but its safety mechanisms will alert the occupant.")
+
+
+/obj/machinery/netpod/update_icon_state()
+ if(!is_operational)
+ icon_state = base_icon_state
+ return ..()
+
+ if(state_open)
+ icon_state = base_icon_state + "_open_active"
+ return ..()
+
+ if(panel_open)
+ icon_state = base_icon_state + "_panel"
+ return ..()
+
+ icon_state = base_icon_state + "_closed"
+ if(occupant)
+ icon_state += "_active"
+
+ return ..()
+
+
+/obj/machinery/netpod/mouse_drop_receive(mob/target, mob/user, params)
+ var/mob/living/carbon/player = user
+
+ if(!iscarbon(player) || !is_operational || !state_open || player.buckled)
+ return
+
+ close_machine(target)
+
+
+/obj/machinery/netpod/attack_hand(mob/living/user, list/modifiers)
+ . = ..()
+ if(!state_open && user == occupant)
+ container_resist_act(user)
+
+
+/obj/machinery/netpod/attack_ghost(mob/dead/observer/our_observer)
+ var/our_target = avatar_ref?.resolve()
+ if(isnull(our_target) || !our_observer.orbit(our_target))
+ return ..()
+
+
+/// When the server is upgraded, drops brain damage a little
+/obj/machinery/netpod/proc/on_server_upgraded(obj/machinery/quantum_server/source)
+ SIGNAL_HANDLER
+
+ disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - source.servo_bonus)
+
+/obj/machinery/netpod/click_alt(mob/user)
+ if(world.time < scanning_can_toggle)
+ return CLICK_ACTION_BLOCKING
+ copy_body = !copy_body
+ scanning_can_toggle = world.time + SCANNING_TOGGLE_COOLDOWN
+ playsound(src, 'sound/machines/click.ogg', 50, TRUE)
+ user.balloon_alert_to_viewers(user, "scanning [copy_body ? "enabled" : "disabled"]")
+ return CLICK_ACTION_SUCCESS
+
+#undef BASE_DISCONNECT_DAMAGE
+#undef SCANNING_TOGGLE_COOLDOWN
diff --git a/code/modules/bitrunning/netpod/container.dm b/code/modules/bitrunning/netpod/container.dm
new file mode 100644
index 000000000000..616554454451
--- /dev/null
+++ b/code/modules/bitrunning/netpod/container.dm
@@ -0,0 +1,74 @@
+/obj/machinery/netpod/Exited(atom/movable/gone, direction)
+ . = ..()
+ if(!state_open && gone == occupant)
+ container_resist_act(gone)
+
+
+/obj/machinery/netpod/relaymove(mob/living/user, direction)
+ if(!state_open)
+ container_resist_act(user)
+
+
+/obj/machinery/netpod/container_resist_act(mob/living/user)
+ user.visible_message(span_notice("[occupant] emerges from [src]!"),
+ span_notice("You climb out of [src]!"),
+ span_notice("With a hiss, you hear a machine opening."))
+ open_machine()
+
+
+/obj/machinery/netpod/open_machine(drop = TRUE, density_to_set = FALSE)
+ playsound(src, 'sound/machines/tramopen.ogg', 60, TRUE, frequency = 65000)
+ flick("[base_icon_state]_opening", src)
+ SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_OPENED)
+ update_use_power(IDLE_POWER_USE)
+
+ return ..()
+
+
+/obj/machinery/netpod/close_machine(mob/user, density_to_set = TRUE)
+ if(!state_open || panel_open || !is_operational || !iscarbon(user))
+ return
+
+ playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
+ flick("[base_icon_state]_closing", src)
+ ..()
+
+ enter_matrix()
+
+
+/obj/machinery/netpod/default_pry_open(obj/item/crowbar, mob/living/pryer)
+ if(isnull(occupant) || !iscarbon(occupant))
+ if(!state_open)
+ if(panel_open)
+ return FALSE
+ open_machine()
+ else
+ shut_pod()
+
+ return TRUE
+
+ pryer.visible_message(
+ span_danger("[pryer] starts prying open [src]!"),
+ span_notice("You start to pry open [src]."),
+ span_notice("You hear loud prying on metal.")
+ )
+ playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
+
+ SEND_SIGNAL(src, COMSIG_BITRUNNER_CROWBAR_ALERT, pryer)
+
+ if(do_after(pryer, 15 SECONDS, src))
+ if(!state_open)
+ sever_connection()
+ open_machine()
+
+ return TRUE
+
+
+/// Closes the machine without shoving in an occupant
+/obj/machinery/netpod/proc/shut_pod()
+ state_open = FALSE
+ playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
+ flick("[base_icon_state]_closing", src)
+ set_density(TRUE)
+
+ update_appearance()
diff --git a/code/modules/bitrunning/netpod/outfitting.dm b/code/modules/bitrunning/netpod/outfitting.dm
new file mode 100644
index 000000000000..07f251541980
--- /dev/null
+++ b/code/modules/bitrunning/netpod/outfitting.dm
@@ -0,0 +1,30 @@
+/// Creates a list of outfit entries for the UI.
+/obj/machinery/netpod/proc/make_outfit_collection(identifier, list/outfit_list)
+ var/list/collection = list(
+ "name" = identifier,
+ "outfits" = list()
+ )
+
+ for(var/datum/outfit/outfit as anything in outfit_list)
+ var/outfit_name = initial(outfit.name)
+ if(findtext(outfit_name, "(") != 0 || findtext(outfit_name, "-") != 0) // No special variants please
+ continue
+
+ collection["outfits"] += list(list("path" = outfit, "name" = outfit_name))
+
+ return list(collection)
+
+
+/// Resolves a path to an outfit.
+/obj/machinery/netpod/proc/resolve_outfit(text)
+ var/path = text2path(text)
+ if(!ispath(path, /datum/outfit))
+ return
+
+ for(var/wardrobe in cached_outfits)
+ for(var/outfit in wardrobe["outfits"])
+ if(path == outfit["path"])
+ return path
+
+ message_admins("[usr]:[usr.ckey] attempted to select an unavailable outfit from a netpod")
+ return
diff --git a/code/modules/bitrunning/netpod/signals.dm b/code/modules/bitrunning/netpod/signals.dm
new file mode 100644
index 000000000000..8f8416aeb7b1
--- /dev/null
+++ b/code/modules/bitrunning/netpod/signals.dm
@@ -0,0 +1,64 @@
+/// Machine has been broken - handles signals and reverting sprites
+/obj/machinery/netpod/proc/on_broken(datum/source)
+ SIGNAL_HANDLER
+
+ sever_connection()
+
+
+/// Checks the integrity, alerts occupants
+/obj/machinery/netpod/proc/on_damage_taken(datum/source, damage_amount)
+ SIGNAL_HANDLER
+
+ if(isnull(occupant) || !connected)
+ return
+
+ var/total = max_integrity - damage_amount
+ var/integrity = (atom_integrity / total) * 100
+ if(integrity > 50)
+ return
+
+ SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_INTEGRITY)
+
+
+/// Puts points on the current occupant's card account
+/obj/machinery/netpod/proc/on_domain_complete(datum/source, atom/movable/crate, reward_points)
+ SIGNAL_HANDLER
+
+ if(isnull(occupant) || !connected)
+ return
+
+ var/mob/living/player = occupant
+
+ var/datum/bank_account/account = player.get_bank_account()
+ if(isnull(account))
+ return
+
+ account.bitrunning_points += reward_points * 100
+
+
+/// The domain has been fully purged, so we should double check our avatar is deleted
+/obj/machinery/netpod/proc/on_domain_scrubbed(datum/source)
+ SIGNAL_HANDLER
+
+ var/mob/avatar = avatar_ref?.resolve()
+ if(isnull(avatar))
+ return
+
+ QDEL_NULL(avatar)
+
+
+/// Boots out anyone in the machine && opens it
+/obj/machinery/netpod/proc/on_power_loss(datum/source)
+ SIGNAL_HANDLER
+
+ if(state_open)
+ return
+
+ if(isnull(occupant) || !connected)
+ connected = FALSE
+ open_machine()
+ return
+
+ sever_connection()
+
+
diff --git a/code/modules/bitrunning/netpod/tools.dm b/code/modules/bitrunning/netpod/tools.dm
new file mode 100644
index 000000000000..0d31bdab8665
--- /dev/null
+++ b/code/modules/bitrunning/netpod/tools.dm
@@ -0,0 +1,22 @@
+/obj/machinery/netpod/crowbar_act(mob/living/user, obj/item/tool)
+ if(user.combat_mode)
+ attack_hand(user)
+ return ITEM_INTERACT_SUCCESS
+
+ if(default_pry_open(tool, user) || default_deconstruction_crowbar(tool))
+ return ITEM_INTERACT_SUCCESS
+
+
+/obj/machinery/netpod/screwdriver_act(mob/living/user, obj/item/tool)
+ if(occupant)
+ balloon_alert(user, "in use!")
+ return ITEM_INTERACT_SUCCESS
+
+ if(state_open)
+ balloon_alert(user, "close first.")
+ return ITEM_INTERACT_SUCCESS
+
+ if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", "[base_icon_state]_closed", tool))
+ update_appearance() // sometimes icon doesnt properly update during flick()
+ ui_close(user)
+ return ITEM_INTERACT_SUCCESS
diff --git a/code/modules/bitrunning/netpod/ui.dm b/code/modules/bitrunning/netpod/ui.dm
new file mode 100644
index 000000000000..93719fe64ebe
--- /dev/null
+++ b/code/modules/bitrunning/netpod/ui.dm
@@ -0,0 +1,41 @@
+/obj/machinery/netpod/ui_interact(mob/user, datum/tgui/ui)
+ if(!is_operational || occupant)
+ return
+
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "NetpodOutfits")
+ ui.set_autoupdate(FALSE)
+ ui.open()
+
+
+/obj/machinery/netpod/ui_data()
+ var/list/data = list()
+
+ data["netsuit"] = netsuit
+ return data
+
+
+/obj/machinery/netpod/ui_static_data()
+ var/list/data = list()
+
+ if(!length(cached_outfits))
+ cached_outfits += make_outfit_collection("Jobs", subtypesof(/datum/outfit/job))
+
+ data["collections"] = cached_outfits
+
+ return data
+
+
+/obj/machinery/netpod/ui_act(action, params)
+ . = ..()
+ if(.)
+ return TRUE
+ switch(action)
+ if("select_outfit")
+ var/datum/outfit/new_suit = resolve_outfit(params["outfit"])
+ if(new_suit)
+ netsuit = new_suit
+ return TRUE
+
+ return FALSE
diff --git a/code/modules/bitrunning/netpod/utils.dm b/code/modules/bitrunning/netpod/utils.dm
new file mode 100644
index 000000000000..39e476218ac9
--- /dev/null
+++ b/code/modules/bitrunning/netpod/utils.dm
@@ -0,0 +1,156 @@
+/// Puts the occupant in netpod stasis, basically short-circuiting environmental conditions
+/obj/machinery/netpod/proc/add_healing(mob/living/target)
+ if(target != occupant)
+ return
+
+ target.AddComponent(/datum/component/netpod_healing, pod = src)
+ target.playsound_local(src, 'sound/effects/submerge.ogg', 20, vary = TRUE)
+ target.extinguish_mob()
+ update_use_power(ACTIVE_POWER_USE)
+
+
+/// Disconnects the occupant after a certain time so they aren't just hibernating in netpod stasis. A balance change
+/obj/machinery/netpod/proc/auto_disconnect()
+ if(isnull(occupant) || state_open || connected)
+ return
+
+ var/mob/player = occupant
+ player.playsound_local(src, 'sound/effects/splash.ogg', 60, TRUE)
+ to_chat(player, span_notice("The machine disconnects itself and begins to drain."))
+ open_machine()
+
+
+/// Handles occupant post-disconnection effects like damage, sounds, etc
+/obj/machinery/netpod/proc/disconnect_occupant(cause_damage = FALSE)
+ connected = FALSE
+
+ var/mob/living/mob_occupant = occupant
+ if(isnull(occupant) || mob_occupant.stat == DEAD)
+ open_machine()
+ return
+
+ mob_occupant.playsound_local(src, 'sound/magic/blink.ogg', 25, TRUE)
+ mob_occupant.set_static_vision(2 SECONDS)
+ mob_occupant.set_temp_blindness(1 SECONDS)
+ mob_occupant.Paralyze(2 SECONDS)
+
+ if(!is_operational)
+ open_machine()
+ return
+
+ var/heal_time = 1
+ if(mob_occupant.health < mob_occupant.maxHealth)
+ heal_time = (mob_occupant.stat + 2) * 5
+ addtimer(CALLBACK(src, PROC_REF(auto_disconnect)), heal_time SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME)
+
+ if(!cause_damage)
+ return
+
+ mob_occupant.flash_act(override_blindness_check = TRUE, visual = TRUE)
+ mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, disconnect_damage)
+ INVOKE_ASYNC(mob_occupant, TYPE_PROC_REF(/mob/living, emote), "scream")
+ to_chat(mob_occupant, span_danger("You've been forcefully disconnected from your avatar! Your thoughts feel scrambled!"))
+
+
+/**
+ * ### Enter Matrix
+ * Finds any current avatars from this chair - or generates a new one
+ *
+ * New avatars cost 1 attempt, and this will eject if there's none left
+ *
+ * Connects the mind to the avatar if everything is ok
+ */
+/obj/machinery/netpod/proc/enter_matrix()
+ var/mob/living/carbon/human/neo = occupant
+ if(!ishuman(neo) || neo.stat == DEAD || isnull(neo.mind))
+ balloon_alert(neo, "invalid occupant.")
+ return
+
+ var/obj/machinery/quantum_server/server = find_server()
+ if(isnull(server))
+ balloon_alert(neo, "no server connected!")
+ return
+
+ var/datum/lazy_template/virtual_domain/generated_domain = server.generated_domain
+ if(isnull(generated_domain) || !server.is_ready)
+ balloon_alert(neo, "nothing loaded!")
+ return
+
+ balloon_alert(neo, "establishing connection...")
+
+ // Prevent hand interactions during loading to stop smuggling exploits into virtual domain
+ ADD_TRAIT(neo, TRAIT_HANDS_BLOCKED, TRAIT_GENERIC)
+
+ var/connection_successful = do_after(neo, 2 SECONDS, src)
+
+ // Re-enable hand interactions after loading attempt
+ REMOVE_TRAIT(neo, TRAIT_HANDS_BLOCKED, TRAIT_GENERIC)
+
+ if(!connection_successful)
+ open_machine()
+ return
+
+ var/mob/living/carbon/current_avatar = avatar_ref?.resolve()
+ if(isnull(current_avatar) || current_avatar.stat != CONSCIOUS) // We need a viable avatar
+ current_avatar = server.start_new_connection(neo, netsuit)
+ if(isnull(current_avatar))
+ balloon_alert(neo, "out of bandwidth!")
+ return
+
+ neo.set_static_vision(2 SECONDS)
+ add_healing(occupant)
+
+ if(!validate_entry(neo, current_avatar))
+ open_machine()
+ return
+
+ current_avatar.AddComponent( \
+ /datum/component/avatar_connection, \
+ old_mind = neo.mind, \
+ old_body = neo, \
+ server = server, \
+ pod = src, \
+ help_text = generated_domain.help_text, \
+ copy_body = copy_body, \
+ )
+
+ connected = TRUE
+
+
+/// Finds a server and sets the server_ref
+/obj/machinery/netpod/proc/find_server()
+ var/obj/machinery/quantum_server/server = server_ref?.resolve()
+ if(server)
+ return server
+
+ server = locate(/obj/machinery/quantum_server) in oview(4, src)
+ if(isnull(server))
+ return
+
+ server_ref = WEAKREF(server)
+ RegisterSignal(server, COMSIG_MACHINERY_REFRESH_PARTS, PROC_REF(on_server_upgraded))
+ RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_COMPLETE, PROC_REF(on_domain_complete))
+ RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_SCRUBBED, PROC_REF(on_domain_scrubbed))
+
+ return server
+
+
+/// Severs the connection with the current avatar
+/obj/machinery/netpod/proc/sever_connection()
+ if(isnull(occupant) || !connected)
+ return
+
+ SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_SEVER)
+
+
+/// Checks for cases to eject/fail connecting an avatar
+/obj/machinery/netpod/proc/validate_entry(mob/living/neo, mob/living/avatar)
+ // Very invalid
+ if(QDELETED(neo) || QDELETED(avatar) || QDELETED(src) || !is_operational)
+ return FALSE
+
+ // Invalid
+ if(occupant != neo || isnull(neo.mind) || neo.stat > SOFT_CRIT || avatar.stat == DEAD)
+ return FALSE
+
+ return TRUE
diff --git a/code/modules/bitrunning/objects/byteforge.dm b/code/modules/bitrunning/objects/byteforge.dm
index b971cdae75dd..d9a1c3b85ac2 100644
--- a/code/modules/bitrunning/objects/byteforge.dm
+++ b/code/modules/bitrunning/objects/byteforge.dm
@@ -5,6 +5,7 @@
desc = "A machine used by the quantum server. Quantum code converges here, materializing decrypted assets from the virtual abyss."
icon = 'icons/obj/machines/bitrunning.dmi'
icon_state = "byteforge"
+ base_icon_state = "byteforge"
obj_flags = BLOCKS_CONSTRUCTION | CAN_BE_HIT
/// Idle particles
var/mutable_appearance/byteforge_particles
@@ -12,18 +13,49 @@
/obj/machinery/byteforge/Initialize(mapload)
. = ..()
- return INITIALIZE_HINT_LATELOAD
+ register_context()
/obj/machinery/byteforge/post_machine_initialize()
. = ..()
setup_particles()
+/obj/machinery/byteforge/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = NONE
+ if(isnull(held_item))
+ return
+
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel"
+ return CONTEXTUAL_SCREENTIP_SET
+ else if(held_item.tool_behaviour == TOOL_CROWBAR && panel_open)
+ context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
+ return CONTEXTUAL_SCREENTIP_SET
+
+/obj/machinery/byteforge/examine(mob/user)
+ . = ..()
+
+ . += span_notice("Make sure this is 4 tiles from the quantum server")
+
+ . += span_notice("Its maintainance panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"].")
+ if(panel_open)
+ . += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
+
/obj/machinery/byteforge/update_appearance(updates)
. = ..()
setup_particles()
+/obj/machinery/byteforge/screwdriver_act(mob/living/user, obj/item/screwdriver)
+ . = ITEM_INTERACT_FAILURE
+ if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", base_icon_state, screwdriver))
+ return ITEM_INTERACT_SUCCESS
+
+/obj/machinery/byteforge/crowbar_act(mob/living/user, obj/item/crowbar)
+ . = ITEM_INTERACT_FAILURE
+ if(default_deconstruction_crowbar(crowbar))
+ return ITEM_INTERACT_SUCCESS
+
/// Does some sparks after it's done
/obj/machinery/byteforge/proc/flash(atom/movable/thing)
playsound(src, 'sound/magic/blink.ogg', 50, TRUE)
diff --git a/code/modules/bitrunning/objects/disks.dm b/code/modules/bitrunning/objects/disks.dm
index f91aeaab0438..db470325dd9a 100644
--- a/code/modules/bitrunning/objects/disks.dm
+++ b/code/modules/bitrunning/objects/disks.dm
@@ -111,6 +111,7 @@
)
+
/obj/item/bitrunning_disk/item
desc = "A disk containing source code. It can be used to preload items into the virtual domain."
/// The selected item that this grants
diff --git a/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm b/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm
index bb37a30abf5e..24702d1254ad 100644
--- a/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm
+++ b/code/modules/bitrunning/objects/gimmick_disks/_gimmick_disk.dm
@@ -99,17 +99,3 @@
our_action.Grant(avatar)
return return_flags
-
-
-/**
- * Base container used for gimmick disks.
- */
-/obj/item/storage/briefcase/secure/digital_storage
- name = "digi-case"
- desc = "It's made of AUTHENTIC digital leather and has a price-tag still attached. Its owner must be a real professional."
- icon_state = "secure"
- base_icon_state = "secure"
- inhand_icon_state = "sec-case"
-
-/obj/item/storage/briefcase/secure/digital_storage/PopulateContents()
- return
diff --git a/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm b/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm
index 66ceca2246f6..559c7f022dfa 100644
--- a/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm
+++ b/code/modules/bitrunning/objects/gimmick_disks/dungeon_disk.dm
@@ -148,22 +148,22 @@
granted_items = list(
/obj/item/clothing/under/color/black,
- /obj/item/clothing/shoes/sneakers/black/rogue,
+ /obj/item/clothing/shoes/sneakers/black,
/obj/item/clothing/mask/facescarf/rogue,
- /obj/item/clothing/glasses/eyepatch/rogue,
+ /obj/item/clothing/glasses/eyepatch,
/obj/item/bedsheet/black/rogue_cape,
/obj/item/storage/belt/fannypack/black/rogue,
/obj/item/knife/combat/survival,
)
-/obj/item/clothing/shoes/sneakers/black/rogue
+/obj/item/clothing/shoes/sneakers/black
name = "sneaker of SNEAKING"
/obj/item/clothing/mask/facescarf/rogue
name = "cloth of DOOM"
greyscale_colors = "#292929"
-/obj/item/clothing/glasses/eyepatch/rogue
+/obj/item/clothing/glasses/eyepatch
name = "eyepatch of SEALING"
/obj/item/bedsheet/black/rogue_cape
diff --git a/code/modules/bitrunning/objects/hololadder.dm b/code/modules/bitrunning/objects/hololadder.dm
index 3df41a403e73..1335ef8b848b 100644
--- a/code/modules/bitrunning/objects/hololadder.dm
+++ b/code/modules/bitrunning/objects/hololadder.dm
@@ -64,6 +64,14 @@
if(isnull(user.mind))
return
+ var/obj/machinery/quantum_server/our_server = server_ref.resolve()
+ if(!our_server.domain_complete)
+ for(var/datum/weakref/ghostrole_weakref as anything in our_server.spawned_threat_refs)
+ var/mob/living/ghostrole = ghostrole_weakref.resolve()
+ if(ghostrole?.stat == CONSCIOUS && ghostrole.client && ghostrole.mind.has_antag_datum(/datum/antagonist/bitrunning_glitch))
+ to_chat(user, span_danger("A being in the simulation is preventing your retreat. You must either complete your mission or remove the obstacle before safe exit will be possible."))
+ return
+
if(!HAS_TRAIT(user, TRAIT_TEMPORARY_BODY))
balloon_alert(user, "no connection detected")
return
diff --git a/code/modules/bitrunning/objects/landmarks.dm b/code/modules/bitrunning/objects/landmarks.dm
index b123a793801e..170e7ab3075b 100644
--- a/code/modules/bitrunning/objects/landmarks.dm
+++ b/code/modules/bitrunning/objects/landmarks.dm
@@ -12,6 +12,11 @@
name = "Bitrunning hololadder spawn"
icon_state = "hololadder"
+/// A permanent exit for the domain
+/obj/effect/landmark/bitrunning/permanent_exit
+ name = "Bitrunning permanent exit"
+ icon_state = "perm_exit"
+
/// Where the crates need to be taken
/obj/effect/landmark/bitrunning/cache_goal_turf
name = "Bitrunning goal turf"
diff --git a/code/modules/bitrunning/objects/netpod.dm b/code/modules/bitrunning/objects/netpod.dm
deleted file mode 100644
index f6edeadefddb..000000000000
--- a/code/modules/bitrunning/objects/netpod.dm
+++ /dev/null
@@ -1,482 +0,0 @@
-#define BASE_DISCONNECT_DAMAGE 40
-
-/obj/machinery/netpod
- name = "netpod"
-
- base_icon_state = "netpod"
- circuit = /obj/item/circuitboard/machine/netpod
- desc = "A link to the netverse. It has an assortment of cables to connect yourself to a virtual domain."
- icon = 'icons/obj/machines/bitrunning.dmi'
- icon_state = "netpod"
- max_integrity = 300
- obj_flags = BLOCKS_CONSTRUCTION
- state_open = TRUE
- interaction_flags_mouse_drop = NEED_HANDS | NEED_DEXTERITY
-
- /// Whether we have an ongoing connection
- var/connected = FALSE
- /// A player selected outfit by clicking the netpod
- var/datum/outfit/netsuit = /datum/outfit/job/bitrunner
- /// Holds this to see if it needs to generate a new one
- var/datum/weakref/avatar_ref
- /// The linked quantum server
- var/datum/weakref/server_ref
- /// The amount of brain damage done from force disconnects
- var/disconnect_damage
- /// Static list of outfits to select from
- var/list/cached_outfits = list()
-
-/obj/machinery/netpod/post_machine_initialize()
- . = ..()
-
- disconnect_damage = BASE_DISCONNECT_DAMAGE
- find_server()
-
- RegisterSignal(src, COMSIG_ATOM_TAKE_DAMAGE, PROC_REF(on_damage_taken))
- RegisterSignal(src, COMSIG_MACHINERY_POWER_LOST, PROC_REF(on_power_loss))
- RegisterSignals(src, list(COMSIG_QDELETING, COMSIG_MACHINERY_BROKEN),PROC_REF(on_broken))
-
- register_context()
- update_appearance()
-
-/obj/machinery/netpod/Destroy()
- . = ..()
-
- QDEL_LIST(cached_outfits)
-
-/obj/machinery/netpod/examine(mob/user)
- . = ..()
-
- if(isnull(server_ref?.resolve()))
- . += span_infoplain("It's not connected to anything.")
- . += span_infoplain("Netpods must be built within 4 tiles of a server.")
- return
-
- if(!isobserver(user))
- . += span_infoplain("Drag yourself into the pod to engage the link.")
- . += span_infoplain("It has limited resuscitation capabilities. Remaining in the pod can heal some injuries.")
- . += span_infoplain("It has a security system that will alert the occupant if it is tampered with.")
-
- if(isnull(occupant))
- . += span_infoplain("It's currently unoccupied.")
- return
-
- . += span_infoplain("It's currently occupied by [occupant].")
-
- if(isobserver(user))
- . += span_notice("As an observer, you can click this netpod to jump to its avatar.")
- return
-
- . += span_notice("It can be pried open with a crowbar, but its safety mechanisms will alert the occupant.")
-
-
-
-/obj/machinery/netpod/add_context(atom/source, list/context, obj/item/held_item, mob/user)
- . = ..()
-
- if(isnull(held_item))
- context[SCREENTIP_CONTEXT_LMB] = "Select Outfit"
- return CONTEXTUAL_SCREENTIP_SET
-
- if(istype(held_item, /obj/item/crowbar) && occupant)
- context[SCREENTIP_CONTEXT_LMB] = "Pry Open"
- return CONTEXTUAL_SCREENTIP_SET
-
-
-/obj/machinery/netpod/update_icon_state()
- if(!is_operational)
- icon_state = base_icon_state
- return ..()
-
- if(state_open)
- icon_state = base_icon_state + "_open_active"
- return ..()
-
- if(panel_open)
- icon_state = base_icon_state + "_panel"
- return ..()
-
- icon_state = base_icon_state + "_closed"
- if(occupant)
- icon_state += "_active"
-
- return ..()
-
-/obj/machinery/netpod/mouse_drop_receive(mob/target, mob/user, params)
- var/mob/living/carbon/player = user
-
- if(!iscarbon(player) || !is_operational || !state_open || player.buckled)
- return
-
- close_machine(target)
-
-/obj/machinery/netpod/crowbar_act(mob/living/user, obj/item/tool)
- if(user.combat_mode)
- attack_hand(user)
- return ITEM_INTERACT_SUCCESS
-
- if(default_pry_open(tool, user) || default_deconstruction_crowbar(tool))
- return ITEM_INTERACT_SUCCESS
-
-/obj/machinery/netpod/screwdriver_act(mob/living/user, obj/item/tool)
- if(occupant)
- balloon_alert(user, "in use!")
- return ITEM_INTERACT_SUCCESS
-
- if(state_open)
- balloon_alert(user, "close first.")
- return ITEM_INTERACT_SUCCESS
-
- if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", "[base_icon_state]_closed", tool))
- update_appearance() // sometimes icon doesnt properly update during flick()
- ui_close(user)
- return ITEM_INTERACT_SUCCESS
-
-/obj/machinery/netpod/attack_hand(mob/living/user, list/modifiers)
- . = ..()
- if(!state_open && user == occupant)
- container_resist_act(user)
-
-/obj/machinery/netpod/Exited(atom/movable/gone, direction)
- . = ..()
- if(!state_open && gone == occupant)
- container_resist_act(gone)
-
-/obj/machinery/netpod/relaymove(mob/living/user, direction)
- if(!state_open)
- container_resist_act(user)
-
-/obj/machinery/netpod/container_resist_act(mob/living/user)
- user.visible_message(span_notice("[occupant] emerges from [src]!"),
- span_notice("You climb out of [src]!"),
- span_notice("With a hiss, you hear a machine opening."))
- open_machine()
-
-/obj/machinery/netpod/open_machine(drop = TRUE, density_to_set = FALSE)
- playsound(src, 'sound/machines/tramopen.ogg', 60, TRUE, frequency = 65000)
- flick("[base_icon_state]_opening", src)
- SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_OPENED)
- update_use_power(IDLE_POWER_USE)
-
- return ..()
-
-/obj/machinery/netpod/close_machine(mob/user, density_to_set = TRUE)
- if(!state_open || panel_open || !is_operational || !iscarbon(user))
- return
-
- playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
- flick("[base_icon_state]_closing", src)
- ..()
-
- enter_matrix()
-
-/obj/machinery/netpod/default_pry_open(obj/item/crowbar, mob/living/pryer)
- if(isnull(occupant) || !iscarbon(occupant))
- if(!state_open)
- if(panel_open)
- return FALSE
- open_machine()
- else
- shut_pod()
-
- return TRUE
-
- pryer.visible_message(
- span_danger("[pryer] starts prying open [src]!"),
- span_notice("You start to pry open [src]."),
- span_notice("You hear loud prying on metal.")
- )
- playsound(src, 'sound/machines/airlock_alien_prying.ogg', 100, TRUE)
-
- SEND_SIGNAL(src, COMSIG_BITRUNNER_CROWBAR_ALERT, pryer)
-
- if(do_after(pryer, 15 SECONDS, src))
- if(!state_open)
- sever_connection()
- open_machine()
-
- return TRUE
-
-/obj/machinery/netpod/ui_interact(mob/user, datum/tgui/ui)
- if(!is_operational || occupant)
- return
-
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "NetpodOutfits")
- ui.set_autoupdate(FALSE)
- ui.open()
-
-/obj/machinery/netpod/ui_data()
- var/list/data = list()
-
- data["netsuit"] = netsuit
- return data
-
-/obj/machinery/netpod/ui_static_data()
- var/list/data = list()
-
- if(!length(cached_outfits))
- cached_outfits += make_outfit_collection("Jobs", subtypesof(/datum/outfit/job))
-
- data["collections"] = cached_outfits
-
- return data
-
-/obj/machinery/netpod/ui_act(action, params)
- . = ..()
- if(.)
- return TRUE
- switch(action)
- if("select_outfit")
- var/datum/outfit/new_suit = resolve_outfit(params["outfit"])
- if(new_suit)
- netsuit = new_suit
- return TRUE
-
- return FALSE
-
-/obj/machinery/netpod/attack_ghost(mob/dead/observer/our_observer)
- var/our_target = avatar_ref?.resolve()
- if(isnull(our_target) || !our_observer.orbit(our_target))
- return ..()
-
-/// Puts the occupant in netpod stasis, basically short-circuiting environmental conditions
-/obj/machinery/netpod/proc/add_healing(mob/living/target)
- if(target != occupant)
- return
-
- target.AddComponent(/datum/component/netpod_healing, pod = src)
- target.playsound_local(src, 'sound/effects/submerge.ogg', 20, vary = TRUE)
- target.extinguish_mob()
- update_use_power(ACTIVE_POWER_USE)
-
-/// Disconnects the occupant after a certain time so they aren't just hibernating in netpod stasis. A balance change
-/obj/machinery/netpod/proc/auto_disconnect()
- if(isnull(occupant) || state_open || connected)
- return
-
- var/mob/player = occupant
- player.playsound_local(src, 'sound/effects/splash.ogg', 60, TRUE)
- to_chat(player, span_notice("The machine disconnects itself and begins to drain."))
- open_machine()
-
-/// Handles occupant post-disconnection effects like damage, sounds, etc
-/obj/machinery/netpod/proc/disconnect_occupant(cause_damage = FALSE)
- connected = FALSE
-
- var/mob/living/mob_occupant = occupant
- if(isnull(occupant) || mob_occupant.stat == DEAD)
- open_machine()
- return
-
- mob_occupant.playsound_local(src, 'sound/magic/blink.ogg', 25, TRUE)
- mob_occupant.set_static_vision(2 SECONDS)
- mob_occupant.set_temp_blindness(1 SECONDS)
- mob_occupant.Paralyze(2 SECONDS)
-
- if(!is_operational)
- open_machine()
- return
-
- var/heal_time = 1
- if(mob_occupant.health < mob_occupant.maxHealth)
- heal_time = (mob_occupant.stat + 2) * 5
- addtimer(CALLBACK(src, PROC_REF(auto_disconnect)), heal_time SECONDS, TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_DELETE_ME)
-
- if(!cause_damage)
- return
-
- mob_occupant.flash_act(override_blindness_check = TRUE, visual = TRUE)
- mob_occupant.adjustOrganLoss(ORGAN_SLOT_BRAIN, disconnect_damage)
- INVOKE_ASYNC(mob_occupant, TYPE_PROC_REF(/mob/living, emote), "scream")
- to_chat(mob_occupant, span_danger("You've been forcefully disconnected from your avatar! Your thoughts feel scrambled!"))
-
-/**
- * ### Enter Matrix
- * Finds any current avatars from this chair - or generates a new one
- *
- * New avatars cost 1 attempt, and this will eject if there's none left
- *
- * Connects the mind to the avatar if everything is ok
- */
-/obj/machinery/netpod/proc/enter_matrix()
- var/mob/living/carbon/human/neo = occupant
- if(!ishuman(neo) || neo.stat == DEAD || isnull(neo.mind))
- balloon_alert(neo, "invalid occupant.")
- return
-
- var/obj/machinery/quantum_server/server = find_server()
- if(isnull(server))
- balloon_alert(neo, "no server connected!")
- return
-
- var/datum/lazy_template/virtual_domain/generated_domain = server.generated_domain
- if(isnull(generated_domain) || !server.is_ready)
- balloon_alert(neo, "nothing loaded!")
- return
-
- var/mob/living/carbon/current_avatar = avatar_ref?.resolve()
- if(isnull(current_avatar) || current_avatar.stat != CONSCIOUS) // We need a viable avatar
- var/obj/structure/hololadder/wayout = server.generate_hololadder()
- if(isnull(wayout))
- balloon_alert(neo, "out of bandwidth!")
- return
- current_avatar = server.generate_avatar(wayout, netsuit)
- avatar_ref = WEAKREF(current_avatar)
- server.stock_gear(current_avatar, neo, generated_domain)
-
- neo.set_static_vision(3 SECONDS)
- add_healing(occupant)
-
- if(!validate_entry(neo, current_avatar))
- open_machine()
- return
-
- current_avatar.AddComponent( \
- /datum/component/avatar_connection, \
- old_mind = neo.mind, \
- old_body = neo, \
- server = server, \
- pod = src, \
- help_text = generated_domain.help_text, \
- )
-
- connected = TRUE
-
-/// Finds a server and sets the server_ref
-/obj/machinery/netpod/proc/find_server()
- var/obj/machinery/quantum_server/server = server_ref?.resolve()
- if(server)
- return server
-
- server = locate(/obj/machinery/quantum_server) in oview(4, src)
- if(isnull(server))
- return
-
- server_ref = WEAKREF(server)
- RegisterSignal(server, COMSIG_MACHINERY_REFRESH_PARTS, PROC_REF(on_server_upgraded))
- RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_COMPLETE, PROC_REF(on_domain_complete))
- RegisterSignal(server, COMSIG_BITRUNNER_DOMAIN_SCRUBBED, PROC_REF(on_domain_scrubbed))
-
- return server
-
-/// Creates a list of outfit entries for the UI.
-/obj/machinery/netpod/proc/make_outfit_collection(identifier, list/outfit_list)
- var/list/collection = list(
- "name" = identifier,
- "outfits" = list()
- )
-
- for(var/datum/outfit/outfit as anything in outfit_list)
- var/outfit_name = initial(outfit.name)
- if(findtext(outfit_name, "(") != 0 || findtext(outfit_name, "-") != 0) // No special variants please
- continue
-
- collection["outfits"] += list(list("path" = outfit, "name" = outfit_name))
-
- return list(collection)
-
-/// Machine has been broken - handles signals and reverting sprites
-/obj/machinery/netpod/proc/on_broken(datum/source)
- SIGNAL_HANDLER
-
- sever_connection()
-
-/// Checks the integrity, alerts occupants
-/obj/machinery/netpod/proc/on_damage_taken(datum/source, damage_amount)
- SIGNAL_HANDLER
-
- if(isnull(occupant) || !connected)
- return
-
- var/total = max_integrity - damage_amount
- var/integrity = (atom_integrity / total) * 100
- if(integrity > 50)
- return
-
- SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_INTEGRITY)
-
-/// Puts points on the current occupant's card account
-/obj/machinery/netpod/proc/on_domain_complete(datum/source, atom/movable/crate, reward_points)
- SIGNAL_HANDLER
-
- if(isnull(occupant) || !connected)
- return
-
- var/mob/living/player = occupant
-
- var/datum/bank_account/account = player.get_bank_account()
- if(isnull(account))
- return
-
- account.bitrunning_points += reward_points * 100
-
-/// The domain has been fully purged, so we should double check our avatar is deleted
-/obj/machinery/netpod/proc/on_domain_scrubbed(datum/source)
- SIGNAL_HANDLER
-
- var/mob/avatar = avatar_ref?.resolve()
- if(isnull(avatar))
- return
-
- QDEL_NULL(avatar)
-
-/// Boots out anyone in the machine && opens it
-/obj/machinery/netpod/proc/on_power_loss(datum/source)
- SIGNAL_HANDLER
-
- if(state_open)
- return
-
- if(isnull(occupant) || !connected)
- connected = FALSE
- open_machine()
- return
-
- sever_connection()
-
-/// When the server is upgraded, drops brain damage a little
-/obj/machinery/netpod/proc/on_server_upgraded(obj/machinery/quantum_server/source)
- SIGNAL_HANDLER
-
- disconnect_damage = BASE_DISCONNECT_DAMAGE * (1 - source.servo_bonus)
-
-/// Resolves a path to an outfit.
-/obj/machinery/netpod/proc/resolve_outfit(text)
- var/path = text2path(text)
- if(ispath(path, /datum/outfit))
- return path
-
-/// Severs the connection with the current avatar
-/obj/machinery/netpod/proc/sever_connection()
- if(isnull(occupant) || !connected)
- return
-
- SEND_SIGNAL(src, COMSIG_BITRUNNER_NETPOD_SEVER)
-
-/// Closes the machine without shoving in an occupant
-/obj/machinery/netpod/proc/shut_pod()
- state_open = FALSE
- playsound(src, 'sound/machines/tramclose.ogg', 60, TRUE, frequency = 65000)
- flick("[base_icon_state]_closing", src)
- set_density(TRUE)
-
- update_appearance()
-
-/// Checks for cases to eject/fail connecting an avatar
-/obj/machinery/netpod/proc/validate_entry(mob/living/neo, mob/living/avatar)
- if(!do_after(neo, 2 SECONDS, src))
- return FALSE
-
- // Very invalid
- if(QDELETED(neo) || QDELETED(avatar) || QDELETED(src) || !is_operational)
- return FALSE
-
- // Invalid
- if(occupant != neo || isnull(neo.mind) || neo.stat > SOFT_CRIT || avatar.stat == DEAD)
- return FALSE
-
- return TRUE
-
-#undef BASE_DISCONNECT_DAMAGE
diff --git a/code/modules/bitrunning/objects/quantum_console.dm b/code/modules/bitrunning/objects/quantum_console.dm
index 9a0f48ae80b8..b87bf433cde1 100644
--- a/code/modules/bitrunning/objects/quantum_console.dm
+++ b/code/modules/bitrunning/objects/quantum_console.dm
@@ -16,6 +16,11 @@
. = ..()
find_server()
+/obj/machinery/computer/quantum_console/examine(mob/user)
+ . = ..()
+ if(!server_ref)
+ . += span_warning("Please install an quantum server in any tile next to this console.")
+
/obj/machinery/computer/quantum_console/ui_interact(mob/user, datum/tgui/ui)
. = ..()
@@ -71,13 +76,13 @@
switch(action)
if("random_domain")
- server.cold_boot_map(server.get_random_domain_id())
+ server.cold_boot_map(server.get_random_domain_id(), was_random_selection = TRUE)
return TRUE
if("refresh")
ui.send_full_update()
return TRUE
if("set_domain")
- server.cold_boot_map(params["id"])
+ server.cold_boot_map(params["id"], was_random_selection = FALSE)
return TRUE
if("stop_domain")
server.begin_shutdown(usr)
diff --git a/code/modules/bitrunning/objects/vendor.dm b/code/modules/bitrunning/objects/vendor.dm
index 6c66f7e379d8..2fab4b6e9024 100644
--- a/code/modules/bitrunning/objects/vendor.dm
+++ b/code/modules/bitrunning/objects/vendor.dm
@@ -23,6 +23,7 @@
CATEGORY_BEPIS,
)
blackbox_key = "bitrunning"
+ announcement_line = "A bitrunner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!"
/obj/machinery/computer/order_console/bitrunning/subtract_points(final_cost, obj/item/card/id/card)
if(final_cost <= card.registered_account.bitrunning_points)
@@ -56,7 +57,7 @@
can_be_cancelled = FALSE,
)
say("Thank you for your purchase! It will arrive on the next cargo shuttle!")
- radio.talk_into(src, "A bitrunner has ordered equipment which will arrive on the cargo shuttle! Please make sure it gets to them as soon as possible!", radio_channel)
+ aas_config_announce(/datum/aas_config_entry/order_console, list(), src, list(radio_channel), capitalize(blackbox_key))
SSshuttle.shopping_list += new_order
/obj/machinery/computer/order_console/bitrunning/retrieve_points(obj/item/card/id/id_card)
diff --git a/code/modules/bitrunning/outfits.dm b/code/modules/bitrunning/outfits.dm
index d8a288f8af2a..4cbf2ea60d7d 100644
--- a/code/modules/bitrunning/outfits.dm
+++ b/code/modules/bitrunning/outfits.dm
@@ -10,12 +10,62 @@
suit = /obj/item/clothing/suit/jacket/leather_trenchcoat
id = /obj/item/card/id/advanced
+
/datum/outfit/echolocator/post_equip(mob/living/carbon/human/user, visualsOnly)
. = ..()
user.psykerize()
+
/datum/outfit/bitductor
name = "Bitrunning Abductor"
uniform = /obj/item/clothing/under/abductor
gloves = /obj/item/clothing/gloves/fingerless
shoes = /obj/item/clothing/shoes/jackboots
+
+
+/datum/outfit/beachbum_combat
+ name = "Beachbum: Island Combat"
+ id = /obj/item/card/id/advanced
+ l_pocket = null
+ r_pocket = null
+ shoes = /obj/item/clothing/shoes/sandal
+ uniform = /obj/item/clothing/under/pants/jeans
+ /// Available ranged weapons
+ var/list/ranged_weaps = list(
+ /obj/item/gun/ballistic/automatic/pistol,
+ /obj/item/gun/ballistic/rifle/boltaction,
+ /obj/item/gun/ballistic/automatic/mini_uzi,
+ /obj/item/gun/ballistic/automatic/pistol/deagle,
+ /obj/item/gun/ballistic/rocketlauncher/unrestricted,
+ /obj/item/gun/ballistic/automatic/ar,
+
+ )
+ /// Corresponding ammo
+ var/list/corresponding_ammo = list(
+ /obj/item/ammo_box/magazine/m9mm,
+ /obj/item/ammo_box/strilka310,
+ /obj/item/ammo_box/magazine/uzim9mm,
+ /obj/item/ammo_box/magazine/m50,
+ /obj/item/food/pizzaslice/dank, // more silly, less destructive
+ /obj/item/ammo_box/magazine/m223,
+ )
+
+
+/datum/outfit/beachbum_combat/post_equip(mob/living/carbon/human/bum, visualsOnly)
+ . = ..()
+
+ var/choice = rand(1, length(ranged_weaps))
+ var/weapon = ranged_weaps[choice]
+ bum.put_in_active_hand(new weapon)
+
+ var/ammo = corresponding_ammo[choice]
+ var/obj/item/ammo1 = new ammo
+ var/obj/item/ammo2 = new ammo
+
+ if(!bum.equip_to_slot_if_possible(new ammo, ITEM_SLOT_LPOCKET))
+ ammo1.forceMove(get_turf(bum))
+ if(!bum.equip_to_slot_if_possible(new ammo, ITEM_SLOT_RPOCKET))
+ ammo2.forceMove(get_turf(bum))
+
+ if(prob(50))
+ bum.equip_to_slot_if_possible(new /obj/item/clothing/glasses/sunglasses, ITEM_SLOT_EYES)
diff --git a/code/modules/bitrunning/server/_parent.dm b/code/modules/bitrunning/server/_parent.dm
index b398d8d1aa33..82adb01cacb5 100644
--- a/code/modules/bitrunning/server/_parent.dm
+++ b/code/modules/bitrunning/server/_parent.dm
@@ -16,6 +16,8 @@
var/datum/lazy_template/virtual_domain/generated_domain
/// If the current domain was a random selection
var/domain_randomized = FALSE
+ /// Whether the domain is finished, so the bitrunners can leave despite glitches
+ var/domain_complete = FALSE
/// Prevents multiple user actions. Handled by loading domains and cooldowns
var/is_ready = TRUE
/// Chance multipled by threat to spawn a glitch
@@ -27,11 +29,9 @@
/// Any ghosts that have spawned in
var/list/datum/weakref/spawned_threat_refs = list()
/// Scales loot with extra players
- var/multiplayer_bonus = 1.2
+ var/multiplayer_bonus = 1.1
/// Extra bonus for every player that nohits the run
var/nohit_bonus = 0.8
- ///The radio the console can speak into
- var/obj/item/radio/radio
/// The amount of points in the system, used to purchase maps
var/points = 0
/// Keeps track of the number of times someone has built a hololadder
@@ -52,14 +52,15 @@
var/broadcasting = FALSE
/// Cooldown between being able to toggle broadcasting
COOLDOWN_DECLARE(broadcast_toggle_cd)
+ /// Cooldown for how often you're allowed to harass deadchat for PVP domains
+ COOLDOWN_DECLARE(polling_cooldown)
-/obj/machinery/quantum_server/post_machine_initialize()
+/obj/machinery/quantum_server/Initialize(mapload)
. = ..()
+ register_context()
- radio = new(src)
- radio.keyslot = new /obj/item/encryptionkey/headset_cargo()
- radio.set_listening(FALSE)
- radio.recalculateChannels()
+/obj/machinery/quantum_server/post_machine_initialize()
+ . = ..()
RegisterSignals(src, list(COMSIG_MACHINERY_BROKEN, COMSIG_MACHINERY_POWER_LOST), PROC_REF(on_broken))
RegisterSignal(src, COMSIG_QDELETING, PROC_REF(on_delete))
@@ -70,20 +71,41 @@
spawned_threat_refs.Cut()
exit_turfs.Cut()
QDEL_NULL(generated_domain)
- QDEL_NULL(radio)
return ..()
+/obj/machinery/quantum_server/add_context(atom/source, list/context, obj/item/held_item, mob/user)
+ . = NONE
+ if(isnull(held_item))
+ return
+
+ if(held_item.tool_behaviour == TOOL_SCREWDRIVER)
+ context[SCREENTIP_CONTEXT_LMB] = "[panel_open ? "Close" : "Open"] Panel"
+ return CONTEXTUAL_SCREENTIP_SET
+ else if(held_item.tool_behaviour == TOOL_CROWBAR && panel_open)
+ context[SCREENTIP_CONTEXT_LMB] = "Deconstruct"
+ return CONTEXTUAL_SCREENTIP_SET
+
/obj/machinery/quantum_server/examine(mob/user)
. = ..()
. += span_infoplain("Can be resource intensive to run. Ensure adequate power supply.")
+ . += span_notice("Its maintainance panel can be [EXAMINE_HINT("screwed")] [panel_open ? "close" : "open"].")
+ if(panel_open)
+ . += span_notice("It can be [EXAMINE_HINT("pried")] apart.")
+
+ var/upgraded = FALSE
if(capacitor_coefficient < 1)
. += span_infoplain("- Its coolant capacity reduces cooldown time by [(1 - capacitor_coefficient) * 100]%.")
+ upgraded = TRUE
if(servo_bonus > 0.2)
. += span_infoplain("- Its manipulation potential is increasing rewards by [servo_bonus]x.")
. += span_infoplain("- Injury from unsafe ejection reduced [servo_bonus * 100]%.")
+ upgraded = TRUE
+
+ if(!upgraded)
+ . += span_notice("Its output is suboptimal. Improved components will grant domain information, reduce cooldowns and increase rewards.")
if(!is_ready)
. += span_notice("It is currently cooling down. Give it a few moments.")
@@ -122,7 +144,7 @@
return ..()
-/obj/machinery/quantum_server/item_interaction(mob/living/user, obj/item/tool, list/modifiers, list/attack_modifiers)
+/obj/machinery/quantum_server/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
if(!istype(tool, /obj/item/bitrunning_debug))
return NONE
@@ -134,27 +156,23 @@
return ITEM_INTERACT_SUCCESS
/obj/machinery/quantum_server/crowbar_act(mob/living/user, obj/item/crowbar)
- . = ..()
-
+ . = NONE
if(!is_ready)
balloon_alert(user, "it's scalding hot!")
- return TRUE
+ return ITEM_INTERACT_FAILURE
if(length(avatar_connection_refs))
balloon_alert(user, "all clients must disconnect!")
- return TRUE
+ return ITEM_INTERACT_FAILURE
if(default_deconstruction_crowbar(crowbar))
- return TRUE
- return FALSE
+ return ITEM_INTERACT_SUCCESS
/obj/machinery/quantum_server/screwdriver_act(mob/living/user, obj/item/screwdriver)
- . = ..()
-
+ . = NONE
if(!is_ready)
balloon_alert(user, "it's scalding hot!")
- return TRUE
- if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", icon_state, screwdriver))
- return TRUE
- return FALSE
+ return ITEM_INTERACT_FAILURE
+ if(default_deconstruction_screwdriver(user, "[base_icon_state]_panel", base_icon_state, screwdriver))
+ return ITEM_INTERACT_SUCCESS
/obj/machinery/quantum_server/RefreshParts()
var/capacitor_rating = 1.15
@@ -174,3 +192,10 @@
servo_bonus = servo_rating
return ..()
+
+/datum/aas_config_entry/bitrunning_QS_ready_announcement
+ name = "Cargo Alert: Bitrunning QS Ready"
+ general_tooltip = "Announces when the quantum server is ready to be used. No variables provided"
+ announcement_lines_map = list(
+ "Message" = "Quantum Server report: Thermal systems within operational parameters. Proceeding to domain configuration."
+ )
diff --git a/code/modules/bitrunning/server/loot.dm b/code/modules/bitrunning/server/loot.dm
index 36fdd2b39d03..f46b39bede9b 100644
--- a/code/modules/bitrunning/server/loot.dm
+++ b/code/modules/bitrunning/server/loot.dm
@@ -19,7 +19,7 @@
/obj/machinery/quantum_server/proc/get_multiplayer_bonus()
var/total = 0
var/multiplayer = FALSE
- for(var/datum/weakref/connection_ref in avatar_connection_refs)
+ for(var/datum/weakref/connection_ref as anything in avatar_connection_refs)
var/datum/component/avatar_connection/connection = connection_ref.resolve()
if(isnull(connection))
continue
@@ -34,11 +34,9 @@
return 0
var/total = 0
- for(var/datum/weakref/connection_ref in avatar_connection_refs)
+ for(var/datum/weakref/connection_ref as anything in avatar_connection_refs)
var/datum/component/avatar_connection/connection = connection_ref.resolve()
- if(isnull(connection))
- continue
- if(connection.nohit)
+ if(connection?.nohit)
total += nohit_bonus
return total
@@ -56,8 +54,11 @@
var/bonus = calculate_rewards()
+ var/time_difference = world.time - generated_domain.start_time
+ var/grade = grade_completion(time_difference)
+
var/obj/item/paper/certificate = new()
- certificate.add_raw_text(get_completion_certificate())
+ certificate.add_raw_text(get_completion_certificate(time_difference, grade))
certificate.name = "certificate of domain completion"
certificate.update_appearance()
@@ -65,9 +66,20 @@
reward_cache.manifest = certificate
reward_cache.update_appearance()
+ generated_domain.submit_grade(grade)
+
+ if(can_generate_tech_disk(grade))
+ SSblackbox.record_feedback("tally", "bitrunning_bepis_rewarded", 1, generated_domain.key)
+ new /obj/item/disk/design_disk/bepis/remove_tech(reward_cache)
+ generated_domain.disk_reward_spawned = TRUE
+
chosen_forge.start_to_spawn(reward_cache)
+
+ domain_complete = TRUE
return TRUE
+
+/// Builds secondary loot if the achievements were met
/obj/machinery/quantum_server/proc/generate_secondary_loot(obj/curiosity, obj/machinery/byteforge/chosen_forge)
spark_at_location(curiosity) // abracadabra!
qdel(curiosity) // and it's gone!
@@ -77,8 +89,9 @@
chosen_forge.start_to_spawn(reward_curiosity)
return TRUE
+
/// Returns the markdown text containing domain completion information
-/obj/machinery/quantum_server/proc/get_completion_certificate()
+/obj/machinery/quantum_server/proc/get_completion_certificate(time_difference, grade)
var/base_points = generated_domain.reward_points
if(domain_randomized)
base_points -= 1
@@ -87,11 +100,9 @@
var/domain_threats = length(spawned_threat_refs)
- var/time_difference = world.time - generated_domain.start_time
-
var/completion_time = "### Completion Time: [DisplayTimeText(time_difference)]\n"
- var/grade = "\n---\n\n# Rating: [grade_completion(time_difference)]"
+ var/completion_grade = "\n---\n\n# Rating: [grade]"
var/text = "# Certificate of Domain Completion\n\n---\n\n"
@@ -103,7 +114,7 @@
if(bonuses <= 1)
text += completion_time
- text += grade
+ text += completion_grade
return text
text += "### Bonuses\n"
@@ -127,10 +138,25 @@
text += "- **Components:** + [servo_rating]\n"
text += completion_time
- text += grade
+ text += completion_grade
return text
+/// Checks if the players should get a bepis reward
+/obj/machinery/quantum_server/proc/can_generate_tech_disk(grade)
+ if(generated_domain.disk_reward_spawned)
+ return FALSE
+
+ if(!LAZYLEN(SSresearch.techweb_nodes_experimental))
+ return FALSE
+
+ var/static/list/passing_grades = list()
+ if(!passing_grades.len)
+ passing_grades = list(BITRUNNING_GRADE_A,BITRUNNING_GRADE_S)
+
+ return generated_domain.difficulty >= BITRUNNER_DIFFICULTY_MEDIUM && (grade in passing_grades)
+
+
/// Grades the player's run based on several factors
/obj/machinery/quantum_server/proc/grade_completion(completion_time)
var/score = length(spawned_threat_refs) * 5
@@ -157,12 +183,12 @@
switch(score)
if(1 to 4)
- return "D"
+ return BITRUNNING_GRADE_D
if(5 to 7)
- return "C"
+ return BITRUNNING_GRADE_C
if(8 to 10)
- return "B"
+ return BITRUNNING_GRADE_B
if(11 to 13)
- return "A"
+ return BITRUNNING_GRADE_A
else
- return "S"
+ return BITRUNNING_GRADE_S
diff --git a/code/modules/bitrunning/server/map_handling.dm b/code/modules/bitrunning/server/map_handling.dm
index fb5b8b431495..65c4c9c91d88 100644
--- a/code/modules/bitrunning/server/map_handling.dm
+++ b/code/modules/bitrunning/server/map_handling.dm
@@ -1,3 +1,5 @@
+#define POLLING_COOLDOWN_TIME 2 MINUTES
+
/// Gives all current occupants a notification that the server is going down
/obj/machinery/quantum_server/proc/begin_shutdown(mob/user)
if(isnull(generated_domain))
@@ -24,8 +26,9 @@
reset()
+
/// Links all the loading processes together - does validation for booting a map
-/obj/machinery/quantum_server/proc/cold_boot_map(map_key)
+/obj/machinery/quantum_server/proc/cold_boot_map(map_key, was_random_selection)
if(!is_ready)
return FALSE
@@ -51,6 +54,20 @@
is_ready = TRUE
return FALSE
+
+ //We will want to record how the domain was selected. Either entirely randomly, with the name redacted, or with full information.
+ //Without this, it is difficult to determine what domains are selected more often intentionallly, vs unintentionally.
+ var/selection_type
+
+ if(was_random_selection)
+ selection_type = "random selection"
+ else
+ if(generated_domain.can_view_name(scanner_tier, points))
+ selection_type = "full information"
+ else
+ selection_type = "redacted information"
+ SSblackbox.record_feedback("nested tally", "bitrunning_domain_loaded", 1, list(selection_type, map_key))
+
is_ready = TRUE
var/spawn_chance = clamp((threat * glitch_chance), 5, threat_prob_max)
@@ -67,18 +84,54 @@
if(broadcasting)
start_broadcasting_network(BITRUNNER_CAMERA_NET)
+ if(generated_domain.announce_to_ghosts)
+ notify_ghosts("Bitrunners have loaded a domain that offers ghost interactions. Check the spawners menu for more information.",
+ src,
+ "Matrix Glitch",
+ )
+
return TRUE
+
/// Initializes a new domain if the given key is valid and the user has enough points
/obj/machinery/quantum_server/proc/load_domain(map_key)
for(var/datum/lazy_template/virtual_domain/available in SSbitrunning.all_domains)
if(map_key == available.key && points >= available.cost)
generated_domain = available
- RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
- generated_domain.lazy_load()
- return TRUE
+ break
+
+ if(!generated_domain)
+ return FALSE
+
+ if(generated_domain.mission_min_candidates && (!COOLDOWN_FINISHED(src, polling_cooldown)))
+ say("Advanced NPC algorithms resetting, please wait [DisplayTimeText(polling_cooldown)] or load a different domain.")
+ playsound(src, "sound/machines/buzz-[pick("sigh", "two")].ogg", 50, TRUE)
+ return FALSE
- return FALSE
+ var/list/mob/lucky_ghosts
+ if(generated_domain.mission_min_candidates)
+ playsound(src, 'sound/machines/chime.ogg', 50, TRUE)
+ say("Loading advanced NPCs...")
+ var/list/mob/candidates = SSpolling.poll_ghost_candidates("Do you want to play as a virtual [generated_domain.spawner_role] in a bitrunner domain?", ROLE_GHOST_ROLE, ROLE_GHOST_ROLE, 15 SECONDS, POLL_IGNORE_SHUTTLE_DENIZENS, TRUE)
+ for(var/amount in 1 to generated_domain.mission_max_candidates)
+ if(length(candidates)) // If no candidates, fails in code below anyways
+ LAZYADD(lucky_ghosts, pick_n_take(candidates))
+
+ if(length(lucky_ghosts) < generated_domain.mission_min_candidates)
+ notify_ghosts("Not enough candidates for [generated_domain.spawner_role]! Aborting mission!")
+ playsound(src, "sound/machines/buzz-[pick("sigh", "two")].ogg", 50, TRUE)
+ say("Error! Unable to load advanced NPCs. Please try again or select different domain.")
+ COOLDOWN_START(src, polling_cooldown, POLLING_COOLDOWN_TIME)
+ return FALSE
+
+ playsound(src, 'sound/machines/ping.ogg', 50, TRUE)
+ say("Success!")
+
+ generated_domain.load_advanced_npcs(lucky_ghosts)
+ RegisterSignal(generated_domain, COMSIG_LAZY_TEMPLATE_LOADED, PROC_REF(on_template_loaded))
+ generated_domain.lazy_load()
+
+ return TRUE
/// Loads in necessary map items like hololadder spawns, caches, etc
/obj/machinery/quantum_server/proc/load_map_items()
@@ -105,21 +158,31 @@
qdel(thing)
continue
+ if(istype(thing, /obj/effect/mob_spawn))
+ generated_domain.ghost_spawners += thing
+ continue
+
if(istype(thing, /obj/effect/landmark/bitrunning/curiosity_spawn))
curiosity_turfs += get_turf(thing)
qdel(thing)
continue
if(istype(thing, /obj/effect/landmark/bitrunning/loot_signal))
- var/turf/signaler_turf = get_turf(thing)
- signaler_turf.AddComponent(/datum/component/bitrunning_points, generated_domain)
+ generated_domain.main_crate_loc = thing.loc
qdel(thing)
+ continue
+
+ if(istype(thing, /obj/effect/landmark/bitrunning/permanent_exit))
+ var/turf/tile = get_turf(thing)
+ exit_turfs += tile
+ qdel(thing)
+
+ new /obj/structure/hololadder(tile)
if(!length(exit_turfs))
CRASH("Failed to find exit turfs on generated domain.")
if(!length(goal_turfs))
CRASH("Failed to find send turfs on generated domain.")
-
if(!attempt_spawn_cache(cache_turfs))
return FALSE
@@ -132,9 +195,11 @@
return TRUE
+
/// Stops the current virtual domain and disconnects all users
/obj/machinery/quantum_server/proc/reset(fast = FALSE)
is_ready = FALSE
+ domain_complete = FALSE
sever_connections()
@@ -153,6 +218,7 @@
stop_broadcasting_network(BITRUNNER_CAMERA_NET)
+
/// Tries to clean up everything in the domain
/obj/machinery/quantum_server/proc/scrub_vdom()
sever_connections() /// just in case someone's connected
@@ -171,9 +237,12 @@
creature.dust(just_ash = TRUE, force = TRUE) // sometimes mobs just don't die
generated_domain.secondary_loot_generated = 0
+ generated_domain.main_crate_points = 0
avatar_connection_refs.Cut()
exit_turfs = list()
generated_domain = null
mutation_candidate_refs.Cut()
spawned_threat_refs.Cut()
+
+#undef POLLING_COOLDOWN_TIME
diff --git a/code/modules/bitrunning/server/obj_generation.dm b/code/modules/bitrunning/server/obj_generation.dm
index 54c265f8e33a..0e88ff2c5a16 100644
--- a/code/modules/bitrunning/server/obj_generation.dm
+++ b/code/modules/bitrunning/server/obj_generation.dm
@@ -15,6 +15,7 @@
new /obj/structure/closet/crate/secure/bitrunning/encrypted(chosen_turf)
return TRUE
+
/// Attempts to spawn a lootbox
/obj/machinery/quantum_server/proc/attempt_spawn_curiosity(list/possible_turfs)
if(!length(possible_turfs)) // Out of turfs to place a curiosity
@@ -35,9 +36,10 @@
new /obj/item/storage/lockbox/bitrunning/encrypted(chosen_turf)
return chosen_turf
+
/// Generates a new avatar for the bitrunner.
-/obj/machinery/quantum_server/proc/generate_avatar(obj/structure/hololadder/wayout, datum/outfit/netsuit)
- var/mob/living/carbon/human/avatar = new(wayout.loc)
+/obj/machinery/quantum_server/proc/generate_avatar(turf/destination, datum/outfit/netsuit)
+ var/mob/living/carbon/human/avatar = new(destination)
avatar.mind_initialize()
avatar.mind.set_level(/datum/skill/eva, SKILL_LEVEL_MASTER, silent = TRUE)
@@ -67,8 +69,9 @@
if(istype(hat))
hat.set_armor(/datum/armor/none)
- for(var/obj/thing in avatar.held_items)
- qdel(thing)
+ if(!generated_domain.forced_outfit)
+ for(var/obj/thing in avatar.held_items)
+ qdel(thing)
var/obj/item/storage/backpack/bag = avatar.back
if(istype(bag))
@@ -94,32 +97,9 @@
network = BITRUNNER_CAMERA_NET, \
emp_proof = TRUE, \
)
- return avatar
-
-/// Generates a new hololadder for the bitrunner. Effectively a respawn attempt.
-/obj/machinery/quantum_server/proc/generate_hololadder()
- if(!length(exit_turfs))
- return
-
- if(retries_spent >= length(exit_turfs))
- return
- var/turf/destination
- for(var/turf/dest_turf in exit_turfs)
- if(!locate(/obj/structure/hololadder) in dest_turf)
- destination = dest_turf
- break
-
- if(isnull(destination))
- return
-
- var/obj/structure/hololadder/wayout = new(destination, src)
- if(isnull(wayout))
- return
-
- retries_spent += 1
+ return avatar
- return wayout
/// Loads in any mob segments of the map
/obj/machinery/quantum_server/proc/load_mob_segments()
@@ -152,6 +132,7 @@
return TRUE
+
/// Scans over neo's contents for bitrunning tech disks. Loads the items or abilities onto the avatar.
/obj/machinery/quantum_server/proc/stock_gear(mob/living/carbon/human/avatar, mob/living/carbon/human/neo, datum/lazy_template/virtual_domain/generated_domain)
var/domain_forbids_flags = generated_domain.domain_flags
diff --git a/code/modules/bitrunning/server/signal_handlers.dm b/code/modules/bitrunning/server/signal_handlers.dm
index 0e5e949e8bb5..f5d2840143e1 100644
--- a/code/modules/bitrunning/server/signal_handlers.dm
+++ b/code/modules/bitrunning/server/signal_handlers.dm
@@ -4,12 +4,14 @@
sever_connections()
+
/// Whenever a corpse spawner makes a new corpse, add it to the list of potential mutations
/obj/machinery/quantum_server/proc/on_corpse_spawned(datum/source, mob/living/corpse)
SIGNAL_HANDLER
mutation_candidate_refs.Add(WEAKREF(corpse))
+
/// Being qdeleted - make sure the circuit and connected mobs go with it
/obj/machinery/quantum_server/proc/on_delete(datum/source)
SIGNAL_HANDLER
@@ -26,6 +28,7 @@
if(circuit)
qdel(circuit)
+
/// Whenever something enters the send tiles, check if it's a loot crate. If so, alert players.
/obj/machinery/quantum_server/proc/on_goal_turf_entered(datum/source, atom/movable/arrived, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
@@ -51,6 +54,7 @@
generate_secondary_loot(arrived, chosen_forge, generated_domain)
return
+
/// Handles examining the server. Shows cooldown time and efficiency.
/obj/machinery/quantum_server/proc/on_goal_turf_examined(datum/source, mob/examiner, list/examine_text)
SIGNAL_HANDLER
@@ -58,6 +62,7 @@
examine_text += span_info("Beneath your gaze, the floor pulses subtly with streams of encoded data.")
examine_text += span_info("It seems to be part of the location designated for retrieving encrypted payloads.")
+
/// Scans over the inbound created_atoms from lazy templates
/obj/machinery/quantum_server/proc/on_template_loaded(datum/lazy_template/source, list/created_atoms)
SIGNAL_HANDLER
@@ -98,6 +103,7 @@
/// Just in case there's any special handling for the domain
generated_domain.setup_domain(created_atoms)
+
/// Handles when cybercops are summoned into the area or ghosts click a ghost role spawner
/obj/machinery/quantum_server/proc/on_threat_created(datum/source, mob/living/threat)
SIGNAL_HANDLER
diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm
index 4c44355412bf..22558f51925d 100644
--- a/code/modules/bitrunning/server/threats.dm
+++ b/code/modules/bitrunning/server/threats.dm
@@ -4,6 +4,7 @@
SEND_SIGNAL(src, COMSIG_BITRUNNER_THREAT_CREATED)
threat.AddComponent(/datum/component/virtual_entity, src)
+
/// Choses which antagonist role is spawned based on threat
/obj/machinery/quantum_server/proc/get_antagonist_role()
var/list/available = list()
@@ -19,6 +20,7 @@
return chosen
+
/// Selects a target to mutate. Gives two attempts, then crashes if it fails.
/obj/machinery/quantum_server/proc/get_mutation_target()
var/datum/weakref/target_ref = pick(mutation_candidate_refs)
@@ -35,6 +37,7 @@
resolved = target_ref.resolve()
return resolved
+
/// Finds any mobs with minds in the zones and gives them the bad news
/obj/machinery/quantum_server/proc/notify_spawned_threats()
for(var/datum/weakref/baddie_ref as anything in spawned_threat_refs)
@@ -52,10 +55,12 @@
to_chat(baddie, span_userdanger("You have been flagged for deletion! Thank you for your service."))
+
/// Removes a specific threat - used when station spawning
/obj/machinery/quantum_server/proc/remove_threat(mob/living/threat)
spawned_threat_refs.Remove(WEAKREF(threat))
+
/// Selects the role and waits for a ghost orbiter
/obj/machinery/quantum_server/proc/setup_glitch(datum/antagonist/bitrunning_glitch/forced_role)
if(!validate_mutation_candidates())
@@ -82,6 +87,7 @@
return mutation_target
+
/// Orbit poll has concluded - spawn the antag
/obj/machinery/quantum_server/proc/spawn_glitch(datum/antagonist/bitrunning_glitch/chosen_role, mob/living/mutation_target, mob/dead/observer/ghost)
if(QDELETED(mutation_target))
@@ -119,18 +125,38 @@
add_threats(new_mob)
+
/// Oh boy - transports the antag station side
/obj/machinery/quantum_server/proc/station_spawn(mob/living/antag, obj/machinery/byteforge/chosen_forge)
antag.balloon_alert(antag, "scanning...")
chosen_forge.setup_particles(angry = TRUE)
- radio.talk_into(src, "SECURITY BREACH: Unauthorized entry sequence detected.", RADIO_CHANNEL_SUPPLY)
+ var/obj/machinery/announcement_system/aas = get_announcement_system(source = src)
+ if (aas)
+ aas.broadcast("QUANTUM SERVER ALERT: Security breach detected. Unauthorized entry sequence in progress...", list(RADIO_CHANNEL_SUPPLY))
SEND_SIGNAL(src, COMSIG_BITRUNNER_STATION_SPAWN)
var/timeout = 2 SECONDS
if(!ishuman(antag))
- radio.talk_into(src, "Fabrication protocols have crashed unexpectedly. Please evacuate the area.", RADIO_CHANNEL_SUPPLY)
+ if (aas)
+ aas.broadcast("QUANTUM SERVER ALERT: Fabrication protocols have crashed unexpectedly. Please evacuate the area.", list(RADIO_CHANNEL_SUPPLY))
timeout = 10 SECONDS
+ var/bitrunners_alive = 0
+ var/island_brawl_exception = istype(generated_domain, /datum/lazy_template/virtual_domain/island_brawl)
+ for(var/datum/weakref/bitrunner_ref in avatar_connection_refs)
+ var/mob/living/bitrunner = astype(bitrunner_ref.resolve(), /datum/component/avatar_connection)?.parent
+ if(!bitrunner)
+ continue
+ if((bitrunner.stat > CONSCIOUS) || !bitrunner.client)
+ continue
+ if(island_brawl_exception)
+ timeout *= max(5 - generated_domain.main_crate_points, 1)
+ continue
+ bitrunners_alive++
+ timeout *= 5
+ if(bitrunners_alive)
+ to_chat(antag, span_warning("[bitrunners_alive] criminals still remain here, pilfering your domain. It will be more difficult to leave until they are handled."))
+
if(!do_after(antag, timeout) || QDELETED(chosen_forge) || QDELETED(antag) || QDELETED(src) || !is_ready || !is_operational)
chosen_forge.setup_particles()
return
@@ -150,8 +176,8 @@
if(ishuman(antag))
reset_equipment(antag)
- else
- radio.talk_into(src, "CRITICAL ALERT: Unregistered mechanical entity deployed.")
+ else if (aas)
+ aas.broadcast("QUANTUM SERVER CRITICAL ALERT: Unregistered mechanical entity deployed.", list())
var/datum/antagonist/antag_datum = antag.mind?.has_antag_datum(/datum/antagonist/bitrunning_glitch)
if(istype(antag_datum))
@@ -163,6 +189,7 @@
do_teleport(antag, get_turf(chosen_forge), forced = TRUE, asoundin = 'sound/magic/ethereal_enter.ogg', asoundout = 'sound/magic/ethereal_exit.ogg', channel = TELEPORT_CHANNEL_QUANTUM)
+
/// Removes any invalid candidates from the list
/obj/machinery/quantum_server/proc/validate_mutation_candidates()
for(var/datum/weakref/creature_ref as anything in mutation_candidate_refs)
diff --git a/code/modules/bitrunning/server/util.dm b/code/modules/bitrunning/server/util.dm
index 4fe45d382af0..c8cbca42d250 100644
--- a/code/modules/bitrunning/server/util.dm
+++ b/code/modules/bitrunning/server/util.dm
@@ -1,10 +1,12 @@
#define MAX_DISTANCE 4 // How far crates can spawn from the server
+
/// Resets the cooldown state and updates icons
/obj/machinery/quantum_server/proc/cool_off()
is_ready = TRUE
update_appearance()
- radio.talk_into(src, "Thermal systems within operational parameters. Proceeding to domain configuration.", RADIO_CHANNEL_SUPPLY)
+ aas_config_announce(/datum/aas_config_entry/bitrunning_QS_ready_announcement, list(), src, list(RADIO_CHANNEL_SUPPLY))
+
/// If there are hosted minds, attempts to get a list of their current virtual bodies w/ vitals
/obj/machinery/quantum_server/proc/get_avatar_data()
@@ -31,6 +33,49 @@
return hosted_avatars
+
+/// I grab the atom here so I can signal it / manipulate spawners etc
+/obj/machinery/quantum_server/proc/get_avatar_destination() as /atom
+ // Branch A: Custom spawns
+ if(length(generated_domain.custom_spawns))
+ var/atom/valid_spawner
+
+ while(isnull(valid_spawner))
+ var/atom/chosen = pick(generated_domain.custom_spawns)
+ if(QDELETED(chosen))
+ generated_domain.custom_spawns -= chosen
+ continue
+
+ valid_spawner = chosen
+ break
+
+ return valid_spawner
+
+ // Branch B: Hololadders
+ if(!length(exit_turfs))
+ return
+
+ if(retries_spent >= length(exit_turfs))
+ return
+
+ var/turf/exit_tile
+ for(var/turf/dest_turf in exit_turfs)
+ if(!locate(/obj/structure/hololadder) in dest_turf)
+ exit_tile = dest_turf
+ break
+
+ if(isnull(exit_tile))
+ return
+
+ var/obj/structure/hololadder/wayout = new(exit_tile, src)
+ if(isnull(wayout))
+ return
+
+ retries_spent += 1
+
+ return wayout
+
+
/// Locates any turfs with forges on them, returns a random one
/obj/machinery/quantum_server/proc/get_random_nearby_forge()
var/list/nearby_forges = list()
@@ -40,6 +85,7 @@
return pick(nearby_forges)
+
/// Gets a random available domain given the current points.
/obj/machinery/quantum_server/proc/get_random_domain_id()
if(points < 1)
@@ -85,6 +131,7 @@
SEND_SIGNAL(src, COMSIG_BITRUNNER_QSRV_SEVER)
+
/// Do some magic teleport sparks
/obj/machinery/quantum_server/proc/spark_at_location(obj/cache)
playsound(cache, 'sound/magic/blink.ogg', 50, vary = TRUE)
@@ -92,16 +139,33 @@
sparks.set_up(5, location = get_turf(cache))
sparks.start()
-/// Returns a turf if it's not dense, else will find a neighbor.
-/obj/machinery/quantum_server/proc/validate_turf(turf/chosen_turf)
- if(!chosen_turf.is_blocked_turf())
- return chosen_turf
- for(var/turf/tile in get_adjacent_open_turfs(chosen_turf))
- if(!tile.is_blocked_turf())
- return chosen_turf
+/// Starts building a new avatar for the player.
+/// Called by netpods when they don't have a current avatar.
+/// This is a procedural proc which links several others together.
+/obj/machinery/quantum_server/proc/start_new_connection(mob/living/carbon/human/neo, datum/outfit/netsuit) as /mob/living/carbon/human
+ var/atom/entry_atom = get_avatar_destination()
+ if(isnull(entry_atom))
+ return
+
+ var/mob/living/carbon/new_avatar = generate_avatar(get_turf(entry_atom), netsuit)
+ stock_gear(new_avatar, neo, generated_domain)
+
+ // Cleanup for domains with one time use custom spawns
+ if(!length(generated_domain.custom_spawns))
+ return new_avatar
+
+ // If we're spawning from some other fuckery, no need for this
+ if(istype(entry_atom, /obj/effect/mob_spawn/ghost_role/human/virtual_domain))
+ var/obj/effect/mob_spawn/ghost_role/human/virtual_domain/spawner = entry_atom
+ spawner.artificial_spawn(new_avatar)
+
+ if(!generated_domain.keep_custom_spawns)
+ generated_domain.custom_spawns -= entry_atom
+ qdel(entry_atom)
+
+ return new_avatar
-#undef MAX_DISTANCE
/// Toggles broadcast on and off
/obj/machinery/quantum_server/proc/toggle_broadcast()
@@ -116,3 +180,16 @@
// And we only flip TVs when there's a domain, because otherwise there's no cams to watch
set_network_broadcast_status(BITRUNNER_CAMERA_NET, broadcasting)
return TRUE
+
+
+/// Returns a turf if it's not dense, else will find a neighbor.
+/obj/machinery/quantum_server/proc/validate_turf(turf/chosen_turf)
+ if(!chosen_turf.is_blocked_turf())
+ return chosen_turf
+
+ for(var/turf/tile in get_adjacent_open_turfs(chosen_turf))
+ if(!tile.is_blocked_turf())
+ return chosen_turf
+
+
+#undef MAX_DISTANCE
diff --git a/code/modules/bitrunning/spawners.dm b/code/modules/bitrunning/spawners.dm
index 0ad7e454e6f2..8758062bd21e 100644
--- a/code/modules/bitrunning/spawners.dm
+++ b/code/modules/bitrunning/spawners.dm
@@ -3,12 +3,11 @@
prompt_name = "a virtual domain debug entity"
flavour_text = "You probably shouldn't be seeing this, contact a coder!"
you_are_text = "You are NOT supposed to be here. How did you let this happen?"
- important_text = "You must eliminate any bitrunners from the domain."
+ important_text = "Bitrunning is a crime, and your primary threat."
temp_body = TRUE
+ ///Does this bit-entity get an antag datum with the goal of hunting bitrunners? TRUE by default
+ var/antag = TRUE
-/obj/effect/mob_spawn/ghost_role/human/virtual_domain/Initialize(mapload)
- . = ..()
- notify_ghosts("The [name] has been created. The virtual world calls for aid!", src, "Virtual Insanity!")
/obj/effect/mob_spawn/ghost_role/human/virtual_domain/special(mob/living/spawned_mob, mob/mob_possessor)
var/datum/mind/ghost_mind = mob_possessor.mind
@@ -17,9 +16,43 @@
..()
- spawned_mob.mind.add_antag_datum(/datum/antagonist/domain_ghost_actor)
- spawned_mob.mind.set_assigned_role(SSjob.get_job_type(/datum/job/bitrunning_glitch))
+ if(antag)
+ spawned_mob.mind.add_antag_datum(/datum/antagonist/domain_ghost_actor)
+ spawned_mob.mind.set_assigned_role(SSjob.get_job_type(/datum/job/bitrunning_glitch))
+
+/// Simulates a ghost role spawn without calling special(), ie a bitrunner spawn instead of a ghost.
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/proc/artificial_spawn(mob/living/runner)
+ SEND_SIGNAL(src, COMSIG_BITRUNNER_SPAWNED, runner)
+
+//Beach Bums (Friendly)
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach
+ prompt_name = "a virtual beach bum"
+ name = "virtual beach bum sleeper"
+ you_are_text = "You're, like, totally a virtual simulation of a dudebro, bruh."
+ flavour_text = "Ch'yea. You came here, like, on spring break, hopin' to pick up some bangin' hot e-chicks, y'knaw?"
+ important_text = "You have no qualms with Bitrunning: in fact, you aren't even aware you're in a simulation."
+ outfit = /datum/outfit/beachbum
+ spawner_job_path = /datum/job/beach_bum
+ antag = FALSE
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/lifeguard
+ name = "virtual lifeguard sleeper"
+ you_are_text = "You are a spunky virtual lifeguard!"
+ flavour_text = "It's up to you to make sure nobody lags or gets eaten by malware and stuff."
+ outfit = /datum/outfit/beachbum/lifeguard
+
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/lifeguard/special(mob/living/carbon/human/lifeguard, mob/mob_possessor)
+ . = ..()
+ lifeguard.gender = FEMALE
+ lifeguard.update_body()
+
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/beach/bartender
+ name = "virtual bartender sleeper"
+ you_are_text = "You are a virtual beach bartender!"
+ flavour_text = "Your job is to keep the virtually rendered drinks coming, and help the dudebros engage drunkness simulations."
+ outfit = /datum/outfit/spacebartender
+
+//Skeleton Pirates
/obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate
name = "Virtual Pirate Remains"
desc = "Some inanimate bones. They feel like they could spring to life at any moment!"
@@ -28,19 +61,21 @@
icon_state = "remains"
prompt_name = "a virtual skeleton pirate"
you_are_text = "You are a virtual pirate. Yarrr!"
- flavour_text = "You have awoken, without instruction. There's a LANDLUBBER after yer booty. Stop them!"
+ flavour_text = " There's a LANDLUBBER after yer booty. Stop them!"
+
/obj/effect/mob_spawn/ghost_role/human/virtual_domain/pirate/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.fully_replace_character_name(spawned_mob.real_name, "[pick(strings(PIRATE_NAMES_FILE, "generic_beginnings"))][pick(strings(PIRATE_NAMES_FILE, "generic_endings"))]")
+//Syndicate
/obj/effect/mob_spawn/ghost_role/human/virtual_domain/syndie
name = "Virtual Syndicate Sleeper"
icon = 'icons/obj/machines/sleeper.dmi'
icon_state = "sleeper_s"
prompt_name = "a virtual syndicate operative"
you_are_text = "You are a virtual syndicate operative."
- flavour_text = "You have awoken, without instruction. Alarms blare! We are being boarded!"
+ flavour_text = "Alarms blare! We are being boarded!"
outfit = /datum/outfit/virtual_syndicate
spawner_job_path = /datum/job/space_syndicate
@@ -54,5 +89,6 @@
shoes = /obj/item/clothing/shoes/combat
implants = list(/obj/item/implant/weapons_auth)
+
/datum/outfit/virtual_syndicate/post_equip(mob/living/carbon/human/user, visualsOnly)
user.faction |= ROLE_SYNDICATE
diff --git a/code/modules/bitrunning/util/virtual_megafauna.dm b/code/modules/bitrunning/util/virtual_megafauna.dm
index 2707db9e2e74..6d2f2250c7bd 100644
--- a/code/modules/bitrunning/util/virtual_megafauna.dm
+++ b/code/modules/bitrunning/util/virtual_megafauna.dm
@@ -6,8 +6,16 @@
true_spawn = FALSE
+ // NON-MODULE CHANGE: its a proc here instead of an element so its just a singular var assignment
+ achievement_type = null
+
+ // remove the crusher loot element's arguments also to remove it appropriately
+ RemoveElement(\
+ /datum/element/crusher_loot,\
+ trophy_type = crusher_loot,\
+ guaranteed_drop = 0.6,\
+ drop_immediately = del_on_death,\
+ )
+
loot.Cut()
loot += /obj/structure/closet/crate/secure/bitrunning/encrypted
-
- crusher_loot.Cut()
- crusher_loot += /obj/structure/closet/crate/secure/bitrunning/encrypted
diff --git a/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm b/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm
index 5ae0793b6e92..12d6becc1367 100644
--- a/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/beach_bar.dm
@@ -13,6 +13,14 @@
for(var/obj/item/reagent_containers/cup/glass/drink in created_atoms)
RegisterSignal(drink, COMSIG_GLASS_DRANK, PROC_REF(on_drink_drank))
+ for(var/obj/machinery/vending/vending_machine in created_atoms)
+ RegisterSignal(vending_machine, COMSIG_VENDING_DISPENSED, PROC_REF(on_vended_item))
+
+
+/datum/lazy_template/virtual_domain/beach_bar/proc/on_vended_item(obj/machinery/vending/vending_machine, obj/item/vended_item)
+ if(istype(vended_item, /obj/item/reagent_containers/cup/glass))
+ RegisterSignal(vended_item, COMSIG_GLASS_DRANK, PROC_REF(on_drink_drank))
+
/// Eventually reveal the cache
/datum/lazy_template/virtual_domain/beach_bar/proc/on_drink_drank(datum/source)
diff --git a/code/modules/bitrunning/virtual_domain/domains/fredingtonfastingbear.dm b/code/modules/bitrunning/virtual_domain/domains/fredingtonfastingbear.dm
index 841956675ca9..f3c803384c45 100644
--- a/code/modules/bitrunning/virtual_domain/domains/fredingtonfastingbear.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/fredingtonfastingbear.dm
@@ -2,6 +2,7 @@
name = "Pizza Party"
cost = BITRUNNER_COST_MEDIUM
desc = "A famous pizzeria that got ruined by what it had to offer."
+ completion_loot = list(/obj/item/food/pizzaslice/meat/pizzeria = 1)
difficulty = BITRUNNER_DIFFICULTY_MEDIUM
help_text = "Pick up a flashlight and get going. Your favourite bear has been waiting for you..."
key = "fredingtonfastingbear"
diff --git a/code/modules/bitrunning/virtual_domain/domains/grassland_hunt.dm b/code/modules/bitrunning/virtual_domain/domains/grassland_hunt.dm
index b8840d6b952e..005587e9b7ef 100644
--- a/code/modules/bitrunning/virtual_domain/domains/grassland_hunt.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/grassland_hunt.dm
@@ -8,6 +8,7 @@
mob_modules = list(/datum/modular_mob_segment/deer)
domain_flags = DOMAIN_NO_NOHIT_BONUS
+
/datum/lazy_template/virtual_domain/grasslands_hunt/setup_domain(list/created_atoms)
for(var/obj/effect/landmark/bitrunning/mob_segment/landmark in created_atoms)
RegisterSignal(landmark, COMSIG_BITRUNNING_MOB_SEGMENT_SPAWNED, PROC_REF(on_spawned))
diff --git a/code/modules/bitrunning/virtual_domain/domains/heretic_hunt.dm b/code/modules/bitrunning/virtual_domain/domains/heretic_hunt.dm
index 2abd96e94c18..43225d18e38b 100644
--- a/code/modules/bitrunning/virtual_domain/domains/heretic_hunt.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/heretic_hunt.dm
@@ -182,7 +182,7 @@
name = "engineer"
death_spawner = /obj/effect/mob_spawn/corpse/human/engineer
weapon = /obj/item/weldingtool
- attack_sound = 'sound/items/welder.ogg'
+ attack_sound = 'sound/items/tools/welder.ogg'
melee_damage_type = BURN
damage_coeff = list(BRUTE = 1, BURN = 0.9, TOX = 1, STAMINA = 1, OXY = 1)
diff --git a/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm b/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm
new file mode 100644
index 000000000000..6368cacd726e
--- /dev/null
+++ b/code/modules/bitrunning/virtual_domain/domains/island_brawl.dm
@@ -0,0 +1,55 @@
+/datum/lazy_template/virtual_domain/island_brawl
+ name = "Island Brawl"
+ announce_to_ghosts = TRUE
+ cost = BITRUNNER_COST_HIGH
+ desc = "A 'peaceful' island tucked away in the middle of nowhere. This map will auto-complete after a number of deaths have occurred."
+ difficulty = BITRUNNER_DIFFICULTY_HIGH
+ forced_outfit = /datum/outfit/beachbum_combat
+ help_text = "There may be bounties laid out across the island, but the primary objective is to survive. Deaths on the island will count towards the final score."
+ key = "island_brawl"
+ map_name = "island_brawl"
+ reward_points = BITRUNNER_REWARD_HIGH
+ secondary_loot = list(
+ /obj/item/toy/beach_ball = 2,
+ /obj/item/clothing/shoes/sandal = 1,
+ /obj/item/clothing/glasses/sunglasses = 1,
+ /obj/item/gun/energy/laser/chameleon/ballistic_only = 1,
+ /obj/item/bitrunning_disk/item/mini_uzi = 1,
+ )
+ domain_flags = DOMAIN_TEST_ONLY // NON-MODULE CHANGE : we don't want island brawl here
+
+/datum/lazy_template/virtual_domain/island_brawl/setup_domain(list/created_atoms)
+ for(var/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander/spawner in created_atoms)
+ custom_spawns += spawner
+
+ RegisterSignal(spawner, COMSIG_QDELETING, PROC_REF(on_spawner_qdeleted))
+ RegisterSignals(spawner, list(COMSIG_GHOSTROLE_SPAWNED, COMSIG_BITRUNNER_SPAWNED), PROC_REF(on_spawn))
+
+
+/datum/lazy_template/virtual_domain/island_brawl/proc/on_spawner_qdeleted(obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander/source)
+ SIGNAL_HANDLER
+
+ custom_spawns -= source
+ UnregisterSignal(source, COMSIG_QDELETING)
+
+
+/// Someone has spawned in, so we check for their death
+/datum/lazy_template/virtual_domain/island_brawl/proc/on_spawn(datum/source, mob/living/spawned_mob)
+ SIGNAL_HANDLER
+
+ RegisterSignals(spawned_mob, list(COMSIG_LIVING_DEATH), PROC_REF(on_death))
+
+
+/// Mob has died, so we add a point to the domain
+/datum/lazy_template/virtual_domain/island_brawl/proc/on_death(datum/source, gibbed)
+ SIGNAL_HANDLER
+
+ add_points(1)
+
+
+/obj/effect/mob_spawn/ghost_role/human/virtual_domain/islander
+ name = "Islander"
+ outfit = /datum/outfit/beachbum_combat
+ prompt_name = "a combat beach bum"
+ you_are_text = "You are a virtual islander."
+ flavour_text = "Don't let anyone ruin your idyllic vacation spot. Coordinate with others- or don't!"
diff --git a/code/modules/bitrunning/virtual_domain/domains/pipedream.dm b/code/modules/bitrunning/virtual_domain/domains/pipedream.dm
index 595600ce71c4..33938fe4630a 100644
--- a/code/modules/bitrunning/virtual_domain/domains/pipedream.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/pipedream.dm
@@ -15,6 +15,7 @@
/datum/modular_mob_segment/hivebots_strong
)
reward_points = BITRUNNER_REWARD_LOW
+ domain_flags = DOMAIN_TEST_ONLY // NON-MODULE CHANGE : currently impossible, you get mulched by the recycler
// ID Trims
/datum/id_trim/factory
@@ -102,4 +103,3 @@
name = "Factory Quartermaster"
outfit = /datum/outfit/factory/qm
icon_state = "corpsecargotech"
-
diff --git a/code/modules/bitrunning/virtual_domain/domains/pirates.dm b/code/modules/bitrunning/virtual_domain/domains/pirates.dm
index 52d86a712118..b8bff6dbeb36 100644
--- a/code/modules/bitrunning/virtual_domain/domains/pirates.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/pirates.dm
@@ -1,5 +1,6 @@
/datum/lazy_template/virtual_domain/pirates
name = "Corsair Cove"
+ announce_to_ghosts = TRUE
cost = BITRUNNER_COST_MEDIUM
desc = "Battle your way to the hidden treasure, seize the booty, and make a swift escape before the pirates turn the tide."
difficulty = BITRUNNER_DIFFICULTY_MEDIUM
diff --git a/code/modules/bitrunning/virtual_domain/domains/stairs_and_cliffs.dm b/code/modules/bitrunning/virtual_domain/domains/stairs_and_cliffs.dm
index ba18653a2c23..a4b8c87fb955 100644
--- a/code/modules/bitrunning/virtual_domain/domains/stairs_and_cliffs.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/stairs_and_cliffs.dm
@@ -16,11 +16,11 @@
/turf/open/cliff/snowrock/virtual_domain
name = "icy cliff"
- initial_gas_mix = "o2=22;n2=82;TEMP=180"
+ initial_gas_mix = FROZEN_ATMOS
/turf/open/lava/plasma/virtual_domain
name = "plasma lake"
- initial_gas_mix = "o2=22;n2=82;TEMP=180"
+ initial_gas_mix = FROZEN_ATMOS
/datum/outfit/job/virtual_domain_iceclimber
name = "Ice Climber"
diff --git a/code/modules/bitrunning/virtual_domain/domains/syndicate_assault.dm b/code/modules/bitrunning/virtual_domain/domains/syndicate_assault.dm
index 5f754dd433ad..f81bc6daae2c 100644
--- a/code/modules/bitrunning/virtual_domain/domains/syndicate_assault.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/syndicate_assault.dm
@@ -1,5 +1,6 @@
/datum/lazy_template/virtual_domain/syndicate_assault
name = "Syndicate Assault"
+ announce_to_ghosts = TRUE
cost = BITRUNNER_COST_MEDIUM
desc = "Board the enemy ship and recover the stolen cargo."
difficulty = BITRUNNER_DIFFICULTY_MEDIUM
diff --git a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm
index 6db7c3337b6b..469234f08197 100644
--- a/code/modules/bitrunning/virtual_domain/domains/wendigo.dm
+++ b/code/modules/bitrunning/virtual_domain/domains/wendigo.dm
@@ -8,10 +8,10 @@
map_name = "wendigo"
reward_points = BITRUNNER_REWARD_HIGH
-/obj/effect/mob_spawn/corpse/human/bitrunner/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/bitrunner/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.apply_status_effect(/datum/status_effect/gutted)
-/obj/effect/mob_spawn/corpse/human/cyber_police/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/cyber_police/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.apply_status_effect(/datum/status_effect/gutted)
diff --git a/code/modules/bitrunning/virtual_domain/virtual_domain.dm b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
index b147e1514dec..9114c29d0ec7 100644
--- a/code/modules/bitrunning/virtual_domain/virtual_domain.dm
+++ b/code/modules/bitrunning/virtual_domain/virtual_domain.dm
@@ -47,11 +47,18 @@
/// An assoc list of typepath/amount to spawn on completion. Not weighted - the value is the amount
var/list/completion_loot
/// An assoc list of typepath/amount to spawn from secondary objectives. Not weighted - the value is the total number of items that can be obtained.
+ /// An assoc list of typepath/amount to spawn from secondary objectives. Not weighted - the value is the total number of items that can be obtained.
var/list/secondary_loot = list()
/// Number of secondary loot boxes generated. Resets when the domain is reloaded.
var/secondary_loot_generated
/// Has this domain been beaten with high enough score to spawn a tech disk?
var/disk_reward_spawned = FALSE
+ /// The amount of points towards the spawning of the main crate, on maps using points.
+ var/main_crate_points = 0
+ /// The amount of points required to spawn the main crate, on maps using points.
+ var/main_crate_point_goal = 10
+ /// The location the crate will spawn when enough points are accumulated, on maps using points.
+ var/main_crate_loc
/**
* Modularity
@@ -64,10 +71,78 @@
/// Forces all mob modules to only load once
var/modular_unique_mobs = FALSE
+ /**
+ * Spawning
+ */
+
+ /// Looks for random landmarks to spawn on.
+ var/list/custom_spawns = list()
+ /// Set TRUE if you want reusable custom spawners
+ var/keep_custom_spawns = FALSE
+ /// The domain must have this many ghost candidates willing to join as entities, or else it will not load.
+ var/mission_min_candidates = 0
+ /// Maximum amount possible of above.
+ var/mission_max_candidates = 0
+ /// Ghosts that will be spawned as, presumably, an antagonist in the map.
+ var/list/chosen_ghosts
+ /// List of spawners used for candidates.
+ var/list/obj/effect/mob_spawn/ghost_role/ghost_spawners
+ /// Current domain mobs being held by ghosts
+ var/list/mob/living/ghost_mobs
+ /// The role that ghosts will get. Only used for poll text.
+ var/spawner_role = "Antagonist"
+
+ /**
+ * Scorekeeping
+ */
+
+ /// The highest score grade achieved so far
+ var/best_grade = "None"
+
+/datum/lazy_template/virtual_domain/proc/can_view_name(scanner_tier, server_points)
+ return cost <= server_points + 5
+
+/datum/lazy_template/virtual_domain/proc/can_view_reward(scanner_tier, server_points)
+ return difficulty < (scanner_tier + 1) && cost <= server_points + 3
+
+/datum/lazy_template/virtual_domain/Destroy(force)
+ QDEL_NULL(ghost_spawners)
+ QDEL_NULL(ghost_mobs)
+ . = ..()
+
/// Sends a point to any loot signals on the map
-/datum/lazy_template/virtual_domain/proc/add_points(points_to_add)
- SEND_SIGNAL(src, COMSIG_BITRUNNER_GOAL_POINT, points_to_add)
+/datum/lazy_template/virtual_domain/proc/add_points(points_to_add = 1)
+ main_crate_points += points_to_add
+ if(main_crate_points >= main_crate_point_goal)
+ reveal()
+
+/datum/lazy_template/virtual_domain/proc/reveal()
+ if(!main_crate_loc)
+ return
+ var/turf/spawn_loc = get_turf(main_crate_loc)
+ playsound(spawn_loc, 'sound/magic/blink.ogg', 50, TRUE)
+ var/obj/structure/closet/crate/secure/bitrunning/encrypted/crate = new()
+ crate.forceMove(spawn_loc) // Triggers any on-move effects on that turf
+ var/datum/effect_system/spark_spread/quantum/sparks = new
+ sparks.set_up(5, FALSE, spawn_loc)
+ main_crate_loc = null
+
+/// Loads the ghost candidates.
+/datum/lazy_template/virtual_domain/proc/load_advanced_npcs(list/mob/lucky_ghosts)
+ for(var/mob/lucky_ghost as anything in lucky_ghosts)
+ var/obj/effect/mob_spawn/ghost_role/ghost_spawner = pick(ghost_spawners)
+ LAZYREMOVE(ghost_spawners, ghost_spawner)
+
+ var/mob/new_mob = ghost_spawner.create(lucky_ghost, lucky_ghost.real_name)
+ LAZYADD(ghost_mobs, new_mob)
+
+ var/ghostname = lucky_ghost.name
+ notify_ghosts("[ghostname] has been selected to be a [ghost_spawner.prompt_name]!", source = new_mob, header = "001010110")
/// Overridable proc to be called after the map is loaded.
/datum/lazy_template/virtual_domain/proc/setup_domain(list/created_atoms)
return
+
+/datum/lazy_template/virtual_domain/proc/submit_grade(new_grade)
+ if(GLOB.bitrunning_grades.Find(new_grade) > GLOB.bitrunning_grades.Find(best_grade))
+ best_grade = new_grade
diff --git a/code/modules/cargo/bounties/bitrunning.dm b/code/modules/cargo/bounties/bitrunning.dm
new file mode 100644
index 000000000000..301f19f0e412
--- /dev/null
+++ b/code/modules/cargo/bounties/bitrunning.dm
@@ -0,0 +1,48 @@
+/datum/bounty/item/bitrunning/abductor_plush
+ name = "Abductor Plush"
+ description = "Rear Admiral Raynes' child won't stop bothering him for one of those little plush aliens. You can get one from the Abductor Ship domain."
+ reward = CARGO_CRATE_VALUE * 6
+ required_count = 1
+ wanted_types = list(/obj/item/toy/plush/abductor/agent = TRUE)
+
+/datum/bounty/item/bitrunning/bubblegum
+ name = "Bubblegum Plush"
+ description = "Some of the miners have been talking about the breakroom being too sterile. We need something cute to spruce the place up a bit."
+ reward = CARGO_CRATE_VALUE * 10
+ required_count = 1
+ wanted_types = list(/obj/item/toy/plush/bubbleplush = TRUE)
+
+/datum/bounty/item/bitrunning/honk
+ name = "Bike Horn"
+ description = "Bonbon the Clown lost his bike horn when Rear Admiral Raynes hurled him out an airlock for slipping him. Can you get us a replacement?"
+ reward = CARGO_CRATE_VALUE * 4
+ required_count = 1
+ wanted_types = list(/obj/item/bikehorn = TRUE)
+
+/datum/bounty/item/bitrunning/pizzeria
+ name = "Slice of Pizzeria Pizza"
+ description = "Admiral Chivara keeps talking about wanting a slice of pizza from that old pizza joint that closed down. Y'know, the one with the robots."
+ reward = CARGO_CRATE_VALUE * 8
+ required_count = 1
+ wanted_types = list(/obj/item/food/pizzaslice/meat/pizzeria = TRUE)
+
+/datum/bounty/item/bitrunning/psyker
+ name = "Psyker Headset"
+ description = "We're doing some research on psykers and could use some of their equipment. Can you send us one of their headsets if you find it?"
+ reward = CARGO_CRATE_VALUE * 8
+ required_count = 1
+ wanted_types = list(/obj/item/radio/headset/psyker = TRUE)
+
+/datum/bounty/item/bitrunning/polar
+ name = "Polar Ushanka"
+ description = "A bunch of Russians raided one of our outposts and won't leave. They keep swearing at us and demanding we give them vodka and ushankas. Can you send us one?"
+ reward = CARGO_CRATE_VALUE * 3
+ required_count = 1
+ wanted_types = list(/obj/item/clothing/head/costume/ushanka/polar = TRUE)
+
+/datum/bounty/item/bitrunning/syndicate
+ name = "Syndicate Plush"
+ description = "We're aware of some contraband that's made it aboard some of our stations that depict Syndicate agents as cute, marketable plushies. Please send us one so we can further investigate."
+ reward = CARGO_CRATE_VALUE * 8
+ required_count = 1
+ wanted_types = list(/obj/item/toy/plush/nukeplushie = 1)
diff --git a/code/modules/cargo/bounty.dm b/code/modules/cargo/bounty.dm
index aa527e847625..38b26e440273 100644
--- a/code/modules/cargo/bounty.dm
+++ b/code/modules/cargo/bounty.dm
@@ -1,5 +1,5 @@
/// How many jobs have bounties, minus the random civ bounties. PLEASE INCREASE THIS NUMBER AS MORE DEPTS ARE ADDED TO BOUNTIES.
-#define MAXIMUM_BOUNTY_JOBS 13
+#define MAXIMUM_BOUNTY_JOBS 14
/datum/bounty
var/name
@@ -77,6 +77,8 @@
chosen_type = pick(subtypesof(/datum/bounty/item/botany))
if(CIV_JOB_ATMOS)
chosen_type = pick(subtypesof(/datum/bounty/item/atmospherics))
+ if(CIV_JOB_BITRUN)
+ chosen_type = pick(subtypesof(/datum/bounty/item/bitrunning))
bounty_ref = new chosen_type
if(bounty_ref.can_get())
bounty_succeeded = TRUE
diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm
index 232bba1e00c3..bf137549f513 100644
--- a/code/modules/cargo/orderconsole.dm
+++ b/code/modules/cargo/orderconsole.dm
@@ -17,8 +17,6 @@
human remains, classified nuclear weaponry, mail, undelivered departmental order crates, syndicate bombs, \
homing beacons, unstable eigenstates, fax machines, or machinery housing any form of artificial intelligence."
var/blockade_warning = "Bluespace instability detected. Shuttle movement impossible."
- /// radio used by the console to send messages on supply channel
- var/obj/item/radio/headset/radio
/// var that tracks message cooldown
var/message_cooldown
var/list/loaded_coupons
@@ -46,14 +44,6 @@
can_approve_requests = FALSE
requestonly = TRUE
-/obj/machinery/computer/cargo/Initialize(mapload)
- . = ..()
- radio = new /obj/item/radio/headset/headset_cargo(src)
-
-/obj/machinery/computer/cargo/Destroy()
- QDEL_NULL(radio)
- return ..()
-
/obj/machinery/computer/cargo/attacked_by(obj/item/I, mob/living/user)
if(istype(I,/obj/item/trade_chip))
var/obj/item/trade_chip/contract = I
@@ -311,8 +301,7 @@
if(self_paid)
say("Order processed. The price will be charged to [account.account_holder]'s bank account on delivery.")
if(requestonly && message_cooldown < world.time)
- var/message = amount == 1 ? "A new order has been requested." : "[amount] order has been requested."
- radio.talk_into(src, message, RADIO_CHANNEL_SUPPLY)
+ aas_config_announce(/datum/aas_config_entry/cargo_orders_announcement, list("AMOUNT" = amount), src, list(RADIO_CHANNEL_SUPPLY), amount == 1 ? "Single Order" : "Multiple Orders")
message_cooldown = world.time + 30 SECONDS
. = TRUE
@@ -487,3 +476,13 @@
var/datum/signal/status_signal = new(list("command" = command))
frequency.post_signal(src, status_signal)
+
+/datum/aas_config_entry/cargo_orders_announcement
+ name = "Cargo Alert: New Orders"
+ announcement_lines_map = list(
+ "Single Order" = "A new order has been requested.",
+ "Multiple Orders" = "%AMOUNT orders have been requested.",
+ )
+ vars_and_tooltips_map = list(
+ "AMOUNT" = "will be replaced wuth number of orders.",
+ )
diff --git a/code/modules/client/preferences/names.dm b/code/modules/client/preferences/names.dm
index 8456eb9a6270..82d37eca0722 100644
--- a/code/modules/client/preferences/names.dm
+++ b/code/modules/client/preferences/names.dm
@@ -17,21 +17,26 @@
/// If the highest priority job matches this, will prioritize this name in the UI
var/relevant_job
+
/datum/preference/name/apply_to_human(mob/living/carbon/human/target, value)
// Only real_name applies directly, everything else is applied by something else
return
+
/datum/preference/name/deserialize(input, datum/preferences/preferences)
return reject_bad_name("[input]", allow_numbers)
+
/datum/preference/name/serialize(input)
// `is_valid` should always be run before `serialize`, so it should not
// be possible for this to return `null`.
return reject_bad_name(input, allow_numbers)
+
/datum/preference/name/is_valid(value)
return istext(value) && !isnull(reject_bad_name(value, allow_numbers))
+
/// A character's real name
/datum/preference/name/real_name
explanation = "Name"
@@ -181,8 +186,21 @@
explanation = "Hacker alias"
group = "bitrunning"
savefile_key = "hacker_alias"
- allow_numbers = TRUE
relevant_job = /datum/job/bitrunner
+
/datum/preference/name/hacker_alias/create_default_value()
return pick(GLOB.hacker_aliases)
+
+
+/datum/preference/name/hacker_alias/is_valid(value)
+ return !isnull(permissive_sanitize_name(value))
+
+
+/datum/preference/name/hacker_alias/deserialize(input, datum/preferences/preferences)
+ return permissive_sanitize_name(input)
+
+
+/datum/preference/name/hacker_alias/serialize(input)
+ return permissive_sanitize_name(input)
+
diff --git a/code/modules/clothing/chameleon/chameleon_action_subtypes.dm b/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
index 705d3a77b39f..46cb20f296b3 100644
--- a/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
+++ b/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
@@ -302,3 +302,7 @@
. = ..()
for(var/other_type in other_cham_types)
add_chameleon_items(other_type)
+
+/datum/action/item_action/chameleon/change/gun/ballistic
+ chameleon_type = /obj/item/gun/ballistic
+ chameleon_name = "Gun"
diff --git a/code/modules/clothing/chameleon/chameleon_gun.dm b/code/modules/clothing/chameleon/chameleon_gun.dm
index bf5af8e4d5fa..efb5913d571b 100644
--- a/code/modules/clothing/chameleon/chameleon_gun.dm
+++ b/code/modules/clothing/chameleon/chameleon_gun.dm
@@ -11,6 +11,8 @@
/// The badmin mode. Makes your projectiles act like the real deal.
var/real_hits = FALSE
+ /// how it looks by default.
+ var/default_look = /obj/item/gun/energy/laser
/obj/item/gun/energy/laser/chameleon/Initialize(mapload)
. = ..()
@@ -18,7 +20,7 @@
AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS|EMP_NO_EXAMINE)
// Init order shenanigans dictate we have to do this last so we can't just use `active_type`
var/datum/action/item_action/chameleon/change/gun/gun_action = locate() in actions
- gun_action?.update_look(/obj/item/gun/energy/laser)
+ gun_action?.update_look(default_look)
/**
* Description: Resets the currently loaded chameleon variables, essentially resetting it to brand new.
@@ -54,36 +56,34 @@
inhand_x_dimension = gun_to_set.inhand_x_dimension
inhand_y_dimension = gun_to_set.inhand_y_dimension
+ // We dupe this casing and then delete it at the end, to grab the projectile.
+ var/obj/item/ammo_casing/casing_to_dupe
+
if(istype(gun_to_set, /obj/item/gun/ballistic))
var/obj/item/gun/ballistic/ball_gun = gun_to_set
- var/obj/item/ammo_box/ball_ammo = new ball_gun.spawn_magazine_type(gun_to_set)
- qdel(ball_gun)
-
- if(!istype(ball_ammo) || !ball_ammo.ammo_type)
- qdel(ball_ammo)
- return FALSE
-
- var/obj/item/ammo_casing/ball_cartridge = new ball_ammo.ammo_type(gun_to_set)
- set_chameleon_ammo(ball_cartridge)
+ // We also need to copy the starting magazine for ballistics.
+ casing_to_dupe = initial(ball_gun.spawn_magazine_type.ammo_type)
+ casing_to_dupe = new casing_to_dupe(src)
else if(istype(gun_to_set, /obj/item/gun/magic))
var/obj/item/gun/magic/magic_gun = gun_to_set
- var/obj/item/ammo_casing/magic_cartridge = new magic_gun.ammo_type(gun_to_set)
- set_chameleon_ammo(magic_cartridge)
+ casing_to_dupe = new magic_gun.ammo_type(src)
else if(istype(gun_to_set, /obj/item/gun/energy))
var/obj/item/gun/energy/energy_gun = gun_to_set
+ // Even if the energy gun has multiple ammo types, we copy the first. Energy guns always (should) have a list in ammo_type.
if(islist(energy_gun.ammo_type) && energy_gun.ammo_type.len)
- var/obj/item/ammo_casing/energy_cartridge = energy_gun.ammo_type[1]
- set_chameleon_ammo(energy_cartridge)
+ var/obj/item/first_casing = energy_gun.ammo_type[1]
+ casing_to_dupe = new first_casing.type(src)
else if(istype(gun_to_set, /obj/item/gun/syringe))
- var/obj/item/ammo_casing/syringe_cartridge = new /obj/item/ammo_casing/syringegun(src)
- set_chameleon_ammo(syringe_cartridge)
+ casing_to_dupe = new /obj/item/ammo_casing/syringegun(src)
else
- var/obj/item/ammo_casing/default_cartridge = new /obj/item/ammo_casing(src)
- set_chameleon_ammo(default_cartridge)
+ casing_to_dupe = new /obj/item/ammo_casing(src)
+
+ set_chameleon_ammo(casing_to_dupe)
+ qdel(casing_to_dupe)
/**
* Description: Sets the ammo type our gun should have.
@@ -155,3 +155,11 @@
var/obj/item/gun/new_gun = new guntype(src)
set_chameleon_gun(new_gun)
qdel(new_gun)
+
+/obj/item/gun/energy/laser/chameleon/ballistic_only
+ actions_types = list(/datum/action/item_action/chameleon/change/gun/ballistic)
+ default_look = /obj/item/gun/ballistic/automatic/mini_uzi
+
+/obj/item/gun/energy/laser/chameleon/ballistic_only/Initialize(mapload)
+ . = ..()
+ set_chameleon_disguise(default_look)
diff --git a/code/modules/events/immovable_rod/immovable_rod.dm b/code/modules/events/immovable_rod/immovable_rod.dm
index ace1093d2428..ad0c9715ed2b 100644
--- a/code/modules/events/immovable_rod/immovable_rod.dm
+++ b/code/modules/events/immovable_rod/immovable_rod.dm
@@ -76,11 +76,6 @@
if(istype(ghost))
ghost.ManualFollow(src)
-/obj/effect/immovablerod/proc/on_entered_over_movable(datum/source, atom/movable/atom_crossed_over)
- SIGNAL_HANDLER
- if((atom_crossed_over.density || isliving(atom_crossed_over)) && !QDELETED(atom_crossed_over))
- Bump(atom_crossed_over)
-
/obj/effect/immovablerod/proc/on_entering_atom(datum/source, atom/destination, atom/old_loc, list/atom/old_locs)
SIGNAL_HANDLER
if(destination.density && isturf(destination))
diff --git a/code/modules/jobs/job_types/_job.dm b/code/modules/jobs/job_types/_job.dm
index 0fd1e1f27fcc..60f919e724cc 100644
--- a/code/modules/jobs/job_types/_job.dm
+++ b/code/modules/jobs/job_types/_job.dm
@@ -269,9 +269,8 @@
var/datum/record/crew/crew_rec = find_record(H.real_name)
var/obj/item/card/id/crew_id = H.get_idcard(hand_first = FALSE)
var/job_name = crew_rec?.rank || crew_id?.assignment || crew_id?.trim?.assignment || H.job
- var/datum/callback/announce = CALLBACK(pick(GLOB.announcement_systems), TYPE_PROC_REF(/obj/machinery/announcement_system, announce), "NEWHEAD", H.real_name, job_name, channels)
//timer because these should come after the captain announcement
- SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), announce, 0.1 SECONDS))
+ SSticker.OnRoundstart(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(_addtimer), CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(aas_config_announce), /datum/aas_config_entry/newhead, list("PERSON" = H.real_name, "RANK" = job_name), null, channels, null, TRUE), 1))
//If the configuration option is set to require players to be logged as old enough to play certain jobs, then this proc checks that they are, otherwise it just returns 1
/datum/job/proc/player_old_enough(client/player)
diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm
index a506c1485f58..b74fac87ecb1 100644
--- a/code/modules/jobs/job_types/security_officer.dm
+++ b/code/modules/jobs/job_types/security_officer.dm
@@ -169,11 +169,14 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
department,
distribution,
)
- var/obj/machinery/announcement_system/announcement_system = pick(GLOB.announcement_systems)
+ var/obj/machinery/announcement_system/announcement_system = get_announcement_system(/datum/aas_config_entry/announce_officer)
if (isnull(announcement_system))
return
- announcement_system.announce_officer(officer, department)
+ announcement_system.announce(/datum/aas_config_entry/announce_officer, list(
+ "OFFICER" = officer.real_name,
+ "DEPARTMENT" = department,
+ ), list(RADIO_CHANNEL_SECURITY))
var/list/targets = list()
@@ -194,10 +197,14 @@ GLOBAL_LIST_EMPTY(security_officer_distribution)
if (!targets.len)
return
+ // I thought it would be great, if AAS also modifies PDA messages. Especially because it's AASs message.
var/datum/signal/subspace/messaging/tablet_message/signal = new(announcement_system, list(
"fakename" = "Security Department Update",
"fakejob" = "Automated Announcement System",
- "message" = "Officer [officer.real_name] has been assigned to your department, [department].",
+ "message" = announcement_system.compile_config_message(/datum/aas_config_entry/announce_officer, list(
+ "OFFICER" = officer.real_name,
+ "DEPARTMENT" = department,
+ )),
"targets" = targets,
"automated" = TRUE,
))
diff --git a/code/modules/mapfluff/ruins/icemoonruin_code/mining_site.dm b/code/modules/mapfluff/ruins/icemoonruin_code/mining_site.dm
index 8a37031b8184..7c1e4f7ddf2a 100644
--- a/code/modules/mapfluff/ruins/icemoonruin_code/mining_site.dm
+++ b/code/modules/mapfluff/ruins/icemoonruin_code/mining_site.dm
@@ -27,7 +27,7 @@
icon_state = "corpseminer"
// Gives the minesite corpses the gutted effect so that the boss ignores them
-/obj/effect/mob_spawn/corpse/human/minesite/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/minesite/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.apply_status_effect(/datum/status_effect/gutted)
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm b/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm
index 43393b28d344..ae8a10f8217e 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/anomalyresearch.dm
@@ -75,7 +75,7 @@
icon = 'icons/area/areas_ruins.dmi'
icon_state = "anomaly_research"
requires_power = FALSE
- area_flags = HIDDEN_AREA | UNIQUE_AREA
+ area_flags = HIDDEN_AREA
has_gravity = TRUE
/obj/item/reagent_containers/cup/bottle/wittel
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/forgottenship.dm b/code/modules/mapfluff/ruins/spaceruin_code/forgottenship.dm
index 6522fad5b29a..f3cef4a5cfd5 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/forgottenship.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/forgottenship.dm
@@ -133,4 +133,4 @@ GLOBAL_VAR_INIT(fscpassword, generate_password())
name = "Syndicate Forgotten Vault"
icon_state = "syndie-ship"
ambientsounds = list('sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg')
- area_flags = NOTELEPORT | UNIQUE_AREA
+ area_flags = NOTELEPORT
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
index 0693cc1cdc4f..cd8ed00928a3 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/hilbertshotel.dm
@@ -392,6 +392,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
requires_power = FALSE
has_gravity = TRUE
area_flags = NOTELEPORT | HIDDEN_AREA
+ area_flags_mapping = NONE
static_lighting = TRUE
ambientsounds = list('sound/ambience/servicebell.ogg')
var/roomnumber = 0
@@ -480,7 +481,8 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
icon = 'icons/area/areas_ruins.dmi'
icon_state = "hilbertshotel"
requires_power = FALSE
- area_flags = HIDDEN_AREA | NOTELEPORT | UNIQUE_AREA
+ area_flags = HIDDEN_AREA | NOTELEPORT
+ area_flags_mapping = UNIQUE_AREA
has_gravity = TRUE
/obj/item/abstracthotelstorage
@@ -514,7 +516,7 @@ GLOBAL_VAR_INIT(hhMysteryRoomNumber, rand(1, 999999))
name = "Hilbert Research Facility"
/area/ruin/space/has_grav/powered/hilbertresearchfacility/secretroom
- area_flags = UNIQUE_AREA | NOTELEPORT | HIDDEN_AREA
+ area_flags = NOTELEPORT | HIDDEN_AREA
/obj/item/analyzer/hilbertsanalyzer
name = "custom rigged analyzer"
diff --git a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
index 15e644cd1392..f127f4467c9c 100644
--- a/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
+++ b/code/modules/mapfluff/ruins/spaceruin_code/meateor.dm
@@ -11,7 +11,7 @@
/// Tiger cultist corpse but with an exit wound
/obj/effect/mob_spawn/corpse/human/tigercultist/perforated
-/obj/effect/mob_spawn/corpse/human/tigercultist/perforated/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/tigercultist/perforated/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
var/obj/item/bodypart/chest/their_chest = spawned_human.get_bodypart(BODY_ZONE_CHEST)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index f47d2cfd938b..d8a74804ec77 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -5,7 +5,7 @@
static_lighting = TRUE
requires_power = FALSE
has_gravity = STANDARD_GRAVITY
- area_flags = BLOBS_ALLOWED | UNIQUE_AREA
+ area_flags = BLOBS_ALLOWED
flags_1 = CAN_BE_DIRTY_1
//Survival Capsule
diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm
index d578116e6b95..d63c59c3b735 100644
--- a/code/modules/mining/laborcamp/laborstacker.dm
+++ b/code/modules/mining/laborcamp/laborstacker.dm
@@ -10,13 +10,11 @@ GLOBAL_LIST(labor_sheet_values)
density = FALSE
/// Connected stacking machine
var/obj/machinery/mineral/stacking_machine/laborstacker/stacking_machine
- /// Needed to send messages to sec radio
- var/obj/item/radio/security_radio
+ /// Cooldown for console says.
+ COOLDOWN_DECLARE(say_cooldown)
/obj/machinery/mineral/labor_claim_console/Initialize(mapload)
. = ..()
- security_radio = new /obj/item/radio(src)
- security_radio.set_listening(FALSE)
locate_stacking_machine()
//If we can't find a stacking machine end it all ok?
if(!stacking_machine)
@@ -31,7 +29,6 @@ GLOBAL_LIST(labor_sheet_values)
GLOB.labor_sheet_values = sort_list(sheet_list, GLOBAL_PROC_REF(cmp_sheet_list))
/obj/machinery/mineral/labor_claim_console/Destroy()
- QDEL_NULL(security_radio)
if(stacking_machine)
stacking_machine.labor_console = null
stacking_machine = null
@@ -118,8 +115,7 @@ GLOBAL_LIST(labor_sheet_values)
to_chat(user_mob, span_alert("No permission to dock could be granted."))
else
if(!(obj_flags & EMAGGED))
- security_radio.set_frequency(FREQ_SECURITY)
- security_radio.talk_into(src, "A prisoner has returned to the station. Minerals and Prisoner ID card ready for retrieval.", FREQ_SECURITY)
+ aas_config_announce(/datum/aas_config_entry/security_labor_stacker, list("PERSON" = user_mob.real_name), src, list(RADIO_CHANNEL_SECURITY))
user_mob.log_message("has completed their labor points goal and is now sending the gulag shuttle back to the station.", LOG_GAME)
to_chat(user_mob, span_notice("Shuttle received message and will be sent shortly."))
return TRUE
@@ -190,3 +186,12 @@ GLOBAL_LIST(labor_sheet_values)
say("ID: [prisoner_id.registered_name].")
say("Points Collected: [prisoner_id.points] / [prisoner_id.goal].")
say("Collect points by bringing smelted minerals to the Labor Shuttle stacking machine. Reach your quota to earn your release.")
+
+/datum/aas_config_entry/security_labor_stacker
+ name = "Security Alert: Labor Camp Release"
+ announcement_lines_map = list(
+ "Message" = "%PERSON returned to the station. Minerals and Prisoner ID card ready for retrieval."
+ )
+ vars_and_tooltips_map = list(
+ "PERSON" = "will be replaced with the name of the prisoner."
+ )
diff --git a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm
index 93045bf476b8..24efa68639ed 100644
--- a/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm
+++ b/code/modules/mob/living/basic/icemoon/ice_demon/ice_demon.dm
@@ -80,7 +80,7 @@
/mob/living/basic/mining/demon_afterimage/Initialize(mapload)
. = ..()
AddElement(/datum/element/simple_flying)
- AddElement(/datum/element/temporary_atom, life_time = existence_period)
+ fade_into_nothing(life_time = existence_period)
///afterimage subtypes summoned by the crusher
/mob/living/basic/mining/demon_afterimage/crusher
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index a82d3b89f4d7..038136e7fd73 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -160,24 +160,17 @@
/obj/item/organ/brain/primate/on_mob_insert(mob/living/carbon/primate)
. = ..()
- RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed), TRUE)
+ RegisterSignal(primate, COMSIG_LIVING_MOB_BUMPED, PROC_REF(on_mob_bump))
/obj/item/organ/brain/primate/on_mob_remove(mob/living/carbon/primate)
. = ..()
- UnregisterSignal(primate, COMSIG_MOVABLE_CROSS)
+ UnregisterSignal(primate, COMSIG_LIVING_MOB_BUMPED)
-/obj/item/organ/brain/primate/proc/on_crossed(datum/source, atom/movable/crossed)
+/obj/item/organ/brain/primate/proc/on_mob_bump(mob/source, mob/living/crossing_mob)
SIGNAL_HANDLER
- if(!tripping)
+ if(!tripping || !crossing_mob.combat_mode)
return
- if(IS_DEAD_OR_INCAP(owner) || !isliving(crossed))
- return
- var/mob/living/in_the_way_mob = crossed
- if(iscarbon(in_the_way_mob) && !in_the_way_mob.combat_mode)
- return
- if(in_the_way_mob.pass_flags & PASSTABLE)
- return
- in_the_way_mob.knockOver(owner)
+ crossing_mob.knockOver(owner)
/obj/item/organ/brain/primate/get_attacking_limb(mob/living/carbon/human/target)
return owner.get_bodypart(BODY_ZONE_HEAD)
diff --git a/code/modules/mob/living/living.dm b/code/modules/mob/living/living.dm
index 68d0d03e8169..c8a2f5f931e8 100644
--- a/code/modules/mob/living/living.dm
+++ b/code/modules/mob/living/living.dm
@@ -178,6 +178,7 @@
return TRUE
SEND_SIGNAL(src, COMSIG_LIVING_MOB_BUMP, M)
+ SEND_SIGNAL(M, COMSIG_LIVING_MOB_BUMPED, src)
//Even if we don't push/swap places, we "touched" them, so spread fire
spreadFire(M)
diff --git a/code/modules/mob/living/silicon/ai/multicam.dm b/code/modules/mob/living/silicon/ai/multicam.dm
index 1f001a4bf054..84703e0c6c60 100644
--- a/code/modules/mob/living/silicon/ai/multicam.dm
+++ b/code/modules/mob/living/silicon/ai/multicam.dm
@@ -103,7 +103,7 @@
static_lighting = FALSE
base_lighting_alpha = 255
- area_flags = NOTELEPORT | HIDDEN_AREA | UNIQUE_AREA
+ area_flags = NOTELEPORT | HIDDEN_AREA
ambientsounds = null
flags_1 = NONE
diff --git a/code/modules/mob_spawn/corpses/job_corpses.dm b/code/modules/mob_spawn/corpses/job_corpses.dm
index 1b950e0f6137..b0014424037b 100644
--- a/code/modules/mob_spawn/corpses/job_corpses.dm
+++ b/code/modules/mob_spawn/corpses/job_corpses.dm
@@ -59,15 +59,15 @@
outfit = /datum/outfit/job/assistant
icon_state = "corpsegreytider"
-/obj/effect/mob_spawn/corpse/human/assistant/beesease_infection/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/assistant/beesease_infection/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.ForceContractDisease(new /datum/disease/beesease)
-/obj/effect/mob_spawn/corpse/human/assistant/brainrot_infection/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/assistant/brainrot_infection/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.ForceContractDisease(new /datum/disease/brainrot)
-/obj/effect/mob_spawn/corpse/human/assistant/spanishflu_infection/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/human/assistant/spanishflu_infection/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.ForceContractDisease(new /datum/disease/fluspanish)
diff --git a/code/modules/mob_spawn/corpses/mining_corpses.dm b/code/modules/mob_spawn/corpses/mining_corpses.dm
index 98070267810a..add04088198d 100644
--- a/code/modules/mob_spawn/corpses/mining_corpses.dm
+++ b/code/modules/mob_spawn/corpses/mining_corpses.dm
@@ -8,7 +8,7 @@
burn_damage = 1000
mob_species = /datum/species/skeleton
-/obj/effect/mob_spawn/corpse/human/charredskeleton/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/charredskeleton/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.color = "#454545"
spawned_human.gender = NEUTER
@@ -24,7 +24,7 @@
outfit = select_outfit()
return ..()
-/obj/effect/mob_spawn/corpse/human/legioninfested/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/legioninfested/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
var/obj/item/organ/legion_tumour/cancer = new()
cancer.Insert(spawned_human, special = TRUE, movement_flags = DELETE_IF_REPLACED)
@@ -65,7 +65,7 @@
/// Corpse spawner used by dwarf legions to make small corpses
/obj/effect/mob_spawn/corpse/human/legioninfested/dwarf
-/obj/effect/mob_spawn/corpse/human/legioninfested/dwarf/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/legioninfested/dwarf/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.dna.add_mutation(/datum/mutation/human/dwarfism)
@@ -113,7 +113,7 @@
/obj/effect/mob_spawn/corpse/human/legioninfested/skeleton/select_outfit()
return null
-/obj/effect/mob_spawn/corpse/human/legioninfested/skeleton/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/legioninfested/skeleton/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.gender = NEUTER
@@ -124,7 +124,7 @@
brute_damage = 0
burn_damage = 1000
-/obj/effect/mob_spawn/corpse/human/legioninfested/skeleton/charred/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/legioninfested/skeleton/charred/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.color = "#454545"
diff --git a/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm b/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
index 0ed30e5a5215..c546173f5565 100644
--- a/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
+++ b/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
@@ -54,7 +54,7 @@
outfit = /datum/outfit/centcom/centcom_intern/unarmed
mob_name = "Nameless Intern"
-/obj/effect/mob_spawn/corpse/human/intern/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/corpse/human/intern/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.gender = MALE //we're making it canon babies
spawned_human.update_body()
diff --git a/code/modules/mob_spawn/corpses/nonhuman_corpses.dm b/code/modules/mob_spawn/corpses/nonhuman_corpses.dm
index 3a63a246035e..e33679017084 100644
--- a/code/modules/mob_spawn/corpses/nonhuman_corpses.dm
+++ b/code/modules/mob_spawn/corpses/nonhuman_corpses.dm
@@ -11,7 +11,7 @@
return
. = ..()
-/obj/effect/mob_spawn/corpse/ai/special(mob/living/silicon/ai/spawned/dead_ai)
+/obj/effect/mob_spawn/corpse/ai/special(mob/living/silicon/ai/spawned/dead_ai, mob/mob_possessor)
. = ..()
dead_ai.name = src.name
dead_ai.real_name = src.name
@@ -24,7 +24,7 @@
///the color of the slime you're spawning.
var/slime_species = /datum/slime_type/grey
-/obj/effect/mob_spawn/corpse/slime/special(mob/living/simple_animal/slime/spawned_slime)
+/obj/effect/mob_spawn/corpse/slime/special(mob/living/simple_animal/slime/spawned_slime, mob/mob_possessor)
. = ..()
spawned_slime.set_slime_type(slime_species)
diff --git a/code/modules/mob_spawn/ghost_roles/away_roles.dm b/code/modules/mob_spawn/ghost_roles/away_roles.dm
index 4891cf1e0089..386e30ea88dc 100644
--- a/code/modules/mob_spawn/ghost_roles/away_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/away_roles.dm
@@ -14,7 +14,7 @@
flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path."
spawner_job_path = /datum/job/skeleton
-/obj/effect/mob_spawn/ghost_role/human/skeleton/special(mob/living/new_spawn)
+/obj/effect/mob_spawn/ghost_role/human/skeleton/special(mob/living/new_spawn, mob/mob_possessor)
. = ..()
to_chat(new_spawn, "You have this horrible lurching feeling deep down that your binding to this world will fail if you abandon this zone... Were you reanimated to protect something?")
new_spawn.AddComponent(/datum/component/stationstuck, PUNISHMENT_MURDER, "You experience a feeling like a stressed twine being pulled until it snaps. Then, merciful nothing.")
@@ -30,7 +30,7 @@
you_are_text = "By unknown powers, your rotting remains have been resurrected!"
flavour_text = "Walk this mortal plane and terrorize all living adventurers who dare cross your path."
-/obj/effect/mob_spawn/ghost_role/human/zombie/special(mob/living/new_spawn)
+/obj/effect/mob_spawn/ghost_role/human/zombie/special(mob/living/new_spawn, mob/mob_possessor)
. = ..()
to_chat(new_spawn, "You have this horrible lurching feeling deep down that your binding to this world will fail if you abandon this zone... Were you reanimated to protect something?")
new_spawn.AddComponent(/datum/component/stationstuck, PUNISHMENT_MURDER, "You experience a feeling like a stressed twine being pulled until it snaps. Then, merciful nothing.")
diff --git a/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm b/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm
index 5b9e043349ea..4e32c9359349 100644
--- a/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/fugitive_hunter_roles.dm
@@ -7,7 +7,7 @@
show_flavor = FALSE
var/back_story = "error"
-/obj/effect/mob_spawn/ghost_role/human/fugitive/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/ghost_role/human/fugitive/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
var/datum/antagonist/fugitive_hunter/fughunter = new
fughunter.backstory = back_story
diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
index 53fa00109703..cf8b1474eae0 100644
--- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm
@@ -233,7 +233,7 @@
to_chat(user, span_warning("You have exhausted your usefulness to the Necropolis."))
return FALSE
-/obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/ghost_role/human/ash_walker/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.fully_replace_character_name(null, spawned_human.generate_random_mob_name(TRUE))
to_chat(spawned_human, "Drag the corpses of men and beasts to your nest. It will absorb them to create more of your kind. Invade the strange structure of the outsiders if you must. Do not cause unnecessary destruction, as littering the wastes with ugly wreckage is certain to not gain you favor. Glory to the Necropolis!")
@@ -284,7 +284,7 @@
outfit = /datum/outfit/lavaland_syndicate
spawner_job_path = /datum/job/lavaland_syndicate
-/obj/effect/mob_spawn/ghost_role/human/lavaland_syndicate/special(mob/living/new_spawn)
+/obj/effect/mob_spawn/ghost_role/human/lavaland_syndicate/special(mob/living/new_spawn, mob/mob_possessor)
. = ..()
new_spawn.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
diff --git a/code/modules/mob_spawn/ghost_roles/unused_roles.dm b/code/modules/mob_spawn/ghost_roles/unused_roles.dm
index 4ca259fa47c3..3fc87f4c572c 100644
--- a/code/modules/mob_spawn/ghost_roles/unused_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/unused_roles.dm
@@ -24,7 +24,7 @@
new /obj/structure/fluff/empty_sleeper/syndicate(get_turf(src))
return ..()
-/obj/effect/mob_spawn/ghost_role/human/prisoner_transport/special(mob/living/carbon/human/spawned_human)
+/obj/effect/mob_spawn/ghost_role/human/prisoner_transport/special(mob/living/carbon/human/spawned_human, mob/mob_possessor)
. = ..()
spawned_human.fully_replace_character_name(null, "NTP #LL-0[rand(111,999)]") //Nanotrasen Prisoner #Lavaland-(numbers)
@@ -153,7 +153,7 @@
new/obj/structure/fluff/empty_sleeper(get_turf(src))
return ..()
-/obj/effect/mob_spawn/ghost_role/human/exile/special(mob/living/new_spawn)
+/obj/effect/mob_spawn/ghost_role/human/exile/special(mob/living/new_spawn, mob/mob_possessor)
. = ..()
new_spawn.fully_replace_character_name(null,"Wish Granter's Victim ([rand(1,999)])")
var/wish = rand(1,4)
@@ -227,7 +227,7 @@
icon = 'icons/obj/machines/sleeper.dmi'
icon_state = "sleeper"
-/obj/effect/mob_spawn/cow/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/cow/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
gender = FEMALE
@@ -270,7 +270,7 @@
outfit = /datum/outfit/syndicatespace/syndicrew
spawner_job_path = /datum/job/syndicate_cybersun
-/obj/effect/mob_spawn/ghost_role/human/syndicatespace/special(mob/living/new_spawn)
+/obj/effect/mob_spawn/ghost_role/human/syndicatespace/special(mob/living/new_spawn, mob/mob_possessor)
. = ..()
new_spawn.grant_language(/datum/language/codespeak, source = LANGUAGE_MIND)
var/datum/job/spawn_job = SSjob.get_job_type(spawner_job_path)
diff --git a/code/modules/mob_spawn/mob_spawn.dm b/code/modules/mob_spawn/mob_spawn.dm
index b94499907570..15e40bfa777e 100644
--- a/code/modules/mob_spawn/mob_spawn.dm
+++ b/code/modules/mob_spawn/mob_spawn.dm
@@ -53,7 +53,7 @@
spawned_mob_ref = WEAKREF(spawned_mob)
return spawned_mob
-/obj/effect/mob_spawn/proc/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/proc/special(mob/living/spawned_mob, mob/mob_possessor)
SHOULD_CALL_PARENT(TRUE)
if(faction)
spawned_mob.faction = faction
@@ -296,7 +296,7 @@
if(mapload || (SSticker && SSticker.current_state > GAME_STATE_SETTING_UP))
INVOKE_ASYNC(src, PROC_REF(create))
-/obj/effect/mob_spawn/corpse/special(mob/living/spawned_mob)
+/obj/effect/mob_spawn/corpse/special(mob/living/spawned_mob, mob/mob_possessor)
. = ..()
spawned_mob.death(TRUE)
spawned_mob.adjustOxyLoss(oxy_damage)
diff --git a/code/modules/modular_computers/file_system/programs/dept_order.dm b/code/modules/modular_computers/file_system/programs/dept_order.dm
index 951dcbae6d3b..bf264e48b3ae 100644
--- a/code/modules/modular_computers/file_system/programs/dept_order.dm
+++ b/code/modules/modular_computers/file_system/programs/dept_order.dm
@@ -29,18 +29,16 @@
)
/// Reference to the order we've made UNTIL it gets sent on the supply shuttle. this is so heads can cancel it
VAR_PRIVATE/datum/supply_order/department_order
- /// Our radio object we use to talk to our department.
- VAR_PRIVATE/obj/item/radio/radio
/// The radio channel we will speak into by default.
VAR_PRIVATE/radio_channel
- /// Maps what department gets what encryption key
+ /// Maps what department should report to what radio channel
/// I could've put this on the job department datum but it felt unnecessary
- VAR_PRIVATE/static/list/dept_to_radio = list(
- /datum/job_department/engineering = /obj/item/encryptionkey/headset_eng,
- /datum/job_department/medical = /obj/item/encryptionkey/headset_med,
- /datum/job_department/science = /obj/item/encryptionkey/headset_sci,
- /datum/job_department/security = /obj/item/encryptionkey/headset_sec,
- /datum/job_department/service = /obj/item/encryptionkey/headset_service,
+ VAR_PRIVATE/static/list/dept_to_radio_channel = list(
+ /datum/job_department/engineering = RADIO_CHANNEL_ENGINEERING,
+ /datum/job_department/medical = RADIO_CHANNEL_MEDICAL,
+ /datum/job_department/science = RADIO_CHANNEL_SCIENCE,
+ /datum/job_department/security = RADIO_CHANNEL_SECURITY,
+ /datum/job_department/service = RADIO_CHANNEL_SERVICE,
)
/// Sets the passed department type as the active department for this computer file.
@@ -53,22 +51,10 @@
use_access |= linked_department_real.head_of_staff_access
use_access |= linked_department_real.department_access
// Also set up the radio
- if(dept_to_radio[linked_department])
- if(!isnull(radio))
- QDEL_NULL(radio)
- var/picked_key = dept_to_radio[linked_department] || /obj/item/encryptionkey/headset_cargo
- radio = new(computer)
- radio.keyslot = new picked_key()
- radio.subspace_transmission = TRUE
- radio.canhear_range = 0
- radio.recalculateChannels()
- radio_channel = radio.keyslot.channels[1]
+ if(dept_to_radio_channel[linked_department])
+ radio_channel = dept_to_radio_channel[linked_department] || RADIO_CHANNEL_SUPPLY
computer.update_static_data_for_all_viewers()
-/datum/computer_file/program/department_order/Destroy()
- QDEL_NULL(radio)
- return ..()
-
/datum/computer_file/program/department_order/ui_interact(mob/user, datum/tgui/ui)
check_cooldown()
@@ -242,6 +228,9 @@
SSshuttle.shopping_list += department_order
if(!already_signalled)
RegisterSignal(SSshuttle, COMSIG_SUPPLY_SHUTTLE_BUY, PROC_REF(finalize_department_order))
+ if(!alert_silenced && alert_able)
+ aas_config_announce(/datum/aas_config_entry/department_orders, list("ORDER" = pack.name, "PERSON" = name), computer.physical, list(radio_channel), "Order Placed")
+ aas_config_announce(/datum/aas_config_entry/department_orders_cargo, list("DEPARTMENT" = linked_department.department_name), computer.physical, list(RADIO_CHANNEL_SUPPLY))
computer.physical.say("Order processed. Cargo will deliver the crate when it comes in on their shuttle. NOTICE: Heads of staff may override the order.")
calculate_cooldown(pack.cost)
@@ -265,7 +254,7 @@
/datum/computer_file/program/department_order/process_tick(seconds_per_tick)
if(!check_cooldown() || alert_silenced || !alert_able)
return
- radio?.talk_into(computer, "Order cooldown has expired! A new order may now be placed!", radio_channel)
+ aas_config_announce(/datum/aas_config_entry/department_orders, list(), computer.physical, list(radio_channel), "Cooldown Reset")
computer.alert_call(src, "Order cooldown expired!", 'sound/machines/ping.ogg')
/// Checks if the cooldown is up and resets it if so.
@@ -274,3 +263,23 @@
department_cooldowns[linked_department] = 0
return TRUE
return FALSE
+
+/datum/aas_config_entry/department_orders
+ name = "Departmental Order Announcement"
+ announcement_lines_map = list(
+ "Order Placed" = "A department order has been placed by %PERSON for %ORDER.",
+ "Cooldown Reset" = "Department order cooldown has expired! A new order may now be placed!",
+ )
+ vars_and_tooltips_map = list(
+ "ORDER" = "will be replaced with the package name",
+ "PERSON" = "with the orderer's name",
+ )
+
+/datum/aas_config_entry/department_orders_cargo
+ name = "Cargo Alert: New Departmental Order"
+ announcement_lines_map = list(
+ "Message" = "New %DEPARTMENT departmental order has been placed"
+ )
+ vars_and_tooltips_map = list(
+ "DEPARTMENT" = "will be replaced with orderer's department."
+ )
diff --git a/code/modules/modular_computers/file_system/programs/nt_pay.dm b/code/modules/modular_computers/file_system/programs/nt_pay.dm
index 4e3fa5d3fb71..ba4b638598a2 100644
--- a/code/modules/modular_computers/file_system/programs/nt_pay.dm
+++ b/code/modules/modular_computers/file_system/programs/nt_pay.dm
@@ -60,6 +60,11 @@
SEND_SIGNAL(computer, COMSIG_MODULAR_COMPUTER_NT_PAY_RESULT, payment_result)
/datum/computer_file/program/nt_pay/proc/_pay(token, money_to_send, mob/user)
+ var/area/user_area = get_area(user)
+ if(user_area && is_area_virtual(user_area))
+ to_chat(user, span_notice("You cannot send virtual money to real accounts."))
+ return NT_PAY_STATUS_NO_ACCOUNT
+
money_to_send = round(money_to_send)
if(IS_DEPARTMENTAL_ACCOUNT(current_user))
diff --git a/code/modules/modular_computers/file_system/programs/virtual_pet.dm b/code/modules/modular_computers/file_system/programs/virtual_pet.dm
index c4016e1e5625..35d80d3ce28c 100644
--- a/code/modules/modular_computers/file_system/programs/virtual_pet.dm
+++ b/code/modules/modular_computers/file_system/programs/virtual_pet.dm
@@ -535,7 +535,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list)
announce_global_updates(message = "has found a chocolate at [selected_area.name]")
selected_area = null
var/obj/item/food/virtual_chocolate/chocolate = new(get_turf(computer))
- chocolate.AddElement(/datum/element/temporary_atom, life_time = 30 SECONDS) //we cant maintain its existence for too long!
+ chocolate.fade_into_nothing(life_time = 30 SECONDS) //we cant maintain its existence for too long!
/datum/computer_file/program/virtual_pet/proc/recall_pet()
animate(pet, transform = matrix().Scale(0.3, 0.3), time = 1.5 SECONDS)
diff --git a/code/modules/power/turbine/turbine.dm b/code/modules/power/turbine/turbine.dm
index 4dc04d6e6f49..5e010305b39b 100644
--- a/code/modules/power/turbine/turbine.dm
+++ b/code/modules/power/turbine/turbine.dm
@@ -412,8 +412,6 @@
var/damage = 0
///Used to calculate the max damage received per tick and if the alarm should be called
var/damage_archived = 0
- ///Our internal radio
- var/obj/item/radio/radio
COOLDOWN_DECLARE(turbine_damage_alert)
@@ -421,17 +419,8 @@
//Volume of gas mixture is 3000
. = ..(mapload, gas_theoretical_volume = 3000)
- radio = new(src)
- radio.keyslot = new /obj/item/encryptionkey/headset_eng
- radio.set_listening(FALSE)
- radio.recalculateChannels()
-
new /obj/item/paper/guides/jobs/atmos/turbine(loc)
-/obj/machinery/power/turbine/core_rotor/Destroy()
- QDEL_NULL(radio)
- return ..()
-
/obj/machinery/power/turbine/core_rotor/add_context(atom/source, list/context, obj/item/held_item, mob/user)
. = ..()
if(. == NONE)
@@ -671,7 +660,7 @@
explosion(src, 2, 5, 7)
return PROCESS_KILL
- radio.talk_into(src, "Warning, turbine at [get_area_name(src)] taking damage, current integrity at [integrity]%!", RADIO_CHANNEL_ENGINEERING)
+ aas_config_announce(/datum/aas_config_entry/engineering_turbine_failure, list("INTEGRITY" = integrity, "LOCATION" = get_area_name(src)), src, list(RADIO_CHANNEL_ENGINEERING))
playsound(src, 'sound/machines/engine_alert1.ogg', 100, FALSE, 30, 30, falloff_distance = 10)
//================ROTOR WORKING============//
@@ -708,5 +697,15 @@
-Each tier increases the efficiency (more power), the max reachable RPM, and the max temperature that the machine can process without taking damage (up to fusion temperatures at the last tier!).
\
-A word of warning, the machine is very inefficient in its gas consumption and many unburnt gases will pass through. If you want to be cheap you can either pre-burn the gases or add a filtering system to collect the unburnt gases and reuse them."
+/datum/aas_config_entry/engineering_turbine_failure
+ name = "Engineering Alert: Turbine Failure"
+ announcement_lines_map = list(
+ "Message" = "Warning, turbine at %LOCATION taking damage, current integrity at %INTEGRITY%!",
+ )
+ vars_and_tooltips_map = list(
+ "LOCATION" = "will be replaced with location of the turbine.",
+ "INTEGRITY" = "with the current integrity of the turbine.",
+ )
+
#undef PRESSURE_MAX
#undef MINIMUM_TURBINE_PRESSURE
diff --git a/code/modules/research/designs/comp_board_designs.dm b/code/modules/research/designs/comp_board_designs.dm
index fb82d0857e3c..f5d4cacafa4c 100644
--- a/code/modules/research/designs/comp_board_designs.dm
+++ b/code/modules/research/designs/comp_board_designs.dm
@@ -395,3 +395,13 @@
RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_COMMAND
)
departmental_flags = DEPARTMENT_BITFLAG_SECURITY //Honestly should have a bridge techfab for this sometime.
+
+/datum/design/board/quantum_console
+ name = "Quantum Console Board"
+ desc = "Allows for the construction of circuit boards used to build a Quantum Console."
+ id = "quantum_console"
+ build_path = /obj/item/circuitboard/computer/quantum_console
+ category = list(
+ RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_CARGO
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
diff --git a/code/modules/research/designs/machine_designs.dm b/code/modules/research/designs/machine_designs.dm
index 938ceb574b2c..16da1d229eb1 100644
--- a/code/modules/research/designs/machine_designs.dm
+++ b/code/modules/research/designs/machine_designs.dm
@@ -1238,3 +1238,23 @@
RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_SERVICE
)
departmental_flags = DEPARTMENT_BITFLAG_SERVICE
+
+/datum/design/board/netpod
+ name = "Netpod Board"
+ desc = "The circuit board for a netpod."
+ id = "netpod"
+ build_path = /obj/item/circuitboard/machine/netpod
+ category = list(
+ RND_CATEGORY_MACHINE + RND_SUBCATEGORY_MACHINE_CARGO
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
+
+/datum/design/board/byteforge
+ name = "Byteforge Board"
+ desc = "Allows for the construction of circuit boards used to build a Byteforge."
+ id = "byteforge"
+ build_path = /obj/item/circuitboard/machine/byteforge
+ category = list(
+ RND_CATEGORY_COMPUTER + RND_SUBCATEGORY_COMPUTER_CARGO
+ )
+ departmental_flags = DEPARTMENT_BITFLAG_ENGINEERING
diff --git a/code/modules/shuttle/arrivals.dm b/code/modules/shuttle/arrivals.dm
index bd50a6b68958..3d3d291ad48b 100644
--- a/code/modules/shuttle/arrivals.dm
+++ b/code/modules/shuttle/arrivals.dm
@@ -78,10 +78,7 @@
damaged = TRUE
if(console)
console.say("Alert, hull breach detected!")
- if (length(GLOB.announcement_systems))
- var/obj/machinery/announcement_system/announcer = pick(GLOB.announcement_systems)
- if(!QDELETED(announcer))
- announcer.announce("ARRIVALS_BROKEN", channels = list())
+ aas_config_announce(/datum/aas_config_entry/arrivals_broken, list(), command_span=TRUE)
if(mode != SHUTTLE_CALL)
sound_played = FALSE
mode = SHUTTLE_IDLE
diff --git a/code/modules/unit_tests/_unit_tests.dm b/code/modules/unit_tests/_unit_tests.dm
index ab28763bd28f..4dae9af8e731 100644
--- a/code/modules/unit_tests/_unit_tests.dm
+++ b/code/modules/unit_tests/_unit_tests.dm
@@ -89,6 +89,7 @@
// BEGIN_INCLUDE
#include "aaa_modular_vendors.dm"
#include "aaa_pain.dm"
+#include "aas_configs.dm"
#include "abductor_baton_spell.dm"
#include "ablative_hud.dm"
#include "achievements.dm"
diff --git a/code/modules/unit_tests/aas_configs.dm b/code/modules/unit_tests/aas_configs.dm
new file mode 100644
index 000000000000..30b82619dd75
--- /dev/null
+++ b/code/modules/unit_tests/aas_configs.dm
@@ -0,0 +1,10 @@
+/datum/unit_test/aas_configs
+
+/datum/unit_test/aas_configs/Run()
+ var/expected_max_length = MAX_AAS_LENGTH
+
+ for(var/config_type in valid_subtypesof(/datum/aas_config_entry))
+ var/datum/aas_config_entry/entry = allocate(config_type)
+ for(var/key, line in entry.announcement_lines_map)
+ if(length_char(line) > expected_max_length)
+ TEST_FAIL("Announcement line '[key]' in config '[config_type]' exceeds max length of [expected_max_length] characters (actual length: [length(line)])")
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 1f1ac9d9fdd0..26b7962e944e 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -218,9 +218,6 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
///Name of lighting mask for the vending machine
var/light_mask
- /// used for narcing on underages
- var/obj/item/radio/sec_radio
-
///Whether this vendor can be selected when building a custom vending machine
var/allow_custom = FALSE
@@ -296,7 +293,6 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
/obj/machinery/vending/Destroy()
QDEL_NULL(coin)
QDEL_NULL(bill)
- QDEL_NULL(sec_radio)
GLOB.vending_machines_to_restock -= src
return ..()
@@ -1419,11 +1415,12 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
if(age_restrictions && item_record.age_restricted && (!card_used.registered_age || card_used.registered_age < AGE_MINOR))
speak("You are not of legal age to purchase [item_record.name].")
if(!(usr in GLOB.narcd_underages))
- if (isnull(sec_radio))
- sec_radio = new (src)
- sec_radio.set_listening(FALSE)
- sec_radio.set_frequency(FREQ_SECURITY)
- sec_radio.talk_into(src, "SECURITY ALERT: Underaged crewmember [usr] recorded attempting to purchase [item_record.name] in [get_area(src)]. Please watch for substance abuse.", FREQ_SECURITY)
+ aas_config_announce(/datum/aas_config_entry/vendomat_age_control, list(
+ "PERSON" = usr.name,
+ "LOCATION" = get_area_name(src),
+ "VENDOR" = name,
+ "PRODUCT" = item_record.name
+ ), src, list(RADIO_CHANNEL_SECURITY))
GLOB.narcd_underages += usr
flick(icon_deny,src)
vend_ready = TRUE
@@ -1871,4 +1868,16 @@ GLOBAL_LIST_EMPTY(vending_machines_to_restock)
add_filter("vending_outline", 9, list("type" = "outline", "color" = COLOR_VERY_SOFT_YELLOW))
add_filter("vending_rays", 10, list("type" = "rays", "size" = 35, "color" = COLOR_VIVID_YELLOW))
+/datum/aas_config_entry/vendomat_age_control
+ name = "Security Alert: Underaged Substance Abuse"
+ announcement_lines_map = list(
+ "Message" = "SECURITY ALERT: Underaged crewmember %PERSON recorded attempting to purchase %PRODUCT in %LOCATION by %VENDOR. Please watch for substance abuse."
+ )
+ vars_and_tooltips_map = list(
+ "PERSON" = "will be replaced with the name of the crewmember",
+ "PRODUCT" = "with the product, he attempted to purchase",
+ "LOCATION" = "with place of purchase",
+ "VENDOR" = "with the vending machine"
+ )
+
#undef MAX_VENDING_INPUT_AMOUNT
diff --git a/icons/effects/bitrunning.dmi b/icons/effects/bitrunning.dmi
index 8efa429389c3..9a2e9c0228a5 100644
Binary files a/icons/effects/bitrunning.dmi and b/icons/effects/bitrunning.dmi differ
diff --git a/icons/obj/machines/bitrunning.dmi b/icons/obj/machines/bitrunning.dmi
index d61e910d195b..626ab4ff4f39 100644
Binary files a/icons/obj/machines/bitrunning.dmi and b/icons/obj/machines/bitrunning.dmi differ
diff --git a/icons/obj/storage/closet.dmi b/icons/obj/storage/closet.dmi
index ec01f4b9a347..9392e4ccb4f1 100644
Binary files a/icons/obj/storage/closet.dmi and b/icons/obj/storage/closet.dmi differ
diff --git a/maplestation.dme b/maplestation.dme
index 5d0fc3d1094b..effebf5e5eb9 100644
--- a/maplestation.dme
+++ b/maplestation.dme
@@ -420,6 +420,7 @@
#include "code\__HELPERS\duplicating.dm"
#include "code\__HELPERS\dynamic_human_icon_gen.dm"
#include "code\__HELPERS\events.dm"
+#include "code\__HELPERS\fade_into_nothing.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\filters.dm"
#include "code\__HELPERS\forensics.dm"
@@ -530,6 +531,7 @@
#include "code\_globalvars\time_vars.dm"
#include "code\_globalvars\lists\achievements.dm"
#include "code\_globalvars\lists\ambience.dm"
+#include "code\_globalvars\lists\bitrunning.dm"
#include "code\_globalvars\lists\canisters.dm"
#include "code\_globalvars\lists\cargo.dm"
#include "code\_globalvars\lists\client.dm"
@@ -1527,7 +1529,6 @@
#include "code\datums\elements\structure_repair.dm"
#include "code\datums\elements\surgery_aid.dm"
#include "code\datums\elements\swabbable.dm"
-#include "code\datums\elements\temporary_atom.dm"
#include "code\datums\elements\tenacious.dm"
#include "code\datums\elements\tiny_mob_hunter.dm"
#include "code\datums\elements\tool_flash.dm"
@@ -2719,6 +2720,7 @@
#include "code\game\objects\structures\mystery_box.dm"
#include "code\game\objects\structures\noticeboard.dm"
#include "code\game\objects\structures\ore_containers.dm"
+#include "code\game\objects\structures\outfit_wardrobe.dm"
#include "code\game\objects\structures\petrified_statue.dm"
#include "code\game\objects\structures\pinatas.dm"
#include "code\game\objects\structures\plasticflaps.dm"
@@ -2898,6 +2900,7 @@
#include "code\modules\admin\trophy_manager.dm"
#include "code\modules\admin\whitelist.dm"
#include "code\modules\admin\callproc\callproc.dm"
+#include "code\modules\admin\smites\_smite.dm"
#include "code\modules\admin\smites\bad_luck.dm"
#include "code\modules\admin\smites\become_object.dm"
#include "code\modules\admin\smites\berforate.dm"
@@ -2923,7 +2926,6 @@
#include "code\modules\admin\smites\puzzle.dm"
#include "code\modules\admin\smites\rod.dm"
#include "code\modules\admin\smites\scarify.dm"
-#include "code\modules\admin\smites\smite.dm"
#include "code\modules\admin\smites\supply_pod.dm"
#include "code\modules\admin\smites\supply_pod_quick.dm"
#include "code\modules\admin\spawn_panel\admin_hotkeys.dm"
@@ -3509,7 +3511,6 @@
#include "code\modules\bitrunning\abilities.dm"
#include "code\modules\bitrunning\alerts.dm"
#include "code\modules\bitrunning\areas.dm"
-#include "code\modules\bitrunning\designs.dm"
#include "code\modules\bitrunning\event.dm"
#include "code\modules\bitrunning\job.dm"
#include "code\modules\bitrunning\outfits.dm"
@@ -3522,11 +3523,17 @@
#include "code\modules\bitrunning\antagonists\netguardian.dm"
#include "code\modules\bitrunning\components\avatar_connection.dm"
#include "code\modules\bitrunning\components\avatar_gear.dm"
-#include "code\modules\bitrunning\components\bitrunning_points.dm"
#include "code\modules\bitrunning\components\glitch.dm"
#include "code\modules\bitrunning\components\netpod_healing.dm"
#include "code\modules\bitrunning\components\npc_friendly.dm"
#include "code\modules\bitrunning\components\virtual_entity.dm"
+#include "code\modules\bitrunning\netpod\_netpod.dm"
+#include "code\modules\bitrunning\netpod\container.dm"
+#include "code\modules\bitrunning\netpod\outfitting.dm"
+#include "code\modules\bitrunning\netpod\signals.dm"
+#include "code\modules\bitrunning\netpod\tools.dm"
+#include "code\modules\bitrunning\netpod\ui.dm"
+#include "code\modules\bitrunning\netpod\utils.dm"
#include "code\modules\bitrunning\objects\byteforge.dm"
#include "code\modules\bitrunning\objects\clothing.dm"
#include "code\modules\bitrunning\objects\debug.dm"
@@ -3536,7 +3543,6 @@
#include "code\modules\bitrunning\objects\landmarks.dm"
#include "code\modules\bitrunning\objects\loot_box.dm"
#include "code\modules\bitrunning\objects\loot_crate.dm"
-#include "code\modules\bitrunning\objects\netpod.dm"
#include "code\modules\bitrunning\objects\quantum_console.dm"
#include "code\modules\bitrunning\objects\vendor.dm"
#include "code\modules\bitrunning\objects\gimmick_disks\_gimmick_disk.dm"
@@ -3570,6 +3576,7 @@
#include "code\modules\bitrunning\virtual_domain\domains\gondola_asteroid.dm"
#include "code\modules\bitrunning\virtual_domain\domains\grassland_hunt.dm"
#include "code\modules\bitrunning\virtual_domain\domains\hierophant.dm"
+#include "code\modules\bitrunning\virtual_domain\domains\island_brawl.dm"
#include "code\modules\bitrunning\virtual_domain\domains\meta_central.dm"
#include "code\modules\bitrunning\virtual_domain\domains\pipedream.dm"
#include "code\modules\bitrunning\virtual_domain\domains\pirates.dm"
@@ -3634,6 +3641,7 @@
#include "code\modules\cargo\universal_scanner.dm"
#include "code\modules\cargo\bounties\assistant.dm"
#include "code\modules\cargo\bounties\atmos.dm"
+#include "code\modules\cargo\bounties\bitrunning.dm"
#include "code\modules\cargo\bounties\botany.dm"
#include "code\modules\cargo\bounties\chef.dm"
#include "code\modules\cargo\bounties\engineering.dm"
diff --git a/tgstation.dme b/tgstation.dme
index 90710db7a252..cde06e9a327d 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -420,6 +420,7 @@
#include "code\__HELPERS\duplicating.dm"
#include "code\__HELPERS\dynamic_human_icon_gen.dm"
#include "code\__HELPERS\events.dm"
+#include "code\__HELPERS\fade_into_nothing.dm"
#include "code\__HELPERS\files.dm"
#include "code\__HELPERS\filters.dm"
#include "code\__HELPERS\forensics.dm"
@@ -530,6 +531,7 @@
#include "code\_globalvars\time_vars.dm"
#include "code\_globalvars\lists\achievements.dm"
#include "code\_globalvars\lists\ambience.dm"
+#include "code\_globalvars\lists\bitrunning.dm"
#include "code\_globalvars\lists\canisters.dm"
#include "code\_globalvars\lists\cargo.dm"
#include "code\_globalvars\lists\client.dm"
@@ -1528,7 +1530,6 @@
#include "code\datums\elements\structure_repair.dm"
#include "code\datums\elements\surgery_aid.dm"
#include "code\datums\elements\swabbable.dm"
-#include "code\datums\elements\temporary_atom.dm"
#include "code\datums\elements\tenacious.dm"
#include "code\datums\elements\tiny_mob_hunter.dm"
#include "code\datums\elements\tool_flash.dm"
@@ -2729,6 +2730,7 @@
#include "code\game\objects\structures\mystery_box.dm"
#include "code\game\objects\structures\noticeboard.dm"
#include "code\game\objects\structures\ore_containers.dm"
+#include "code\game\objects\structures\outfit_wardrobe.dm"
#include "code\game\objects\structures\petrified_statue.dm"
#include "code\game\objects\structures\pinatas.dm"
#include "code\game\objects\structures\plasticflaps.dm"
@@ -2908,6 +2910,7 @@
#include "code\modules\admin\trophy_manager.dm"
#include "code\modules\admin\whitelist.dm"
#include "code\modules\admin\callproc\callproc.dm"
+#include "code\modules\admin\smites\_smite.dm"
#include "code\modules\admin\smites\bad_luck.dm"
#include "code\modules\admin\smites\become_object.dm"
#include "code\modules\admin\smites\berforate.dm"
@@ -2931,9 +2934,9 @@
#include "code\modules\admin\smites\phobia_ocky_icky.dm"
#include "code\modules\admin\smites\puzzgrid.dm"
#include "code\modules\admin\smites\puzzle.dm"
+#include "code\modules\admin\smites\retcon.dm"
#include "code\modules\admin\smites\rod.dm"
#include "code\modules\admin\smites\scarify.dm"
-#include "code\modules\admin\smites\smite.dm"
#include "code\modules\admin\smites\supply_pod.dm"
#include "code\modules\admin\smites\supply_pod_quick.dm"
#include "code\modules\admin\spawn_panel\admin_hotkeys.dm"
@@ -3520,7 +3523,6 @@
#include "code\modules\bitrunning\abilities.dm"
#include "code\modules\bitrunning\alerts.dm"
#include "code\modules\bitrunning\areas.dm"
-#include "code\modules\bitrunning\designs.dm"
#include "code\modules\bitrunning\event.dm"
#include "code\modules\bitrunning\job.dm"
#include "code\modules\bitrunning\outfits.dm"
@@ -3533,11 +3535,17 @@
#include "code\modules\bitrunning\antagonists\netguardian.dm"
#include "code\modules\bitrunning\components\avatar_connection.dm"
#include "code\modules\bitrunning\components\avatar_gear.dm"
-#include "code\modules\bitrunning\components\bitrunning_points.dm"
#include "code\modules\bitrunning\components\glitch.dm"
#include "code\modules\bitrunning\components\netpod_healing.dm"
#include "code\modules\bitrunning\components\npc_friendly.dm"
#include "code\modules\bitrunning\components\virtual_entity.dm"
+#include "code\modules\bitrunning\netpod\_netpod.dm"
+#include "code\modules\bitrunning\netpod\container.dm"
+#include "code\modules\bitrunning\netpod\outfitting.dm"
+#include "code\modules\bitrunning\netpod\signals.dm"
+#include "code\modules\bitrunning\netpod\tools.dm"
+#include "code\modules\bitrunning\netpod\ui.dm"
+#include "code\modules\bitrunning\netpod\utils.dm"
#include "code\modules\bitrunning\objects\byteforge.dm"
#include "code\modules\bitrunning\objects\clothing.dm"
#include "code\modules\bitrunning\objects\debug.dm"
@@ -3547,7 +3555,6 @@
#include "code\modules\bitrunning\objects\landmarks.dm"
#include "code\modules\bitrunning\objects\loot_box.dm"
#include "code\modules\bitrunning\objects\loot_crate.dm"
-#include "code\modules\bitrunning\objects\netpod.dm"
#include "code\modules\bitrunning\objects\quantum_console.dm"
#include "code\modules\bitrunning\objects\vendor.dm"
#include "code\modules\bitrunning\objects\gimmick_disks\_gimmick_disk.dm"
@@ -3582,6 +3589,7 @@
#include "code\modules\bitrunning\virtual_domain\domains\grassland_hunt.dm"
#include "code\modules\bitrunning\virtual_domain\domains\heretic_hunt.dm"
#include "code\modules\bitrunning\virtual_domain\domains\hierophant.dm"
+#include "code\modules\bitrunning\virtual_domain\domains\island_brawl.dm"
#include "code\modules\bitrunning\virtual_domain\domains\meta_central.dm"
#include "code\modules\bitrunning\virtual_domain\domains\pipedream.dm"
#include "code\modules\bitrunning\virtual_domain\domains\pirates.dm"
@@ -3646,6 +3654,7 @@
#include "code\modules\cargo\universal_scanner.dm"
#include "code\modules\cargo\bounties\assistant.dm"
#include "code\modules\cargo\bounties\atmos.dm"
+#include "code\modules\cargo\bounties\bitrunning.dm"
#include "code\modules\cargo\bounties\botany.dm"
#include "code\modules\cargo\bounties\chef.dm"
#include "code\modules\cargo\bounties\engineering.dm"
diff --git a/tgui/bun.lock b/tgui/bun.lock
index acef62558fdd..b1c304ede32a 100644
--- a/tgui/bun.lock
+++ b/tgui/bun.lock
@@ -1,5 +1,6 @@
{
"lockfileVersion": 1,
+ "configVersion": 0,
"workspaces": {
"": {
"name": "tgui-workspace",
@@ -49,7 +50,7 @@
"marked-smartypants": "^1.1.9",
"react": "^19.1.0",
"react-dom": "^19.1.0",
- "tgui-core": "^5.3.1",
+ "tgui-core": "^5.10.0",
"tgui-dev-server": "workspace:*",
},
},
@@ -72,7 +73,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
- "tgui-core": "^5.3.1",
+ "tgui-core": "^5.10.0",
"tgui-dev-server": "workspace:*",
},
},
@@ -84,7 +85,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
- "tgui-core": "^5.3.1",
+ "tgui-core": "^5.10.0",
},
},
"packages/tgui-setup": {
@@ -991,7 +992,7 @@
"tgui": ["tgui@workspace:packages/tgui"],
- "tgui-core": ["tgui-core@5.3.1", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@nozbe/microfuzz": "^1.0.0" }, "peerDependencies": { "react": "^19.1.0", "react-dom": "^19.1.0" } }, "sha512-+8dDM4R2G6T1SpzpkRXGYc7YD+9ohqYjTV/4Zgcqc1I4Ld8bJH9vKHCQVbEAsHTCIjHsTBW4xnOpKyAx1gRB5w=="],
+ "tgui-core": ["tgui-core@5.10.0", "", { "dependencies": { "@floating-ui/react": "^0.27.16", "@nozbe/microfuzz": "^1.0.0" }, "peerDependencies": { "react": "^19.1.0", "react-dom": "^19.1.0" } }, "sha512-sbw2zSdJM55M333CHP2HALoEh3LBF07HNPDEXIwPDTGu0TKEaBMvkRnQlLN81A5s9cLjS4DCIvYTTE1qUQENeQ=="],
"tgui-dev-server": ["tgui-dev-server@workspace:packages/tgui-dev-server"],
diff --git a/tgui/packages/tgui-panel/package.json b/tgui/packages/tgui-panel/package.json
index b52f197f8699..792bb3ad4f3a 100644
--- a/tgui/packages/tgui-panel/package.json
+++ b/tgui/packages/tgui-panel/package.json
@@ -8,7 +8,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
- "tgui-core": "^5.3.1",
+ "tgui-core": "^5.10.0",
"tgui-dev-server": "workspace:*"
},
"private": true
diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json
index 47d64bc70e9c..b11aa26b1c8b 100644
--- a/tgui/packages/tgui-say/package.json
+++ b/tgui/packages/tgui-say/package.json
@@ -6,7 +6,7 @@
"react": "^19.1.0",
"react-dom": "^19.1.0",
"tgui": "workspace:*",
- "tgui-core": "^5.3.1"
+ "tgui-core": "^5.10.0"
},
"private": true
}
diff --git a/tgui/packages/tgui/interfaces/AutomatedAnnouncement.tsx b/tgui/packages/tgui/interfaces/AutomatedAnnouncement.tsx
index d4fab9f73f4a..285d5ee01856 100644
--- a/tgui/packages/tgui/interfaces/AutomatedAnnouncement.tsx
+++ b/tgui/packages/tgui/interfaces/AutomatedAnnouncement.tsx
@@ -1,96 +1,156 @@
-import { Button, Input, LabeledList, Section } from 'tgui-core/components';
+import { sortBy } from 'es-toolkit';
+import { filter } from 'es-toolkit/compat';
+import { useState } from 'react';
+import {
+ Button,
+ Input,
+ LabeledList,
+ NoticeBox,
+ Section,
+ Stack,
+ Table,
+} from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
import { useBackend } from '../backend';
import { Window } from '../layouts';
-const TOOLTIP_TEXT = `
- %PERSON will be replaced with their name.
- %RANK with their job.
-`;
+type AASConfigEntry = {
+ name: string;
+ entryRef: string;
+ enabled: BooleanLike;
+ modifiable: BooleanLike;
+ announcementLinesMap: Record;
+ generalTooltip: string;
+ varsAndTooltipsMap: Record;
+};
type Data = {
- arrivalToggle: BooleanLike;
- arrival: string;
- newheadToggle: BooleanLike;
- newhead: string;
+ config_entries: AASConfigEntry[];
+ max_announcement_len: number;
};
export const AutomatedAnnouncement = (props) => {
const { act, data } = useBackend();
- const { arrivalToggle, arrival, newheadToggle, newhead } = data;
+ const { config_entries = [], max_announcement_len } = data;
+
+ const [search, setSearch] = useState('');
+
+ const isEntryMatch = (entry: AASConfigEntry, search: string) => {
+ if (!search) return true;
+ const { name, announcementLinesMap = [], varsAndTooltipsMap = [] } = entry;
+ switch (true) {
+ case name?.toLowerCase().includes(search?.toLowerCase()):
+ case Object.keys(announcementLinesMap).some((lineKey) =>
+ lineKey.toLowerCase().includes(search?.toLowerCase()),
+ ):
+ case Object.values(announcementLinesMap).some((line) =>
+ line.toLowerCase().includes(search?.toLowerCase()),
+ ):
+ case Object.keys(varsAndTooltipsMap).some((varName) =>
+ varName.toLowerCase().includes(search?.toLowerCase()),
+ ):
+ return true;
+ default:
+ return false;
+ }
+ };
+
+ const errorMessage = !config_entries.length
+ ? 'No configurable options detected! Please report this to Nanotrasen.'
+ : 'No match. Refine your search.';
+
+ const sorted = sortBy(
+ filter(config_entries, (entry) => isEntryMatch(entry, search)),
+ [(entry) => entry.name],
+ );
return (
-
+
-
-
+
+
+
+
+
+
+
+
+
+ {!sorted.length ? (
+ {errorMessage}
+ ) : (
+
+ {sorted.map((entry, index) => (
+
+
+ ))}
+
+ )}
+
+
);
diff --git a/tgui/packages/tgui/interfaces/QuantumConsole.tsx b/tgui/packages/tgui/interfaces/QuantumConsole.tsx
index 2b08c4add218..b191549a6ef0 100644
--- a/tgui/packages/tgui/interfaces/QuantumConsole.tsx
+++ b/tgui/packages/tgui/interfaces/QuantumConsole.tsx
@@ -11,7 +11,6 @@ import {
Tooltip,
} from 'tgui-core/components';
import type { BooleanLike } from 'tgui-core/react';
-
import { useBackend, useSharedState } from '../backend';
import { Window } from '../layouts';
import { LoadingScreen } from './common/LoadingScreen';
@@ -46,6 +45,7 @@ type Avatar = {
};
type Domain = {
+ announce_ghosts: BooleanLike;
cost: number;
desc: string;
difficulty: number;
@@ -54,6 +54,7 @@ type Domain = {
has_secondary_objectives: BooleanLike;
name: string;
reward: number | string;
+ grade_symbol: string;
};
type DomainEntryProps = {
@@ -73,10 +74,11 @@ enum Difficulty {
High,
}
-const isConnected = (data: Data): data is Data & { connected: 1 } =>
- data.connected === 1;
+function isConnected(data: Data): data is Data & { connected: 1 } {
+ return data.connected === 1;
+}
-const getColor = (difficulty: number) => {
+function getColor(difficulty: number) {
switch (difficulty) {
case Difficulty.Low:
return 'yellow';
@@ -87,9 +89,9 @@ const getColor = (difficulty: number) => {
default:
return 'green';
}
-};
+}
-export const QuantumConsole = (props) => {
+export function QuantumConsole(props) {
const { data } = useBackend();
return (
@@ -100,9 +102,9 @@ export const QuantumConsole = (props) => {
);
-};
+}
-const AccessView = (props) => {
+function AccessView(props) {
const { act, data } = useBackend();
const [tab, setTab] = useSharedState('tab', 0);
@@ -246,11 +248,12 @@ const AccessView = (props) => {
);
-};
+}
-const DomainEntry = (props: DomainEntryProps) => {
+function DomainEntry(props: DomainEntryProps) {
const {
domain: {
+ announce_ghosts,
cost,
desc,
difficulty,
@@ -259,6 +262,7 @@ const DomainEntry = (props: DomainEntryProps) => {
has_secondary_objectives,
name,
reward,
+ grade_symbol,
},
} = props;
const { act, data } = useBackend();
@@ -282,6 +286,8 @@ const DomainEntry = (props: DomainEntryProps) => {
buttonName = 'Deploy';
}
+ const canView = name !== '???';
+
return (
{
title={
<>
{name}
- {!!is_modular && name !== '???' && }
- {!!has_secondary_objectives && name !== '???' && (
-
- )}
+ {!!is_modular && canView && }
+ {!!has_secondary_objectives && canView && }
+ {!!announce_ghosts && canView && }
>
}
+ sideIcon={grade_symbol}
>
{desc}
{!!is_modular && ' (Modular)'}
{!!has_secondary_objectives && ' (Secondary Objective Available)'}
+ {!!announce_ghosts && ' (Ghost Interaction)'}
@@ -330,7 +337,7 @@ const DomainEntry = (props: DomainEntryProps) => {
);
-};
+}
const AvatarDisplay = (props) => {
const { act, data } = useBackend();
diff --git a/tgui/packages/tgui/package.json b/tgui/packages/tgui/package.json
index e4f1037775f9..b7f6fbcfa7bc 100644
--- a/tgui/packages/tgui/package.json
+++ b/tgui/packages/tgui/package.json
@@ -14,7 +14,7 @@
"marked-smartypants": "^1.1.9",
"react": "^19.1.0",
"react-dom": "^19.1.0",
- "tgui-core": "^5.3.1",
+ "tgui-core": "^5.10.0",
"tgui-dev-server": "workspace:*"
},
"private": true