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 ( - + -
act('ArrivalToggle')} - /> - } - > - - - } - > - - act('ArrivalText', { - newText: value, - }) - } - /> - - -
-
act('NewheadToggle')} - /> - } - > - - - } - > - - act('NewheadText', { - newText: value, - }) - } - /> - - -
+ + + + + + + + + + {!sorted.length ? ( + {errorMessage} + ) : ( +
+ {sorted.map((entry, index) => ( +
+ + + } + > + + {Object.entries(entry.announcementLinesMap).map( + ([lineKey, announcementLine]) => ( + + + {lineKey}: + + + + act('Text', { + entryRef: entry.entryRef, + lineKey, + newText: value, + }) + } + /> + + + ), + )} +
+
+ ))} +
+ )} +
+
); 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