diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm index f7d7be770e949..3244b6d9d936f 100644 --- a/_maps/map_files/generic/CentCom.dmm +++ b/_maps/map_files/generic/CentCom.dmm @@ -52,14 +52,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/evac) -"ao" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/table/glass, -/obj/item/storage/box/beakers, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "ap" = ( /obj/structure/filingcabinet/security, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -72,11 +64,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) -"ar" = ( -/obj/structure/table/reinforced, -/obj/item/assembly/flash/handheld, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "as" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 8 @@ -209,11 +196,13 @@ }, /turf/open/floor/iron/white, /area/centcom/control) -"aM" = ( -/obj/machinery/computer/operating{ - dir = 1 +"aL" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 }, -/turf/open/floor/mineral/titanium/blue, +/obj/item/banner/command, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/sepia, /area/centcom/evac) "aP" = ( /obj/machinery/vending/hydronutrients, @@ -256,6 +245,23 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/syndicate_mothership/control) +"aW" = ( +/obj/structure/reagent_dispensers/fueltank, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/cobweb, +/obj/effect/decal/cleanable/blood/old, +/obj/structure/sign/warning/nosmoking{ + pixel_y = 32 + }, +/obj/structure/sign/warning/fire{ + pixel_x = -32 + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "ba" = ( /obj/effect/spawner/xmastree, /obj/effect/turf_decal/tile/bar/opposingcorners, @@ -309,6 +315,17 @@ }, /turf/open/floor/iron, /area/centcom/supplypod/loading/four) +"bo" = ( +/obj/structure/filingcabinet{ + pixel_x = 9 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/item/kirbyplants{ + icon_state = "plant-22"; + pixel_x = -5 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "bp" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on{ dir = 8 @@ -371,6 +388,28 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/evac) +"bz" = ( +/obj/structure/table/wood, +/obj/item/phone{ + desc = "Supposedly a direct line to Nanotrasen Central Command. It's not even plugged in."; + pixel_x = -3; + pixel_y = 3 + }, +/obj/item/clothing/mask/cigarette/cigar/cohiba{ + pixel_x = 6 + }, +/obj/item/clothing/mask/cigarette/cigar/havana{ + pixel_x = 2 + }, +/obj/item/clothing/mask/cigarette/cigar{ + pixel_x = 4.5 + }, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/tdome/tdomeadmin) "bA" = ( /obj/structure/table, /obj/item/clipboard, @@ -410,15 +449,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeadmin) -"bG" = ( -/obj/structure/window/plasma/reinforced{ - dir = 4 - }, -/obj/structure/window/plasma/reinforced{ - dir = 1 - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "bJ" = ( /obj/machinery/computer/secure_data{ dir = 8 @@ -460,27 +490,11 @@ /turf/open/floor/iron, /area/centcom/control) "bO" = ( -/obj/structure/table/wood, -/obj/item/phone{ - desc = "Supposedly a direct line to Nanotrasen Central Command. It's not even plugged in."; - pixel_x = -3; - pixel_y = 3 - }, -/obj/item/clothing/mask/cigarette/cigar/cohiba{ - pixel_x = 6 - }, -/obj/item/clothing/mask/cigarette/cigar/havana{ - pixel_x = 2 - }, -/obj/item/clothing/mask/cigarette/cigar{ - pixel_x = 4.5 - }, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 +/obj/structure/chair/fancy/shuttle{ + dir = 1 }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/tdome/tdomeadmin) +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "bP" = ( /obj/machinery/vending/hydroseeds, /obj/effect/turf_decal/tile/green/fourcorners/contrasted, @@ -504,6 +518,19 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"bV" = ( +/obj/structure/closet/crate/engineering, +/obj/item/stack/sheet/mineral/plasma{ + amount = 10 + }, +/obj/item/stack/sheet/mineral/plasma{ + amount = 10 + }, +/obj/item/stack/sheet/mineral/plasma/five, +/obj/effect/turf_decal/stripes/line, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron/smooth_edge, +/area/centcom/evac) "bX" = ( /obj/structure/table/wood, /obj/item/toy/cards/deck/cas{ @@ -534,10 +561,6 @@ }, /turf/open/floor/iron/dark, /area/ctf) -"cc" = ( -/obj/machinery/vending/boozeomat, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "cd" = ( /obj/structure/fans/tiny, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -591,11 +614,6 @@ }, /turf/open/floor/iron/dark, /area/centcom/control) -"co" = ( -/obj/structure/bed, -/obj/item/bedsheet/medical, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "cp" = ( /obj/structure/closet/secure_closet/hydroponics{ locked = 0 @@ -607,14 +625,6 @@ /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron, /area/centcom/supplypod/loading/three) -"cs" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/table/glass, -/obj/item/storage/firstaid/regular, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "ct" = ( /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, @@ -637,6 +647,18 @@ }, /turf/open/floor/iron/white, /area/centcom/control) +"cA" = ( +/obj/structure/table/reinforced, +/obj/machinery/button/door/indestructible{ + id = "XCCsec3"; + name = "CC Main Access Control" + }, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "cB" = ( /obj/structure/table/wood, /obj/item/phone{ @@ -669,6 +691,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) +"cD" = ( +/obj/docking_port/stationary{ + dir = 4; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_2_away" + }, +/turf/open/space/basic, +/area/space) "cE" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -680,12 +713,6 @@ }, /turf/open/floor/iron, /area/centcom/supplypod/loading/three) -"cH" = ( -/obj/machinery/computer/communications{ - dir = 8 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "cI" = ( /obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/iron, @@ -746,16 +773,6 @@ }, /turf/open/floor/iron/dark, /area/centcom/ferry) -"cU" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/window{ - dir = 8 - }, -/obj/structure/closet/wardrobe/white, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "cV" = ( /obj/item/kirbyplants{ icon_state = "plant-21" @@ -796,11 +813,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"de" = ( -/obj/structure/table/reinforced, -/obj/item/paper_bin, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "df" = ( /obj/structure/chair/office{ dir = 1 @@ -870,11 +882,14 @@ }, /turf/open/floor/iron/dark, /area/centcom/control) -"du" = ( -/obj/structure/grille, -/obj/structure/window/shuttle, -/turf/open/floor/plating, -/area/centcom/evac) +"ds" = ( +/obj/structure/bookcase/random, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "dx" = ( /obj/machinery/computer/secure_data{ dir = 1 @@ -900,6 +915,29 @@ }, /turf/open/floor/iron/dark, /area/ctf) +"dB" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks/beer{ + dir = 8; + pixel_x = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/blood/old, +/obj/structure/sign/poster/official/cohiba_robusto_ad{ + pixel_x = 32 + }, +/obj/item/reagent_containers/food/drinks/shaker{ + pixel_x = -10; + pixel_y = 1 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) "dC" = ( /obj/machinery/computer/med_data{ dir = 4 @@ -913,6 +951,15 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/evac) +"dG" = ( +/obj/effect/turf_decal/trimline/red/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 8 + }, +/turf/open/floor/iron/white, +/area/centcom/evac) "dH" = ( /obj/structure/table/wood, /obj/item/storage/box/drinkingglasses, @@ -969,9 +1016,12 @@ /obj/item/storage/pill_bottle/dice, /turf/open/floor/carpet/grimy, /area/centcom/ferry) -"dV" = ( -/obj/machinery/door/window/westleft, -/turf/open/floor/mineral/titanium/blue, +"dW" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/item/banner/command, +/turf/open/floor/sepia, /area/centcom/evac) "dX" = ( /obj/machinery/computer/security/telescreen, @@ -1002,22 +1052,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"ee" = ( -/obj/structure/table/reinforced, -/obj/machinery/door/firedoor, -/obj/machinery/door/window/brigdoor{ - base_state = "rightsecure"; - dir = 1; - icon_state = "rightsecure"; - name = "CentCom Customs"; - req_access_txt = "109" - }, -/obj/effect/turf_decal/bot, -/obj/item/toy/plush/lizard_plushie/space/green{ - name = "Escapee" - }, -/turf/open/floor/iron, -/area/centcom/evac) "ef" = ( /obj/item/reagent_containers/glass/bottle/epinephrine{ pixel_x = 6 @@ -1055,17 +1089,6 @@ }, /turf/open/floor/iron/white, /area/centcom/control) -"eh" = ( -/obj/structure/table/reinforced, -/obj/item/clipboard, -/obj/item/folder/white, -/obj/item/pen/blue, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/control) "ei" = ( /obj/machinery/computer/security{ dir = 4 @@ -1079,6 +1102,15 @@ }, /turf/open/floor/iron/dark, /area/ctf) +"ek" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/arrows{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/evac) "el" = ( /obj/machinery/door/window/brigdoor{ base_state = "rightsecure"; @@ -1092,6 +1124,20 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"en" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/sign/picture_frame{ + pixel_x = 32 + }, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "eo" = ( /obj/machinery/power/terminal{ dir = 1 @@ -1117,12 +1163,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"er" = ( -/obj/structure/table, -/obj/item/storage/lockbox, -/obj/item/storage/firstaid/advanced, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "eu" = ( /obj/structure/table/wood, /obj/item/paper_bin, @@ -1134,6 +1174,22 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron, /area/tdome/arena) +"ew" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/structure/table/wood, +/obj/item/toy/cards/deck{ + pixel_y = 13; + pixel_x = -6 + }, +/obj/item/trash/cheesie{ + pixel_y = 7; + pixel_x = -4 + }, +/obj/item/reagent_containers/food/drinks/mug/tea{ + pixel_x = 9 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "ex" = ( /obj/machinery/vending/coffee, /obj/machinery/newscaster{ @@ -1208,6 +1264,22 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"eG" = ( +/obj/machinery/power/port_gen/pacman, +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/warning/electricshock{ + pixel_y = 32 + }, +/obj/effect/turf_decal/bot_white, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "eH" = ( /obj/machinery/hydroponics/constructable, /obj/machinery/light{ @@ -1220,6 +1292,21 @@ /obj/effect/turf_decal/tile/red/opposingcorners, /turf/open/floor/iron/dark, /area/ctf) +"eK" = ( +/obj/machinery/power/terminal{ + dir = 1 + }, +/obj/structure/cable, +/obj/effect/decal/cleanable/oil, +/obj/machinery/airalarm/directional/west, +/obj/structure/cable/yellow{ + icon_state = "0-4" + }, +/obj/structure/cable/yellow{ + icon_state = "0-2" + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "eL" = ( /obj/machinery/light{ dir = 4 @@ -1256,24 +1343,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) -"eS" = ( -/obj/machinery/atmospherics/components/unary/portables_connector/visible{ - dir = 1 - }, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/decal/cleanable/dirt, -/obj/effect/decal/cleanable/dirt, -/obj/machinery/portable_atmospherics/canister/air, -/obj/structure/cable/white{ - icon_state = "1-4" - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron, -/area/centcom/ferry) "eT" = ( /obj/machinery/light, /obj/structure/filingcabinet/chestdrawer, @@ -1404,11 +1473,6 @@ /obj/effect/turf_decal/tile/brown/anticorner/contrasted, /turf/open/floor/iron, /area/centcom/supply) -"ft" = ( -/obj/structure/table/reinforced, -/obj/item/storage/box/handcuffs, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "fu" = ( /obj/machinery/firealarm{ dir = 1; @@ -1643,6 +1707,12 @@ /obj/structure/barricade/security/ctf, /turf/open/floor/circuit/red, /area/ctf) +"gr" = ( +/obj/structure/window/reinforced/survival_pod{ + dir = 1 + }, +/turf/open/floor/plating, +/area/centcom/evac) "gs" = ( /obj/machinery/vending/cola, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -1656,6 +1726,16 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/syndicate_mothership/control) +"gx" = ( +/obj/machinery/computer/security{ + dir = 8 + }, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "gy" = ( /obj/structure/table/wood, /obj/machinery/reagentgrinder{ @@ -1717,14 +1797,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) -"gJ" = ( -/obj/structure/rack, -/obj/item/storage/box/donkpockets, -/obj/item/storage/box/donkpockets, -/obj/item/clothing/head/utility/chefhat, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/tdome/tdomeobserve) "gL" = ( /obj/effect/turf_decal/tile/blue{ dir = 8 @@ -1752,6 +1824,20 @@ }, /turf/open/floor/iron, /area/centcom/control) +"gS" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "gT" = ( /obj/effect/turf_decal/tile/blue{ dir = 1 @@ -1893,6 +1979,16 @@ }, /turf/open/floor/iron/dark, /area/ctf) +"hx" = ( +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/machinery/door/airlock/titanium, +/obj/structure/fans/tiny, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "hz" = ( /obj/structure/table/wood, /obj/machinery/recharger, @@ -1939,25 +2035,6 @@ }, /turf/open/floor/iron, /area/centcom/control) -"hM" = ( -/obj/machinery/door/window/westleft, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"hQ" = ( -/obj/item/storage/firstaid/toxin, -/obj/item/storage/firstaid/o2{ - pixel_x = 3; - pixel_y = 3 - }, -/obj/structure/table/reinforced, -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 - }, -/obj/effect/turf_decal/tile/blue/opposingcorners{ - dir = 1 - }, -/turf/open/floor/iron/white, -/area/centcom/control) "hR" = ( /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron, @@ -1985,6 +2062,10 @@ /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/syndicate_mothership/control) +"hV" = ( +/obj/machinery/computer/shuttle_flight, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "hW" = ( /obj/structure/chair{ dir = 8 @@ -1999,6 +2080,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"hY" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/item/kirbyplants{ + icon_state = "plant-10" + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/warning/securearea{ + pixel_y = 32 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "hZ" = ( /obj/structure/closet/crate/bin, /obj/effect/turf_decal/tile/green/anticorner/contrasted{ @@ -2067,6 +2159,21 @@ /obj/machinery/status_display/ai, /turf/closed/indestructible/riveted, /area/centcom/control) +"iq" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark/corner{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/cobweb/cobweb2, +/obj/machinery/vending/cigarette, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/sign/picture_frame{ + pixel_x = 32 + }, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "ir" = ( /turf/closed/indestructible/fakeglass, /area/centcom/prison) @@ -2253,6 +2360,17 @@ /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/centcom/supply) +"iY" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 5 + }, +/obj/structure/window/reinforced/survival_pod{ + dir = 4 + }, +/obj/machinery/suit_storage_unit/engine, +/obj/effect/turf_decal/bot_white, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "ja" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/centcom{ @@ -2598,6 +2716,18 @@ }, /turf/open/floor/iron, /area/centcom/control) +"jX" = ( +/obj/machinery/camera/directional/north{ + c_tag = "Red Team"; + network = list("thunder"); + pixel_x = 11; + pixel_y = -9; + resistance_flags = 64 + }, +/obj/effect/landmark/thunderdome/two, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron, +/area/tdome/arena) "kd" = ( /obj/item/food/meat/slab/human/mutant/slime, /turf/open/floor/grass, @@ -2675,15 +2805,24 @@ }, /turf/open/floor/iron, /area/centcom/control) -"kG" = ( -/obj/structure/destructible/cult/tome, -/obj/item/book/codex_gigas, -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 +"kH" = ( +/obj/machinery/light/floor, +/obj/effect/turf_decal/trimline/neutral, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) +"kJ" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/ferry) +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/sign/poster/official/soft_cap_pop_art{ + pixel_x = -32 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "kK" = ( /turf/closed/indestructible/abductor{ icon_state = "alien16" @@ -2801,6 +2940,11 @@ /obj/machinery/light, /turf/open/floor/plating, /area/syndicate_mothership/control) +"lo" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/machinery/door/airlock/highsecurity, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "lr" = ( /turf/closed/indestructible/fakedoor{ name = "CentCom" @@ -2858,6 +3002,14 @@ }, /turf/open/floor/plating/abductor, /area/abductor_ship) +"lE" = ( +/obj/structure/table/optable/abductor, +/obj/effect/light_emitter{ + set_cap = 1; + set_luminosity = 4 + }, +/turf/open/floor/plating/abductor, +/area/abductor_ship) "lF" = ( /obj/effect/landmark/abductor/agent{ team_number = 4 @@ -2995,6 +3147,17 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"mi" = ( +/obj/structure/railing{ + dir = 6; + layer = 3.1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/dark{ + dir = 6 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "mk" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/directions/engineering{ @@ -3005,18 +3168,32 @@ /turf/open/floor/plating, /area/centcom/control) "ml" = ( -/obj/structure/table/reinforced, -/obj/machinery/microwave{ - desc = "Cooks and boils stuff, somehow."; - pixel_x = -3; - pixel_y = 5 +/obj/structure/chair/stool/bar{ + dir = 4 }, +/turf/open/floor/carpet/red, +/area/centcom/evac) +"mp" = ( +/obj/structure/filingcabinet/filingcabinet, /obj/machinery/airalarm/directional/south{ pixel_y = -22 }, +/obj/effect/turf_decal/stripes/line{ + dir = 9 + }, +/turf/open/floor/iron, +/area/centcom/supply) +"mq" = ( +/obj/structure/railing{ + dir = 10; + layer = 3.1 + }, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/dark{ + dir = 10 + }, /turf/open/floor/iron/dark, -/area/tdome/tdomeobserve) +/area/centcom/evac) "mr" = ( /turf/closed/indestructible/abductor{ icon_state = "alien6" @@ -3095,6 +3272,11 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"mN" = ( +/obj/structure/railing/corner, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/evac) "mO" = ( /obj/machinery/computer/communications, /turf/open/floor/carpet/grimy, @@ -3143,6 +3325,15 @@ }, /turf/open/floor/iron, /area/centcom/control) +"na" = ( +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ + dir = 4 + }, +/turf/open/floor/iron, +/area/centcom/supply) "nb" = ( /turf/closed/indestructible/abductor, /area/abductor_ship) @@ -3215,6 +3406,11 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"nn" = ( +/obj/structure/lattice, +/obj/structure/window/reinforced/spawner/north, +/turf/open/space/basic, +/area/space/nearstation) "no" = ( /obj/structure/plasticflaps/opaque, /obj/effect/decal/cleanable/dirt, @@ -3296,6 +3492,27 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/centcom/control) +"nP" = ( +/obj/docking_port/stationary{ + dir = 8; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_6_away" + }, +/turf/open/space/basic, +/area/space) +"nR" = ( +/obj/item/kirbyplants{ + icon_state = "plant-22" + }, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "nS" = ( /obj/machinery/door/airlock/silver{ name = "Bathroom" @@ -3343,34 +3560,74 @@ }, /turf/open/floor/iron, /area/centcom/control) +"oc" = ( +/obj/machinery/power/port_gen/pacman, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/glass, +/obj/effect/turf_decal/bot_white, +/obj/structure/sign/warning/nosmoking{ + pixel_x = 32 + }, +/obj/machinery/light/small{ + dir = 4 + }, +/obj/structure/cable/yellow{ + icon_state = "0-8" + }, +/turf/open/floor/iron/smooth_edge, +/area/centcom/evac) "oe" = ( /obj/effect/spawner/structure/window/reinforced, /turf/open/floor/plating, /area/centcom/ferry) -"oj" = ( -/obj/structure/closet/secure_closet/personal/cabinet, -/obj/item/clothing/under/rank/civilian/curator/treasure_hunter, -/obj/item/clothing/under/dress/skirt, -/obj/item/clothing/under/shorts/black, -/obj/item/clothing/under/pants/track, -/obj/item/clothing/accessory/armband/deputy, -/obj/item/clothing/accessory/waistcoat, -/obj/item/clothing/shoes/jackboots, -/obj/item/clothing/shoes/laceup, -/obj/item/clothing/neck/stripedredscarf, -/obj/item/clothing/neck/tie/red, -/obj/item/clothing/head/helmet/space/beret, -/obj/item/clothing/suit/jacket/curator, -/obj/item/clothing/suit/space/officer, -/obj/item/clothing/gloves/fingerless, -/obj/item/clothing/gloves/color/black, -/obj/item/clothing/glasses/eyepatch, -/obj/machinery/firealarm{ +"of" = ( +/obj/effect/turf_decal/trimline/red/line{ + dir = 4 + }, +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/white, +/area/centcom/evac) +"oi" = ( +/obj/docking_port/stationary{ + dir = 8; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_7_away" + }, +/turf/open/space/basic, +/area/space) +"om" = ( +/obj/structure/railing{ dir = 4; - pixel_x = -24 + layer = 4.1 }, -/turf/open/floor/carpet/grimy, -/area/centcom/ferry) +/obj/structure/table/reinforced, +/obj/item/paper_bin{ + pixel_y = 3; + pixel_x = -6 + }, +/obj/item/pen{ + pixel_x = -5; + pixel_y = 3 + }, +/obj/item/clipboard{ + pixel_x = 5 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/dark{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"or" = ( +/obj/structure/flora/ausbushes/sparsegrass, +/turf/open/floor/grass, +/area/centcom/evac) "os" = ( /obj/structure/table/reinforced, /obj/item/paper_bin, @@ -3406,6 +3663,16 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"ow" = ( +/obj/structure/reagent_dispensers/watertank, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/oil, +/obj/machinery/airalarm/directional/west, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "ox" = ( /obj/structure/table, /obj/item/paper/pamphlet/centcom/visitor_info, @@ -3437,21 +3704,41 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"oP" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/warning/securearea{ + pixel_y = 32 + }, +/obj/machinery/light{ + dir = 1 + }, +/mob/living/simple_animal/pet/dog/corgi/capybara{ + name = "Tincho" + }, +/obj/structure/bed/dogbed{ + name = "Tincho's bed" + }, +/turf/open/floor/carpet/red, +/area/centcom/evac) "oQ" = ( /obj/machinery/vending/snack, /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/centcom/control) "oS" = ( -/obj/machinery/computer/security{ +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ dir = 8 }, -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 +/obj/effect/turf_decal/stripes/corner{ + dir = 1 }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/control) +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "oU" = ( /obj/structure/closet/emcloset, /obj/item/tank/internals/emergency_oxygen/engi, @@ -3478,6 +3765,23 @@ }, /turf/open/floor/wood, /area/centcom/ferry) +"pc" = ( +/obj/structure/flora/tree/palm{ + pixel_x = -1 + }, +/obj/item/toy/plush/beeplushie{ + pixel_y = 5; + pixel_x = -3 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"pe" = ( +/obj/machinery/atmospherics/components/unary/tank/air, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "ph" = ( /obj/structure/chair/fancy/comfy{ buildstackamount = 0; @@ -3494,6 +3798,13 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"pk" = ( +/obj/machinery/computer/communications, +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "pl" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, @@ -3515,28 +3826,29 @@ /obj/machinery/light, /turf/open/floor/iron, /area/centcom/control) -"pn" = ( -/obj/structure/table/wood, -/obj/item/paper_bin, -/obj/item/pen/fourcolor, +"pp" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark/corner, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/item/kirbyplants{ + icon_state = "plant-21" + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"ps" = ( +/obj/machinery/door/airlock/maintenance_hatch, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) +"pw" = ( /obj/machinery/airalarm/directional/east{ pixel_x = 24 }, +/obj/structure/filingcabinet/filingcabinet, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, -/area/centcom/control) -"po" = ( -/obj/machinery/airalarm/directional/west{ - pixel_x = -23 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 8 - }, -/obj/machinery/light{ - dir = 8 - }, -/turf/open/floor/iron, -/area/centcom/control) +/area/centcom/supply) "px" = ( /obj/structure/chair{ dir = 8 @@ -3625,17 +3937,16 @@ /turf/open/floor/wood, /area/centcom/ferry) "pM" = ( -/obj/machinery/camera/directional/north{ - c_tag = "Green Team"; - network = list("thunder"); - pixel_x = 12; - pixel_y = -10; - resistance_flags = 64 +/obj/structure/table/optable, +/obj/machinery/defibrillator_mount/loaded{ + pixel_y = 28 }, -/obj/effect/landmark/thunderdome/one, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron, -/area/tdome/arena) +/obj/effect/turf_decal/stripes/line, +/obj/effect/decal/cleanable/blood, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/white, +/area/centcom/evac) "pP" = ( /obj/structure/table/reinforced, /obj/item/computer_hardware/hard_drive/role/quartermaster, @@ -3658,6 +3969,13 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/centcom/supply) +"pR" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "pS" = ( /obj/structure/table, /obj/item/stack/package_wrap, @@ -3689,6 +4007,22 @@ /obj/machinery/washing_machine, /turf/open/floor/iron/freezer, /area/syndicate_mothership/control) +"qa" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light/floor, +/obj/effect/turf_decal/trimline/neutral, +/turf/open/floor/iron, +/area/centcom/evac) +"qb" = ( +/obj/structure/window/reinforced/spawner/east, +/obj/structure/bodycontainer/morgue{ + dir = 8 + }, +/turf/open/floor/iron/white/textured_large, +/area/centcom/evac) "qd" = ( /obj/item/kirbyplants{ icon_state = "plant-21" @@ -3709,6 +4043,21 @@ /obj/machinery/light, /turf/open/floor/wood, /area/centcom/ferry) +"ql" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/item/reagent_containers/food/drinks/drinkingglass{ + pixel_x = 4; + pixel_y = 7 + }, +/obj/item/paper/pamphlet/violent_video_games{ + pixel_x = -3; + pixel_y = -3 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) "qo" = ( /obj/structure/table/reinforced, /obj/item/folder, @@ -3723,6 +4072,23 @@ /obj/machinery/light, /turf/open/floor/iron, /area/centcom/supply) +"qp" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/closet/emcloset, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/structure/sign/picture_frame{ + pixel_x = -32 + }, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"qt" = ( +/turf/open/floor/grass, +/area/centcom/evac) "qv" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/fullgrass, @@ -3910,6 +4276,10 @@ }, /turf/open/floor/iron, /area/centcom/supplypod/loading/ert) +"rc" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/sepia, +/area/centcom/evac) "rd" = ( /obj/structure/flora/grass/brown, /obj/effect/light_emitter{ @@ -3951,6 +4321,23 @@ }, /turf/open/floor/iron, /area/centcom/ferry) +"ro" = ( +/obj/structure/window/reinforced/spawner/east, +/obj/structure/window/reinforced/spawner/north, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/obj/structure/table/reinforced, +/obj/item/storage/firstaid/regular{ + pixel_x = -5 + }, +/obj/item/clothing/gloves/color/latex/nitrile, +/obj/item/healthanalyzer{ + pixel_x = 4; + pixel_y = -3 + }, +/turf/open/floor/iron/white/textured_large, +/area/centcom/evac) "rp" = ( /obj/structure/chair/fancy/comfy{ dir = 1 @@ -4014,6 +4401,13 @@ /obj/machinery/photocopier, /turf/open/floor/carpet/grimy, /area/centcom/ferry) +"rx" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/machinery/light/floor, +/obj/effect/turf_decal/trimline/neutral, +/turf/open/floor/iron, +/area/centcom/evac) "rz" = ( /obj/structure/sign/warning/securearea, /turf/closed/indestructible/riveted, @@ -4103,6 +4497,18 @@ name = "sand" }, /area/centcom/supply) +"rG" = ( +/obj/item/trash/boritos{ + pixel_y = -9 + }, +/obj/item/trash/can{ + pixel_y = -9; + pixel_x = -9 + }, +/obj/structure/closet/crate/trashcart, +/obj/effect/decal/cleanable/shreds, +/turf/open/floor/grass, +/area/centcom/evac) "rH" = ( /obj/structure/flora/ausbushes/sparsegrass, /obj/structure/flora/ausbushes/lavendergrass, @@ -4143,6 +4549,22 @@ /obj/structure/flora/ausbushes/pointybush, /turf/open/floor/grass, /area/centcom/control) +"rN" = ( +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/machinery/door/airlock/titanium, +/obj/structure/fans/tiny, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"rP" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) "rS" = ( /obj/machinery/status_display/evac, /turf/closed/indestructible/riveted, @@ -4177,6 +4599,15 @@ }, /turf/open/floor/engine/cult, /area/wizard_station) +"rZ" = ( +/obj/structure/railing/corner, +/obj/structure/railing/corner{ + dir = 4 + }, +/turf/open/floor/iron/stairs{ + dir = 4 + }, +/area/centcom/evac) "sa" = ( /obj/structure/table/wood, /obj/item/lighter, @@ -4187,6 +4618,11 @@ /obj/machinery/vending/snack, /turf/open/floor/iron, /area/centcom/supplypod) +"sc" = ( +/obj/machinery/computer/crew, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/evac) "sd" = ( /obj/machinery/door/airlock/centcom{ name = "Orbital Drop Pod Loading"; @@ -4194,6 +4630,12 @@ }, /turf/open/floor/iron, /area/centcom/ferry) +"sf" = ( +/obj/structure/flora/grass/jungle{ + icon_state = "grassb4" + }, +/turf/open/floor/grass, +/area/centcom/evac) "si" = ( /obj/structure/table/wood, /obj/item/reagent_containers/food/drinks/shaker, @@ -4284,6 +4726,23 @@ /obj/item/stamp/law, /turf/open/floor/carpet/grimy, /area/centcom/control) +"sx" = ( +/obj/structure/table/reinforced, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/item/storage/secure/briefcase{ + pixel_y = 11 + }, +/obj/item/restraints/handcuffs/cable/zipties, +/obj/item/assembly/flash/handheld, +/obj/structure/extinguisher_cabinet{ + pixel_x = -26; + pixel_y = 1 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "sz" = ( /obj/structure/chair/office{ dir = 4 @@ -4312,6 +4771,13 @@ }, /turf/open/floor/iron, /area/centcom/ferry) +"sG" = ( +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/ferry) "sH" = ( /obj/machinery/door/airlock/vault{ name = "Vault Door"; @@ -4476,6 +4942,11 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"tm" = ( +/obj/effect/decal/cleanable/cobweb, +/obj/structure/flora/ausbushes, +/turf/open/floor/grass, +/area/centcom/evac) "tn" = ( /obj/effect/turf_decal/stripes/line{ dir = 10 @@ -4525,23 +4996,10 @@ }, /turf/open/floor/iron/dark, /area/ctf) -"tx" = ( -/obj/structure/table/reinforced, -/obj/item/radio{ - pixel_x = 5; - pixel_y = 5 - }, -/obj/item/radio{ - pixel_x = -5; - pixel_y = 5 - }, -/obj/item/radio, -/obj/machinery/airalarm/directional/north{ - pixel_y = 23 - }, -/obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron, -/area/centcom/control) +"ty" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood/big, +/area/centcom/evac) "tz" = ( /obj/structure/chair/office{ dir = 4 @@ -4662,6 +5120,17 @@ /obj/structure/sign/warning/securearea, /turf/closed/indestructible/riveted, /area/centcom/control) +"tQ" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 6 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/airalarm/directional/south, +/turf/open/floor/wood/big, +/area/centcom/evac) "tR" = ( /obj/machinery/status_display/ai, /turf/closed/indestructible/riveted, @@ -4708,12 +5177,6 @@ }, /turf/open/floor/engine/cult, /area/wizard_station) -"tY" = ( -/obj/machinery/computer/secure_data{ - dir = 8 - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "ua" = ( /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ dir = 8 @@ -4725,6 +5188,30 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/evac) +"uc" = ( +/obj/structure/closet/secure_closet/personal/cabinet, +/obj/item/clothing/under/rank/civilian/curator/treasure_hunter, +/obj/item/clothing/under/dress/skirt, +/obj/item/clothing/under/shorts/black, +/obj/item/clothing/under/pants/track, +/obj/item/clothing/accessory/armband/deputy, +/obj/item/clothing/accessory/waistcoat, +/obj/item/clothing/shoes/jackboots, +/obj/item/clothing/shoes/laceup, +/obj/item/clothing/neck/stripedredscarf, +/obj/item/clothing/neck/tie/red, +/obj/item/clothing/head/helmet/space/beret, +/obj/item/clothing/suit/jacket/curator, +/obj/item/clothing/suit/space/officer, +/obj/item/clothing/gloves/fingerless, +/obj/item/clothing/gloves/color/black, +/obj/item/clothing/glasses/eyepatch, +/obj/machinery/firealarm{ + dir = 4; + pixel_x = -24 + }, +/turf/open/floor/carpet/grimy, +/area/centcom/ferry) "ud" = ( /obj/machinery/door/poddoor/shutters{ id = "nukeop_ready"; @@ -4778,6 +5265,23 @@ }, /turf/open/floor/plating/airless, /area/syndicate_mothership/control) +"uk" = ( +/obj/structure/table/reinforced, +/obj/item/radio{ + pixel_x = 5; + pixel_y = 5 + }, +/obj/item/radio{ + pixel_x = -5; + pixel_y = 5 + }, +/obj/item/radio, +/obj/machinery/airalarm/directional/north{ + pixel_y = 23 + }, +/obj/effect/turf_decal/stripes/line, +/turf/open/floor/iron, +/area/centcom/control) "ul" = ( /obj/machinery/computer/emergency_shuttle{ dir = 1 @@ -4799,18 +5303,13 @@ }, /turf/open/floor/iron, /area/centcom/ferry) -"un" = ( -/obj/structure/table/wood, -/obj/item/folder/red, -/obj/item/book/manual/wiki/security_space_law, -/obj/item/restraints/handcuffs, -/obj/item/assembly/flash/handheld, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 +"uo" = ( +/obj/item/kirbyplants{ + icon_state = "plant-21" }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/ferry) +/obj/machinery/airalarm/directional/west, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "ur" = ( /obj/structure/cable/white{ icon_state = "1-2" @@ -4823,6 +5322,16 @@ }, /turf/open/floor/wood, /area/centcom/ferry) +"uw" = ( +/obj/structure/table/wood, +/obj/item/paper_bin, +/obj/item/pen/fourcolor, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "uz" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -4841,6 +5350,9 @@ }, /turf/open/floor/iron, /area/centcom/evac) +"uB" = ( +/turf/open/floor/carpet/red, +/area/centcom/evac) "uC" = ( /obj/machinery/computer/camera_advanced/wizard, /turf/open/floor/wood, @@ -4857,6 +5369,19 @@ /obj/structure/chair/wood/wings, /turf/open/floor/carpet, /area/wizard_station) +"uG" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/sign/poster/official/moth9{ + pixel_x = -32 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "uH" = ( /obj/structure/bookcase/random, /obj/machinery/light{ @@ -4881,13 +5406,11 @@ }, /turf/open/floor/plating, /area/syndicate_mothership/control) -"uK" = ( -/obj/machinery/power/smes{ - capacity = 9e+006; - charge = 10000 - }, -/obj/structure/cable, -/turf/open/floor/plating, +"uM" = ( +/obj/machinery/computer/operating, +/obj/effect/turf_decal/stripes/line, +/obj/structure/window/reinforced/spawner/east, +/turf/open/floor/iron/white, /area/centcom/evac) "uO" = ( /obj/machinery/door/airlock/centcom{ @@ -4915,14 +5438,24 @@ }, /turf/open/floor/iron, /area/centcom/ferry) -"uU" = ( -/obj/structure/closet/secure_closet/quartermaster, +"uR" = ( +/obj/structure/flora/tree/palm{ + icon_state = "palm2"; + pixel_x = 1 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"uT" = ( /obj/machinery/airalarm/directional/east{ pixel_x = 24 }, -/obj/effect/turf_decal/bot, -/turf/open/floor/iron, -/area/centcom/supply) +/obj/structure/filingcabinet/filingcabinet, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/ferry) "uY" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -5028,11 +5561,28 @@ }, /turf/open/floor/carpet, /area/wizard_station) +"vo" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/closet/emcloset, +/turf/open/floor/iron/dark/smooth_large, +/area/centcom/evac) "vp" = ( /obj/machinery/vending/cigarette/syndicate, /obj/effect/turf_decal/tile/bar/opposingcorners, /turf/open/floor/iron, /area/syndicate_mothership/control) +"vs" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/structure/sign/poster/official/fruit_bowl{ + pixel_y = -32 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "vt" = ( /obj/structure/rack, /obj/item/nullrod/claymore/katana{ @@ -5147,6 +5697,28 @@ }, /turf/open/floor/iron, /area/centcom/control) +"vK" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/sign/poster/official/moth5{ + pixel_x = 32 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"vN" = ( +/obj/effect/turf_decal/trimline/dark_blue/filled/warning{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/dark_blue/filled/warning{ + dir = 4 + }, +/turf/open/floor/iron/white/textured, +/area/centcom/evac) "vO" = ( /obj/machinery/light{ dir = 4 @@ -5562,6 +6134,12 @@ /obj/effect/turf_decal/tile/green, /turf/open/floor/iron, /area/centcom/control) +"xp" = ( +/obj/item/kirbyplants{ + icon_state = "plant-21" + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "xr" = ( /obj/effect/spawner/structure/window/reinforced, /obj/structure/sign/directions/engineering{ @@ -5877,10 +6455,20 @@ }, /turf/open/floor/iron, /area/centcom/control) +"yt" = ( +/obj/effect/turf_decal/siding/wood/corner, +/turf/open/floor/wood/big, +/area/centcom/evac) "yu" = ( /obj/item/food/meat/slab/human/mutant/lizard, /turf/open/floor/grass, /area/wizard_station) +"yv" = ( +/obj/structure/flora/tree/palm{ + pixel_x = -1 + }, +/turf/open/floor/grass, +/area/centcom/evac) "yy" = ( /obj/machinery/light{ dir = 4 @@ -5898,6 +6486,16 @@ /obj/item/stamp/law, /turf/open/floor/carpet/grimy, /area/centcom/control) +"yA" = ( +/obj/structure/closet/secure_closet/ertEngi, +/obj/machinery/airalarm/directional/north{ + pixel_y = 24 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 6 + }, +/turf/open/floor/iron, +/area/centcom/ferry) "yB" = ( /obj/effect/turf_decal/tile/blue{ dir = 4 @@ -5955,29 +6553,12 @@ /obj/effect/decal/cleanable/blood/splatter, /turf/open/floor/grass, /area/wizard_station) -"yL" = ( -/obj/machinery/power/port_gen/pacman, -/obj/structure/cable/yellow, -/obj/item/stack/sheet/mineral/plasma{ - amount = 30 - }, -/obj/item/wrench, -/turf/open/floor/plating, -/area/centcom/evac) "yM" = ( /obj/structure/table/wood/bar, /obj/structure/safe/floor, /obj/item/seeds/cherry/bomb, /turf/open/floor/wood, /area/centcom/holding) -"yO" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/bed, -/obj/item/bedsheet/medical, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "yR" = ( /obj/machinery/computer/card/centcom{ dir = 8 @@ -6041,16 +6622,14 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) -"zc" = ( -/obj/structure/bed, -/obj/item/bedsheet/black, -/obj/machinery/door/window/northright{ - name = "Cell"; - req_access_txt = "103" - }, -/obj/machinery/light, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) +"zb" = ( +/obj/structure/rack, +/obj/item/storage/box/donkpockets, +/obj/item/storage/box/donkpockets, +/obj/item/clothing/head/utility/chefhat, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/tdome/tdomeobserve) "ze" = ( /obj/structure/closet/secure_closet/ertEngi, /obj/structure/sign/directions/engineering{ @@ -6119,13 +6698,6 @@ }, /turf/open/floor/iron, /area/centcom/evac) -"zm" = ( -/obj/structure/table/reinforced, -/obj/item/toy/plush/lizard_plushie/green{ - name = "Escapes-On-Pods" - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "zo" = ( /obj/structure/destructible/cult/tome, /turf/open/floor/engine/cult, @@ -6180,6 +6752,18 @@ /obj/effect/turf_decal/tile/blue, /turf/open/floor/iron, /area/centcom/control) +"zH" = ( +/obj/machinery/computer/monitor, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"zI" = ( +/obj/machinery/vending/boozeomat, +/obj/effect/turf_decal/siding/wood{ + dir = 6 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) "zL" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/fullgrass, @@ -6216,13 +6800,8 @@ }, /turf/open/floor/grass, /area/wizard_station) -"zR" = ( -/obj/machinery/door/window/northright{ - dir = 4; - name = "Brig"; - req_access_txt = "103" - }, -/turf/open/floor/mineral/titanium/yellow, +"zT" = ( +/turf/open/floor/iron/dark/textured, /area/centcom/evac) "zX" = ( /obj/structure/table, @@ -6242,6 +6821,22 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"Ag" = ( +/obj/structure/table, +/obj/item/lighter, +/obj/item/storage/fancy/cigarettes/cigpack_robust{ + pixel_x = 6; + pixel_y = 1 + }, +/obj/item/reagent_containers/food/drinks/britcup{ + pixel_x = -7; + pixel_y = -1 + }, +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "Ah" = ( /obj/structure/chair/office{ dir = 8 @@ -6368,6 +6963,18 @@ "AN" = ( /turf/open/floor/circuit/green, /area/centcom/ferry) +"AP" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/machinery/sleeper{ + dir = 4 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/iron/white/textured, +/area/centcom/evac) "AQ" = ( /obj/structure/table/reinforced, /obj/item/clipboard, @@ -6492,6 +7099,43 @@ }, /turf/open/floor/iron, /area/centcom/supplypod/loading/two) +"Bn" = ( +/obj/item/trash/can/food/peaches{ + pixel_x = 5; + pixel_y = 12 + }, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) +"Bo" = ( +/obj/machinery/atmospherics/components/unary/portables_connector/visible{ + dir = 1 + }, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/portable_atmospherics/canister/air, +/obj/structure/cable/white{ + icon_state = "1-4" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/ferry) +"Bq" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Br" = ( /obj/machinery/computer/secure_data{ dir = 4 @@ -6504,10 +7148,17 @@ /obj/machinery/computer/libraryconsole/bookmanagement, /turf/open/floor/wood, /area/centcom/holding) -"Bw" = ( -/obj/machinery/computer/pandemic, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) +"Bt" = ( +/obj/docking_port/stationary{ + dir = 4; + dwidth = 2; + height = 7; + name = "recovery ship"; + width = 5; + id = "pod_away" + }, +/turf/open/space/basic, +/area/space) "Bx" = ( /obj/structure/closet/secure_closet/freezer/meat/open, /obj/item/food/meat/rawbacon, @@ -6645,6 +7296,12 @@ }, /turf/open/floor/engine/cult, /area/wizard_station) +"BT" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/sepia, +/area/centcom/evac) "BU" = ( /obj/structure/trap/ctf/red, /obj/effect/turf_decal/tile/red/fourcorners/contrasted, @@ -6676,6 +7333,18 @@ /obj/effect/landmark/ert_spawn, /turf/open/floor/iron/dark, /area/centcom/ferry) +"Cc" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Cd" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -6701,10 +7370,49 @@ "Cm" = ( /turf/open/floor/carpet/grimy, /area/centcom/control) +"Cn" = ( +/obj/structure/table/reinforced, +/obj/item/toy/plush/lizard_plushie/space/green{ + name = "Escapes-on-Pods" + }, +/obj/effect/turf_decal/stripes/line{ + dir = 10 + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "Cp" = ( /obj/structure/statue/uranium/nuke, /turf/open/floor/plating/asteroid/snow/airless, /area/syndicate_mothership) +"Cq" = ( +/obj/machinery/computer/med_data{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/machinery/light{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"Cr" = ( +/obj/structure/table/reinforced, +/obj/item/storage/toolbox/electrical{ + pixel_y = 8; + pixel_x = 4 + }, +/obj/item/storage/toolbox/mechanical, +/obj/effect/turf_decal/stripes/white/line{ + dir = 9 + }, +/obj/machinery/light/small{ + dir = 8 + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "CA" = ( /obj/structure/closet/secure_closet/freezer/meat/open, /obj/item/food/fishmeat/carp, @@ -6786,6 +7494,11 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/control) +"CI" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/turf/open/floor/iron, +/area/centcom/evac) "CJ" = ( /obj/structure/chair, /obj/effect/turf_decal/tile/green{ @@ -6800,6 +7513,18 @@ }, /turf/open/floor/iron, /area/centcom/control) +"CN" = ( +/obj/item/gun/energy/pulse/carbine/loyalpin, +/obj/item/flashlight/seclite, +/obj/structure/table/reinforced, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 1 + }, +/turf/open/floor/iron, +/area/centcom/ferry) "CQ" = ( /obj/item/scalpel{ pixel_y = 12 @@ -6831,6 +7556,17 @@ /obj/item/paper/fluff/stations/centcom/disk_memo, /turf/open/floor/wood, /area/syndicate_mothership/control) +"CU" = ( +/obj/structure/table/reinforced, +/obj/item/clipboard, +/obj/item/folder/white, +/obj/item/pen/blue, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/control) "CV" = ( /obj/structure/chair/stool, /turf/open/floor/wood, @@ -6859,17 +7595,28 @@ }, /turf/open/floor/iron, /area/centcom/control) +"Da" = ( +/obj/structure/chair/fancy/shuttle{ + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"De" = ( +/obj/docking_port/stationary{ + dir = 8; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_5_away" + }, +/turf/open/space/basic, +/area/space) "Di" = ( /turf/closed/indestructible/riveted, /area/ai_multicam_room) -"Dk" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/fire, -/obj/structure/window{ - dir = 4 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "Dl" = ( /obj/effect/light_emitter, /turf/open/indestructible/binary, @@ -6945,11 +7692,12 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) -"Dy" = ( -/obj/structure/table/glass, -/obj/item/storage/backpack/duffelbag/med/surgery, -/obj/machinery/light, -/turf/open/floor/mineral/titanium/blue, +"Dz" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, /area/centcom/evac) "DC" = ( /obj/machinery/door/airlock{ @@ -7075,6 +7823,12 @@ /obj/effect/turf_decal/tile/green, /turf/open/floor/iron, /area/centcom/control) +"DY" = ( +/obj/structure/sign/warning/pods{ + pixel_y = -32 + }, +/turf/open/floor/grass, +/area/centcom/evac) "DZ" = ( /obj/item/cautery/alien, /obj/effect/turf_decal/bot, @@ -7188,6 +7942,14 @@ /obj/effect/turf_decal/delivery, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"Et" = ( +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 9 + }, +/obj/effect/turf_decal/trimline/red/corner, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/white, +/area/centcom/evac) "Eu" = ( /obj/structure/table/wood, /obj/item/food/sashimi, @@ -7239,6 +8001,16 @@ icon_state = "wood" }, /area/centcom/holding) +"EE" = ( +/obj/machinery/chem_master/condimaster{ + name = "HoochMaster 2000" + }, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/tdome/tdomeobserve) "EG" = ( /obj/structure/flora/ausbushes/sparsegrass, /obj/structure/flora/ausbushes/lavendergrass, @@ -7274,16 +8046,6 @@ /obj/machinery/status_display/evac, /turf/closed/indestructible/riveted, /area/tdome/tdomeobserve) -"EL" = ( -/obj/structure/filingcabinet/filingcabinet, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 9 - }, -/turf/open/floor/iron, -/area/centcom/supply) "EN" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, @@ -7317,6 +8079,11 @@ /obj/structure/flora/ausbushes/palebush, /turf/open/floor/plating/asteroid, /area/tdome/tdomeobserve) +"EV" = ( +/obj/machinery/door/airlock/titanium/glass, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "EW" = ( /obj/structure/table/wood, /turf/open/floor/engine/cult, @@ -7397,6 +8164,11 @@ /obj/effect/turf_decal/tile/brown/anticorner/contrasted, /turf/open/floor/iron, /area/centcom/supply) +"Fl" = ( +/obj/machinery/door/airlock/maintenance_hatch, +/obj/machinery/door/firedoor, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) "Fm" = ( /obj/structure/table/wood, /obj/item/radio/intercom{ @@ -7463,16 +8235,6 @@ /obj/effect/turf_decal/tile/green, /turf/open/floor/iron, /area/tdome/tdomeobserve) -"Fw" = ( -/obj/structure/closet/secure_closet/ertEngi, -/obj/machinery/airalarm/directional/north{ - pixel_y = 24 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 6 - }, -/turf/open/floor/iron, -/area/centcom/ferry) "FA" = ( /obj/structure/table/wood, /obj/item/dice/d20{ @@ -7624,6 +8386,17 @@ "FX" = ( /turf/open/floor/iron/stairs, /area/centcom/holding) +"FY" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "FZ" = ( /obj/structure/table/reinforced, /obj/item/flashlight/seclite, @@ -7679,6 +8452,16 @@ /obj/effect/turf_decal/loading_area, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"Go" = ( +/obj/structure/tank_dispenser/oxygen, +/obj/effect/turf_decal/stripes/white/line{ + dir = 6 + }, +/obj/structure/window/reinforced/survival_pod{ + dir = 8 + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "Gp" = ( /obj/item/kirbyplants{ icon_state = "plant-21" @@ -7702,18 +8485,6 @@ }, /turf/open/floor/wood, /area/centcom/holding) -"Gt" = ( -/obj/structure/window{ - dir = 8 - }, -/obj/structure/closet/secure_closet/medical3, -/obj/item/storage/firstaid/fire{ - pixel_x = -2; - pixel_y = 4 - }, -/obj/item/storage/firstaid/toxin, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "Gu" = ( /obj/machinery/door/airlock/silver{ name = "Shower" @@ -7767,6 +8538,10 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"GC" = ( +/obj/machinery/airalarm/directional/south, +/turf/open/floor/grass, +/area/centcom/evac) "GE" = ( /obj/effect/turf_decal/tile/red{ dir = 8 @@ -7779,14 +8554,16 @@ /turf/open/floor/iron, /area/tdome/tdomeobserve) "GJ" = ( -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 - }, -/obj/effect/turf_decal/tile/brown/anticorner/contrasted{ +/obj/machinery/iv_drip, +/obj/effect/turf_decal/stripes/line{ dir = 4 }, -/turf/open/floor/iron, -/area/centcom/supply) +/obj/structure/bed/roller, +/obj/structure/sign/poster/official/bless_this_spess{ + pixel_y = 32 + }, +/turf/open/floor/iron/white/textured, +/area/centcom/evac) "GK" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -7810,10 +8587,40 @@ /obj/structure/flora/ausbushes/genericbush, /turf/open/floor/grass, /area/tdome/tdomeobserve) +"GQ" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/extinguisher_cabinet{ + pixel_x = -26; + pixel_y = 1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"GU" = ( +/obj/structure/destructible/cult/tome, +/obj/item/book/codex_gigas, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/ferry) "GV" = ( /obj/effect/turf_decal/tile/green, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"GW" = ( +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/structure/closet/emcloset, +/turf/open/floor/iron/dark/smooth_large, +/area/centcom/evac) "GX" = ( /obj/structure/shuttle/engine/propulsion, /turf/open/space, @@ -7824,6 +8631,26 @@ }, /turf/open/floor/wood, /area/centcom/holding) +"GZ" = ( +/obj/structure/flora/ausbushes/sparsegrass, +/obj/structure/sign/warning/nosmoking{ + pixel_x = 32 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"Ha" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 1 + }, +/obj/effect/turf_decal/stripes/corner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Hb" = ( /obj/structure/sink{ dir = 8; @@ -7837,6 +8664,12 @@ }, /turf/open/floor/iron/white, /area/tdome/tdomeobserve) +"Hd" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/turf/open/floor/sepia, +/area/centcom/evac) "Hh" = ( /obj/structure/sink{ dir = 4; @@ -7892,6 +8725,19 @@ }, /turf/open/floor/iron/white, /area/tdome/tdomeobserve) +"Hr" = ( +/obj/structure/table/wood, +/obj/machinery/chem_dispenser/drinks{ + dir = 8; + pixel_x = 4; + pixel_y = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 5 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood/big, +/area/centcom/evac) "Hx" = ( /obj/structure/sink{ dir = 4; @@ -7967,6 +8813,23 @@ }, /turf/open/space, /area/space) +"HH" = ( +/obj/structure/shuttle/engine/large, +/turf/open/floor/plating, +/area/centcom/evac) +"HJ" = ( +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 10 + }, +/obj/effect/turf_decal/trimline/red/corner{ + dir = 4 + }, +/obj/structure/closet/crate/freezer/blood, +/obj/structure/extinguisher_cabinet{ + pixel_y = -32 + }, +/turf/open/floor/iron/white, +/area/centcom/evac) "HK" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, @@ -7981,6 +8844,15 @@ /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"HL" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) "HM" = ( /obj/structure/chair/fancy/comfy{ dir = 4 @@ -7991,12 +8863,34 @@ /obj/machinery/smartfridge, /turf/closed/indestructible/hotelwall, /area/centcom/holding) +"HO" = ( +/obj/structure/table/reinforced, +/obj/machinery/door/firedoor, +/obj/machinery/door/window/brigdoor{ + base_state = "rightsecure"; + dir = 1; + icon_state = "rightsecure"; + name = "CentCom Customs"; + req_access_txt = "109" + }, +/obj/effect/turf_decal/bot, +/obj/item/toy/plush/lizard_plushie/space/green{ + name = "Escapee" + }, +/turf/open/floor/iron, +/area/centcom/evac) "HP" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, /obj/effect/turf_decal/bot, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"HQ" = ( +/obj/effect/turf_decal/trimline/dark_blue/warning{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "HS" = ( /obj/machinery/door/airlock/centcom{ name = "Thunderdome Locker Room"; @@ -8020,6 +8914,13 @@ /obj/effect/turf_decal/tile/neutral, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"Ib" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/siding/wood/corner, +/obj/machinery/door/airlock/highsecurity, +/obj/machinery/door/firedoor, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Ic" = ( /obj/structure/table/reinforced, /obj/machinery/door/firedoor, @@ -8047,6 +8948,17 @@ }, /turf/open/floor/iron, /area/tdome/tdomeobserve) +"Ii" = ( +/obj/structure/railing{ + dir = 4; + layer = 4.1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/dark{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "Il" = ( /turf/closed/indestructible/fakeglass, /area/tdome/tdomeobserve) @@ -8054,6 +8966,30 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron, /area/centcom/evac) +"Io" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"Ip" = ( +/obj/structure/table/wood, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/item/trash/candy{ + pixel_x = 5 + }, +/obj/item/reagent_containers/food/drinks/drinkingglass{ + pixel_x = -4; + pixel_y = 11 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) +"Iq" = ( +/obj/machinery/door/airlock/titanium/glass, +/obj/machinery/door/firedoor, +/turf/open/floor/sepia, +/area/centcom/evac) "Ir" = ( /obj/effect/turf_decal/tile/green{ dir = 1 @@ -8157,6 +9093,14 @@ /obj/effect/spawner/randomarcade, /turf/open/floor/wood, /area/centcom/holding) +"IK" = ( +/obj/structure/closet/secure_closet/quartermaster, +/obj/machinery/airalarm/directional/east{ + pixel_x = 24 + }, +/obj/effect/turf_decal/bot, +/turf/open/floor/iron, +/area/centcom/supply) "IL" = ( /obj/effect/landmark/thunderdome/one, /obj/effect/turf_decal/stripes/line{ @@ -8296,6 +9240,13 @@ }, /turf/open/floor/iron, /area/tdome/tdomeadmin) +"Jg" = ( +/obj/structure/flora/ausbushes/sparsegrass, +/obj/structure/sign/warning/pods{ + pixel_y = -32 + }, +/turf/open/floor/grass, +/area/centcom/evac) "Jh" = ( /obj/effect/turf_decal/loading_area{ dir = 4 @@ -8474,17 +9425,6 @@ "JI" = ( /turf/closed/indestructible/fakeglass, /area/tdome/tdomeadmin) -"JJ" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/table/glass, -/obj/item/storage/firstaid/regular, -/obj/structure/window{ - dir = 4 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "JL" = ( /obj/structure/rack, /obj/item/clothing/under/color/green, @@ -8505,6 +9445,72 @@ /obj/effect/landmark/abductor/agent, /turf/open/floor/plating/abductor, /area/abductor_ship) +"JP" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/directions/command{ + pixel_x = 32; + pixel_y = 10; + dir = 1 + }, +/obj/structure/sign/directions/engineering{ + pixel_x = 32; + pixel_y = 4; + dir = 1 + }, +/obj/structure/sign/directions/medical{ + pixel_x = 32; + pixel_y = -2; + dir = 1 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"JQ" = ( +/obj/structure/flora/tree/palm{ + icon_state = "palm2"; + pixel_x = 1 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"JR" = ( +/obj/structure/table/wood, +/obj/item/newspaper{ + pixel_x = -4 + }, +/obj/item/newspaper{ + pixel_x = -4; + pixel_y = 2 + }, +/obj/item/newspaper{ + pixel_x = -4; + pixel_y = 4 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 9 + }, +/obj/item/reagent_containers/food/drinks/mug{ + pixel_x = 11; + pixel_y = -2 + }, +/obj/structure/sign/barsign{ + pixel_y = 32 + }, +/obj/item/reagent_containers/food/condiment/saltshaker{ + pixel_x = 12; + pixel_y = 15 + }, +/obj/item/reagent_containers/food/condiment/peppermill{ + pixel_x = 8; + pixel_y = 13 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) "JU" = ( /obj/structure/chair/fancy/comfy{ color = "#596479"; @@ -8512,6 +9518,13 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) +"JV" = ( +/obj/effect/turf_decal/stripes/line, +/obj/structure/cable/yellow{ + icon_state = "1-4" + }, +/turf/open/floor/iron/smooth_edge, +/area/centcom/evac) "JX" = ( /obj/machinery/door/firedoor, /obj/effect/turf_decal/stripes/line{ @@ -8519,13 +9532,6 @@ }, /turf/open/floor/iron, /area/tdome/tdomeadmin) -"Ke" = ( -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/ferry) "Kg" = ( /turf/closed/indestructible/fakedoor{ name = "Thunderdome Admin" @@ -8543,13 +9549,20 @@ /turf/open/floor/iron, /area/tdome/tdomeadmin) "Ki" = ( +/obj/item/storage/firstaid/toxin, +/obj/item/storage/firstaid/o2{ + pixel_x = 3; + pixel_y = 3 + }, +/obj/structure/table/reinforced, /obj/machinery/airalarm/directional/east{ pixel_x = 24 }, -/obj/structure/filingcabinet/filingcabinet, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/ferry) +/obj/effect/turf_decal/tile/blue/opposingcorners{ + dir = 1 + }, +/turf/open/floor/iron/white, +/area/centcom/control) "Kj" = ( /obj/machinery/door/airlock/external{ name = "Backup Emergency Escape Shuttle" @@ -8597,6 +9610,30 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) +"Ks" = ( +/obj/structure/railing{ + dir = 8; + layer = 4.1 + }, +/obj/structure/table/reinforced, +/obj/item/folder/red{ + pixel_x = -2; + pixel_y = -2 + }, +/obj/item/folder/blue{ + pixel_x = 2; + pixel_y = 2 + }, +/obj/item/gun/ballistic/automatic/pistol/m1911{ + pixel_y = 7; + pixel_x = 2 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/dark{ + dir = 8 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "Ku" = ( /obj/machinery/light{ dir = 4 @@ -8606,6 +9643,21 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) +"Kx" = ( +/obj/structure/table/wood, +/obj/item/paper_bin, +/obj/item/pen/fourcolor, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/ferry) +"Kz" = ( +/obj/structure/lattice, +/obj/structure/window/reinforced/spawner, +/turf/open/space/basic, +/area/space/nearstation) "KA" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -8632,6 +9684,13 @@ /obj/machinery/status_display/ai, /turf/closed/indestructible/riveted, /area/tdome/tdomeadmin) +"KE" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/sepia, +/area/centcom/evac) "KG" = ( /obj/structure/flora/ausbushes/lavendergrass, /obj/structure/flora/ausbushes/sparsegrass, @@ -8644,17 +9703,6 @@ "KI" = ( /turf/closed/wall/mineral/titanium/nodiagonal, /area/centcom/evac) -"KJ" = ( -/obj/structure/closet/secure_closet/bar, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"KK" = ( -/obj/structure/filingcabinet/security, -/obj/machinery/light{ - dir = 1 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "KL" = ( /obj/structure/table/reinforced, /obj/item/restraints/handcuffs/cable/zipties, @@ -8662,20 +9710,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"KM" = ( -/obj/effect/spawner/structure/window/shuttle, -/turf/open/floor/plating, -/area/centcom/evac) -"KN" = ( -/obj/docking_port/stationary{ - dwidth = 2; - height = 7; - id = "pod_away"; - name = "recovery ship"; - width = 5 - }, -/turf/open/space/basic, -/area/space) "KO" = ( /obj/item/kirbyplants{ icon_state = "plant-21"; @@ -8685,46 +9719,6 @@ /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, /area/centcom/control) -"KP" = ( -/obj/docking_port/stationary{ - dwidth = 1; - height = 4; - id = "pod2_away"; - name = "recovery ship"; - width = 3 - }, -/turf/open/space/basic, -/area/space) -"KQ" = ( -/obj/docking_port/stationary{ - dwidth = 1; - height = 4; - id = "pod3_away"; - name = "recovery ship"; - width = 3 - }, -/turf/open/space/basic, -/area/space) -"KR" = ( -/obj/docking_port/stationary{ - dwidth = 1; - height = 4; - id = "pod4_away"; - name = "recovery ship"; - width = 3 - }, -/turf/open/space/basic, -/area/space) -"KS" = ( -/obj/docking_port/stationary{ - dwidth = 1; - height = 4; - id = "pod5_away"; - name = "recovery ship"; - width = 3 - }, -/turf/open/space/basic, -/area/space) "KT" = ( /obj/structure/window/reinforced{ dir = 1 @@ -8743,19 +9737,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"KV" = ( -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"KW" = ( -/obj/docking_port/stationary{ - dwidth = 1; - height = 4; - id = "pod6_away"; - name = "recovery ship"; - width = 3 - }, -/turf/open/space/basic, -/area/space) "KX" = ( /obj/structure/chair{ dir = 1 @@ -8763,46 +9744,21 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) -"KY" = ( -/turf/open/space/basic, -/area/centcom/evac) -"KZ" = ( -/obj/structure/shuttle/engine/heater{ - dir = 8 - }, -/obj/structure/cable{ - icon_state = "0-4" - }, -/turf/open/floor/plating, -/area/centcom/evac) -"La" = ( -/obj/structure/cable{ - icon_state = "2-8" - }, -/turf/open/floor/plating, -/area/centcom/evac) -"Lb" = ( -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"Lc" = ( -/obj/machinery/door/airlock/titanium, -/obj/structure/fans/tiny, -/turf/open/floor/plating, -/area/centcom/evac) "Lf" = ( /obj/item/flashlight/lamp, /obj/structure/table/reinforced, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"Lh" = ( -/obj/structure/cable{ - icon_state = "2-8" +"Lg" = ( +/obj/effect/turf_decal/trimline/red/line{ + dir = 8 }, -/obj/structure/cable{ - icon_state = "1-2" +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 4 }, -/turf/open/floor/plating, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/white, /area/centcom/evac) "Li" = ( /obj/item/kirbyplants{ @@ -8821,17 +9777,6 @@ }, /turf/open/floor/iron, /area/centcom/ferry) -"Ll" = ( -/obj/machinery/light{ - dir = 1 - }, -/turf/open/floor/plating, -/area/centcom/evac) -"Lm" = ( -/obj/structure/grille, -/obj/effect/spawner/structure/window/shuttle, -/turf/open/floor/plating, -/area/centcom/evac) "Ln" = ( /obj/item/storage/firstaid/regular, /obj/structure/table, @@ -8840,6 +9785,22 @@ }, /turf/open/floor/iron, /area/centcom/control) +"Lo" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/airalarm/directional/west, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/mob/living/simple_animal/bot/cleanbot{ + on = 0 + }, +/obj/effect/turf_decal/bot_white/right, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Lp" = ( /obj/structure/table/wood, /obj/item/storage/fancy/donut_box, @@ -8879,16 +9840,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"Lu" = ( -/obj/item/kirbyplants{ - icon_state = "plant-22" - }, -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/control) "Lv" = ( /turf/open/floor/plating, /area/centcom/evac) @@ -8898,27 +9849,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) -"Ly" = ( -/obj/machinery/power/terminal{ - dir = 8 - }, -/obj/structure/cable/yellow{ - icon_state = "0-2" - }, -/obj/machinery/light{ - dir = 4 - }, -/turf/open/floor/plating, -/area/centcom/evac) -"Lz" = ( -/obj/structure/table/wood/bar, -/obj/item/reagent_containers/food/drinks/drinkingglass, -/obj/item/reagent_containers/food/drinks/drinkingglass, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"LA" = ( -/turf/closed/wall/mineral/titanium/interior, -/area/centcom/evac) "LB" = ( /obj/machinery/computer/auxillary_base{ pixel_y = 32 @@ -8935,47 +9865,6 @@ /obj/structure/grille, /turf/open/floor/plating, /area/centcom/evac) -"LD" = ( -/obj/machinery/light{ - dir = 1 - }, -/obj/item/kirbyplants/random, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"LE" = ( -/obj/machinery/light{ - dir = 8 - }, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"LF" = ( -/obj/structure/chair/fancy/comfy{ - dir = 4 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"LG" = ( -/obj/structure/shuttle/engine/huge{ - dir = 8 - }, -/turf/open/space/basic, -/area/centcom/evac) -"LH" = ( -/obj/machinery/door/airlock/engineering{ - name = "Engine Room" - }, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"LI" = ( -/obj/machinery/door/airlock/titanium, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"LJ" = ( -/obj/machinery/door/airlock/titanium{ - name = "Cockpit" - }, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) "LK" = ( /obj/machinery/abductor/experiment{ team_number = 2 @@ -8994,34 +9883,6 @@ }, /turf/open/floor/plating/abductor, /area/abductor_ship) -"LN" = ( -/obj/structure/chair{ - dir = 4 - }, -/turf/open/floor/mineral/titanium, -/area/centcom/evac) -"LO" = ( -/obj/machinery/computer{ - dir = 8 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"LP" = ( -/obj/structure/cable{ - icon_state = "1-2" - }, -/turf/open/floor/plating, -/area/centcom/evac) -"LQ" = ( -/obj/structure/table, -/obj/machinery/chem_dispenser/drinks{ - dir = 4 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"LR" = ( -/turf/open/floor/mineral/titanium/yellow, -/area/centcom/evac) "LS" = ( /obj/machinery/computer/camera_advanced/abductor{ team_number = 2 @@ -9293,6 +10154,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"MP" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron, +/area/centcom/evac) "MQ" = ( /obj/item/kirbyplants{ icon_state = "plant-21" @@ -9336,12 +10203,6 @@ /obj/effect/turf_decal/tile/neutral/half/contrasted, /turf/open/floor/iron, /area/tdome/tdomeobserve) -"MX" = ( -/obj/structure/table, -/obj/item/storage/box/donkpockets, -/obj/machinery/light, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "Na" = ( /obj/effect/turf_decal/tile/blue/half/contrasted{ dir = 1 @@ -9381,6 +10242,9 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"Ng" = ( +/turf/open/floor/sepia, +/area/centcom/evac) "Nh" = ( /obj/structure/table/wood, /obj/item/storage/box/drinkingglasses, @@ -9423,6 +10287,22 @@ /obj/item/storage/box/lights/mixed, /turf/open/floor/wood, /area/centcom/holding) +"Nn" = ( +/obj/effect/turf_decal/trimline/dark_blue/filled/warning{ + dir = 8 + }, +/obj/effect/turf_decal/trimline/dark_blue/filled/warning{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/white/textured, +/area/centcom/evac) +"No" = ( +/obj/effect/turf_decal/trimline/dark_blue/warning{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "Nq" = ( /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron, @@ -9431,6 +10311,20 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeadmin) +"Ns" = ( +/obj/structure/flora/grass/jungle, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"Nt" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/machinery/photocopier, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) "Nv" = ( /obj/structure/table, /turf/open/floor/iron/cafeteria, @@ -9446,22 +10340,6 @@ }, /turf/open/floor/wood, /area/centcom/holding) -"Nz" = ( -/obj/structure/table/reinforced, -/obj/machinery/button/door/indestructible{ - id = "XCCsec3"; - name = "CC Main Access Control" - }, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/control) -"NA" = ( -/obj/structure/table/optable, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "NB" = ( /obj/structure/closet/secure_closet/freezer/kitchen, /obj/item/food/grown/banana, @@ -9486,6 +10364,18 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) +"NC" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/item/kirbyplants, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "ND" = ( /obj/structure/table/reinforced, /obj/item/paper_bin, @@ -9614,6 +10504,24 @@ /obj/effect/turf_decal/tile/green/fourcorners/contrasted, /turf/open/floor/iron/white, /area/centcom/holding) +"NW" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) +"NX" = ( +/obj/docking_port/stationary{ + dir = 4; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_4_away" + }, +/turf/open/space/basic, +/area/space) "NY" = ( /obj/machinery/shower{ dir = 4 @@ -9649,6 +10557,14 @@ }, /turf/open/floor/iron/white, /area/centcom/control) +"Of" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/arrows{ + dir = 1 + }, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Og" = ( /obj/machinery/power/emitter/ctf{ dir = 4 @@ -9681,6 +10597,12 @@ /obj/effect/turf_decal/tile/green/fourcorners/contrasted, /turf/open/floor/iron/white, /area/centcom/holding) +"Oo" = ( +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "Op" = ( /obj/structure/sink{ dir = 8; @@ -9694,14 +10616,6 @@ }, /turf/open/floor/iron/white, /area/centcom/holding) -"Or" = ( -/obj/structure/table, -/obj/machinery/chem_dispenser/drinks/beer{ - dir = 4 - }, -/obj/machinery/light, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "Ot" = ( /obj/structure/sink{ dir = 8; @@ -9818,6 +10732,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"ON" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "OP" = ( /obj/effect/turf_decal/delivery, /turf/open/floor/iron, @@ -9850,12 +10775,16 @@ }, /turf/open/floor/iron, /area/centcom/supply) -"OY" = ( -/obj/structure/window{ - dir = 1 +"OZ" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/corner, +/obj/effect/turf_decal/stripes/corner{ + dir = 4 }, -/obj/machinery/stasis, -/turf/open/floor/mineral/titanium/blue, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, /area/centcom/evac) "Pa" = ( /obj/machinery/washing_machine, @@ -9894,6 +10823,20 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) +"Pf" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/warning/nosmoking{ + pixel_x = 32 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Ph" = ( /obj/structure/closet/crate/bin, /turf/open/floor/wood, @@ -9962,6 +10905,18 @@ }, /turf/open/floor/carpet/black, /area/centcom/holding) +"PB" = ( +/obj/structure/table/wood, +/obj/item/folder/red, +/obj/item/book/manual/wiki/security_space_law, +/obj/item/restraints/handcuffs, +/obj/item/assembly/flash/handheld, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/ferry) "PC" = ( /obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/iron, @@ -9991,11 +10946,12 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) -"PJ" = ( -/obj/structure/window{ - dir = 8 +"PK" = ( +/obj/structure/chair/stool/bar{ + dir = 4 }, -/turf/open/floor/mineral/titanium, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/carpet/red, /area/centcom/evac) "PL" = ( /obj/machinery/modular_fabricator/autolathe, @@ -10019,6 +10975,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/supply) +"PP" = ( +/obj/machinery/computer/camera_advanced, +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "PQ" = ( /obj/structure/chair/wood/wings{ dir = 4 @@ -10047,6 +11010,29 @@ /obj/machinery/computer/arcade/battle, /turf/open/floor/wood, /area/centcom/holding) +"PY" = ( +/obj/structure/railing/corner{ + dir = 8 + }, +/obj/structure/railing/corner{ + dir = 1 + }, +/turf/open/floor/iron/stairs{ + dir = 8 + }, +/area/centcom/evac) +"PZ" = ( +/obj/machinery/airalarm/directional/west{ + pixel_x = -23 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 8 + }, +/obj/machinery/light{ + dir = 8 + }, +/turf/open/floor/iron, +/area/centcom/control) "Qc" = ( /obj/machinery/vending/snack, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -10106,6 +11092,19 @@ "Qn" = ( /turf/closed/indestructible/fakeglass, /area/ctf) +"Qo" = ( +/obj/structure/table/reinforced, +/obj/machinery/microwave{ + desc = "Cooks and boils stuff, somehow."; + pixel_x = -3; + pixel_y = 5 + }, +/obj/machinery/airalarm/directional/south{ + pixel_y = -22 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/tdome/tdomeobserve) "Qp" = ( /obj/structure/chair/office{ dir = 4 @@ -10134,11 +11133,52 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeobserve) +"Qr" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"Qs" = ( +/obj/effect/turf_decal/siding/wood/corner{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/wood/big, +/area/centcom/evac) +"Qt" = ( +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 5 + }, +/obj/effect/turf_decal/trimline/red/corner{ + dir = 8 + }, +/turf/open/floor/iron/white, +/area/centcom/evac) "Qu" = ( /obj/structure/bookcase/random, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"Qv" = ( +/obj/structure/table/wood, +/obj/item/storage/fancy/donut_box, +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/obj/structure/window/spawner, +/turf/open/floor/wood/big, +/area/centcom/evac) "Qx" = ( /obj/machinery/door/window/brigdoor{ base_state = "rightsecure"; @@ -10184,6 +11224,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"QE" = ( +/obj/structure/flora/ausbushes/lavendergrass, +/turf/open/floor/grass, +/area/centcom/evac) "QF" = ( /obj/machinery/light, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -10195,31 +11239,12 @@ }, /turf/open/floor/iron, /area/centcom/supply) -"QH" = ( -/obj/structure/table/wood, -/obj/item/paper_bin, -/obj/item/pen/fourcolor, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/ferry) "QI" = ( /obj/structure/toilet{ dir = 4 }, /turf/open/floor/iron/white, /area/centcom/holding) -"QJ" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/brute, -/obj/structure/window{ - dir = 4 - }, -/obj/machinery/light, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "QK" = ( /obj/machinery/light, /obj/effect/turf_decal/tile/red/fourcorners/contrasted, @@ -10232,14 +11257,6 @@ /obj/structure/window/reinforced/fulltile, /turf/open/floor/grass, /area/centcom/holding) -"QM" = ( -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 - }, -/obj/structure/filingcabinet/filingcabinet, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/supply) "QN" = ( /obj/structure/closet/crate/bin, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, @@ -10256,12 +11273,6 @@ /obj/machinery/chem_dispenser/drinks, /turf/closed/indestructible/hotelwall, /area/centcom/holding) -"QU" = ( -/obj/structure/table/glass, -/obj/item/storage/firstaid/o2, -/obj/machinery/light, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "QV" = ( /obj/structure/window/reinforced/spawner/north, /obj/structure/window/reinforced/spawner/east, @@ -10469,18 +11480,6 @@ /obj/structure/fans/tiny, /turf/open/floor/iron, /area/centcom/evac) -"RG" = ( -/obj/item/gun/energy/pulse/carbine/loyalpin, -/obj/item/flashlight/seclite, -/obj/structure/table/reinforced, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/stripes/line{ - dir = 1 - }, -/turf/open/floor/iron, -/area/centcom/ferry) "RK" = ( /obj/structure/table/reinforced, /obj/item/reagent_containers/glass/bottle/charcoal{ @@ -10502,6 +11501,14 @@ }, /turf/open/floor/carpet/black, /area/centcom/holding) +"RN" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/effect/turf_decal/siding/wood{ + dir = 4 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) "RP" = ( /obj/item/storage/box/handcuffs, /obj/item/crowbar/red, @@ -10509,6 +11516,19 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"RQ" = ( +/obj/machinery/portable_atmospherics/canister, +/obj/effect/decal/cleanable/dirt, +/obj/effect/decal/cleanable/glass, +/obj/effect/turf_decal/stripes/white/line{ + dir = 5 + }, +/obj/machinery/firealarm{ + dir = 8; + pixel_x = 24 + }, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "RR" = ( /obj/structure/table/wood, /obj/item/phone{ @@ -10573,6 +11593,43 @@ }, /turf/open/floor/carpet/grimy, /area/centcom/ferry) +"RY" = ( +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 8 + }, +/obj/effect/turf_decal/stripes/line{ + dir = 4 + }, +/obj/structure/sign/directions/medical{ + pixel_x = 32; + pixel_y = -2; + dir = 1 + }, +/obj/structure/sign/directions/command{ + pixel_x = 32; + pixel_y = 10; + dir = 1 + }, +/obj/structure/sign/directions/engineering{ + pixel_x = 32; + pixel_y = 4; + dir = 1 + }, +/obj/structure/closet/firecloset, +/obj/structure/sign/poster/official/anniversary_vintage_reprint{ + pixel_y = -32 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) +"Sb" = ( +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/turf_decal/tile/neutral/opposingcorners, +/obj/effect/decal/cleanable/dirt, +/obj/machinery/light/floor, +/obj/effect/turf_decal/trimline/neutral, +/turf/open/floor/iron, +/area/centcom/evac) "Sc" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 @@ -10600,17 +11657,25 @@ /turf/open/floor/iron, /area/centcom/supplypod/loading/two) "Sj" = ( -/obj/machinery/camera/directional/north{ - c_tag = "Red Team"; - network = list("thunder"); - pixel_x = 11; - pixel_y = -9; - resistance_flags = 64 +/obj/structure/flora/grass/jungle/b, +/obj/item/trash/candy{ + pixel_x = -9; + pixel_y = -7 + }, +/turf/open/floor/grass, +/area/centcom/evac) +"Sk" = ( +/obj/structure/railing{ + dir = 8; + layer = 4.1 }, -/obj/effect/landmark/thunderdome/two, /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron, -/area/tdome/arena) +/obj/effect/turf_decal/siding/dark{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/iron/dark, +/area/centcom/evac) "Sl" = ( /obj/item/cardboard_cutout{ desc = "They seem to be ignoring you... Typical."; @@ -10637,6 +11702,13 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"So" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 10 + }, +/obj/machinery/door/window/westleft, +/turf/open/floor/wood/big, +/area/centcom/evac) "Sp" = ( /obj/effect/turf_decal/tile/blue/anticorner/contrasted{ dir = 8 @@ -10700,6 +11772,13 @@ }, /turf/open/floor/iron/white, /area/centcom/holding) +"SD" = ( +/obj/structure/railing/corner{ + dir = 8 + }, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron/dark, +/area/centcom/evac) "SE" = ( /obj/structure/table/wood, /obj/machinery/chem_dispenser/drinks{ @@ -10763,6 +11842,15 @@ }, /turf/open/floor/iron/dark, /area/ctf) +"SR" = ( +/obj/structure/chair/stool/bar{ + dir = 4 + }, +/obj/machinery/newscaster{ + pixel_y = 32 + }, +/turf/open/floor/carpet/red, +/area/centcom/evac) "SU" = ( /obj/structure/table/wood, /obj/item/camera/detective{ @@ -10775,6 +11863,22 @@ /obj/item/pen/fountain, /turf/open/floor/wood, /area/centcom/holding) +"SV" = ( +/obj/structure/table/reinforced, +/obj/item/storage/box/masks{ + pixel_x = -6; + pixel_y = 4 + }, +/obj/effect/turf_decal/stripes/line, +/obj/item/storage/backpack/duffelbag/med/surgery{ + pixel_x = 2 + }, +/obj/item/storage/pill_bottle/charcoal{ + pixel_x = 7; + pixel_y = 14 + }, +/turf/open/floor/iron/white, +/area/centcom/evac) "SY" = ( /obj/structure/chair, /obj/effect/turf_decal/tile/green/half/contrasted{ @@ -10789,6 +11893,20 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/ferry) +"Ta" = ( +/obj/structure/table/wood, +/obj/machinery/microwave{ + pixel_y = 7 + }, +/obj/effect/turf_decal/siding/wood{ + dir = 5 + }, +/obj/item/storage/box/donkpockets/donkpocketspicy{ + pixel_x = -4; + pixel_y = 4 + }, +/turf/open/floor/wood/big, +/area/centcom/evac) "Tb" = ( /obj/structure/closet/crate/freezer/blood, /turf/open/floor/wood, @@ -10870,10 +11988,6 @@ }, /turf/open/floor/iron, /area/centcom/supplypod) -"Tk" = ( -/obj/structure/table/reinforced, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "Tm" = ( /obj/structure/table/reinforced, /obj/item/folder/red{ @@ -10924,19 +12038,15 @@ /obj/structure/window/reinforced/fulltile, /turf/open/floor/grass, /area/centcom/holding) +"Tv" = ( +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/carpet/red, +/area/centcom/evac) "Ty" = ( /obj/structure/table/reinforced, /obj/item/camera, /turf/open/floor/iron, /area/centcom/supplypod) -"Tz" = ( -/obj/structure/table/optable/abductor, -/obj/effect/light_emitter{ - set_cap = 1; - set_luminosity = 4 - }, -/turf/open/floor/plating/abductor, -/area/abductor_ship) "TA" = ( /obj/structure/table/reinforced, /obj/effect/turf_decal/stripes/line, @@ -10989,6 +12099,16 @@ }, /turf/open/floor/wood, /area/centcom/holding) +"TM" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/sign/poster/official/ian{ + pixel_y = -32 + }, +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 8 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) "TN" = ( /obj/machinery/light{ dir = 1 @@ -11040,15 +12160,30 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"TW" = ( +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/obj/structure/chair/fancy/comfy{ + color = "#666666" + }, +/turf/open/floor/iron/dark, +/area/centcom/evac) "TZ" = ( /obj/effect/turf_decal/tile/brown/anticorner/contrasted{ dir = 8 }, /turf/open/floor/iron, /area/centcom/supplypod/loading/three) -"Ua" = ( -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) +"Uc" = ( +/obj/docking_port/stationary{ + dir = 8; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_8_away" + }, +/turf/open/space/basic, +/area/space) "Ud" = ( /obj/effect/landmark/holding_facility, /turf/open/floor/wood, @@ -11062,14 +12197,6 @@ }, /turf/open/floor/iron, /area/centcom/control) -"Uf" = ( -/obj/structure/bookcase/random, -/obj/machinery/airalarm/directional/south{ - pixel_y = -22 - }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/centcom/control) "Ug" = ( /obj/structure/table/wood, /obj/item/storage/fancy/donut_box, @@ -11151,15 +12278,6 @@ /obj/effect/turf_decal/tile/red/half/contrasted, /turf/open/floor/iron/dark, /area/ctf) -"Uu" = ( -/obj/structure/bed, -/obj/item/bedsheet/black, -/obj/machinery/door/window/northright{ - name = "Cell"; - req_access_txt = "103" - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "Uv" = ( /obj/effect/turf_decal/tile/brown/half/contrasted{ dir = 8 @@ -11216,6 +12334,13 @@ /obj/structure/closet/secure_closet/personal, /turf/open/floor/iron/dark, /area/centcom/supplypod) +"UI" = ( +/obj/effect/turf_decal/siding/wood{ + dir = 8 + }, +/obj/effect/decal/cleanable/dirt, +/turf/open/floor/sepia, +/area/centcom/evac) "UJ" = ( /obj/structure/extinguisher_cabinet{ pixel_y = 32 @@ -11297,11 +12422,6 @@ }, /turf/open/floor/iron/dark, /area/ctf) -"UY" = ( -/obj/structure/table/reinforced, -/obj/item/storage/fancy/donut_box, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "UZ" = ( /obj/machinery/computer/communications{ dir = 8 @@ -11315,15 +12435,15 @@ /turf/open/floor/iron/white, /area/centcom/control) "Va" = ( -/obj/machinery/chem_master/condimaster{ - name = "HoochMaster 2000" +/obj/effect/turf_decal/siding/wideplating_new/dark{ + dir = 4 }, -/obj/machinery/airalarm/directional/east{ - pixel_x = 24 +/obj/effect/turf_decal/stripes/line{ + dir = 8 }, -/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, -/turf/open/floor/iron/dark, -/area/tdome/tdomeobserve) +/obj/effect/turf_decal/tile/neutral/fourcorners, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Vd" = ( /obj/structure/chair/fancy/comfy{ color = "#596479" @@ -11375,6 +12495,19 @@ }, /turf/open/floor/iron/white, /area/tdome/tdomeobserve) +"Vr" = ( +/obj/effect/turf_decal/trimline/red/corner{ + dir = 1 + }, +/obj/effect/turf_decal/trimline/dark_blue/filled/line{ + dir = 6 + }, +/obj/structure/sign/poster/official/enlist{ + pixel_y = -32 + }, +/mob/living/simple_animal/bot/medbot/filled, +/turf/open/floor/iron/white, +/area/centcom/evac) "Vs" = ( /obj/structure/closet/secure_closet/security, /obj/item/storage/belt/security/full, @@ -11405,6 +12538,12 @@ /obj/machinery/reagentgrinder, /turf/open/floor/iron/cafeteria, /area/centcom/holding) +"Vw" = ( +/obj/machinery/light/floor, +/obj/effect/turf_decal/tile/neutral/fourcorners, +/obj/effect/turf_decal/trimline/neutral, +/turf/open/floor/iron/dark/textured_large, +/area/centcom/evac) "Vx" = ( /obj/effect/turf_decal/tile/blue/half/contrasted, /turf/open/floor/iron/dark, @@ -11502,6 +12641,25 @@ }, /turf/open/floor/iron/dark, /area/ctf) +"VP" = ( +/obj/structure/rack, +/obj/structure/window/reinforced/spawner/north, +/obj/item/storage/firstaid/fire{ + pixel_x = -6; + pixel_y = 6 + }, +/obj/item/storage/firstaid/brute{ + pixel_x = 6; + pixel_y = 6 + }, +/obj/item/storage/firstaid/o2{ + pixel_x = -6 + }, +/obj/item/storage/firstaid/toxin{ + pixel_x = 6 + }, +/turf/open/floor/iron/white/textured, +/area/centcom/evac) "VS" = ( /obj/structure/table/wood, /obj/machinery/door/window, @@ -11574,6 +12732,17 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"Wf" = ( +/obj/docking_port/stationary{ + dir = 4; + dwidth = 1; + height = 5; + name = "recovery ship"; + width = 3; + id = "pod_3_away" + }, +/turf/open/space/basic, +/area/space) "Wg" = ( /obj/machinery/computer/arena{ arena_id = "thunderdome" @@ -11633,6 +12802,18 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/centcom/control) +"Ws" = ( +/obj/machinery/camera/directional/north{ + c_tag = "Green Team"; + network = list("thunder"); + pixel_x = 12; + pixel_y = -10; + resistance_flags = 64 + }, +/obj/effect/landmark/thunderdome/one, +/obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, +/turf/open/floor/iron, +/area/tdome/arena) "Wu" = ( /obj/item/storage/briefcase{ pixel_x = -3; @@ -11673,6 +12854,11 @@ /obj/machinery/recharger, /turf/open/floor/plating/abductor, /area/abductor_ship) +"WC" = ( +/obj/effect/decal/cleanable/dirt, +/obj/structure/shuttle/engine/heater, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) "WE" = ( /obj/effect/turf_decal/tile/green/half/contrasted, /turf/open/floor/iron, @@ -11691,20 +12877,6 @@ }, /turf/open/floor/iron/dark, /area/ctf) -"WI" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/structure/table/glass, -/obj/item/storage/firstaid/regular{ - pixel_x = -2; - pixel_y = 4 - }, -/obj/item/storage/firstaid/regular{ - pixel_x = 2 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "WJ" = ( /obj/machinery/door/airlock/centcom{ name = "Thunderdome Administration"; @@ -11771,25 +12943,10 @@ }, /turf/open/floor/iron, /area/centcom/ferry) -"WT" = ( -/obj/structure/window{ - dir = 1 - }, -/obj/machinery/sleeper{ - dir = 8 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "WU" = ( /obj/effect/turf_decal/tile/brown/anticorner/contrasted, /turf/open/floor/iron, /area/centcom/supplypod/loading/two) -"WW" = ( -/obj/structure/table, -/obj/item/paper_bin, -/obj/item/pen, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) "WX" = ( /obj/effect/turf_decal/tile/blue/opposingcorners{ dir = 1 @@ -11888,12 +13045,6 @@ /obj/effect/turf_decal/tile/neutral/fourcorners/contrasted, /turf/open/floor/iron/dark, /area/tdome/tdomeadmin) -"Xq" = ( -/obj/structure/window/plasma/reinforced{ - dir = 4 - }, -/turf/open/floor/mineral/titanium/yellow, -/area/centcom/evac) "Xr" = ( /obj/structure/chair, /obj/effect/landmark/thunderdome/observe, @@ -12326,21 +13477,8 @@ }, /turf/open/floor/wood, /area/centcom/holding) -"YX" = ( -/obj/structure/table/wood/bar, -/obj/item/reagent_containers/food/drinks/drinkingglass, -/obj/item/reagent_containers/food/drinks/drinkingglass, -/obj/item/reagent_containers/food/drinks/shaker{ - pixel_x = -12 - }, -/turf/open/floor/mineral/titanium/blue, -/area/centcom/evac) -"YZ" = ( -/obj/structure/chair/stool/bar{ - can_buckle = 1; - name = "buckleable bar stool" - }, -/turf/open/floor/mineral/titanium/yellow, +"YY" = ( +/turf/open/floor/catwalk_floor/iron_smooth, /area/centcom/evac) "Za" = ( /obj/machinery/door/airlock/wood{ @@ -12474,6 +13612,16 @@ }, /turf/open/floor/wood, /area/centcom/holding) +"Zy" = ( +/obj/effect/turf_decal/trimline/dark_blue/line{ + dir = 4 + }, +/turf/open/floor/iron/dark/textured, +/area/centcom/evac) +"ZB" = ( +/obj/machinery/power/smes/magical, +/turf/open/floor/iron/smooth_large, +/area/centcom/evac) "ZC" = ( /obj/structure/table/wood, /obj/item/paper_bin, @@ -12540,12 +13688,6 @@ /obj/effect/turf_decal/tile/brown/half/contrasted, /turf/open/floor/iron, /area/centcom/supplypod/loading/one) -"ZR" = ( -/obj/structure/window/plasma/reinforced{ - dir = 1 - }, -/turf/open/floor/mineral/plastitanium/red, -/area/centcom/evac) "ZT" = ( /mob/living/simple_animal/cow, /turf/open/floor/grass, @@ -12571,6 +13713,10 @@ }, /turf/open/floor/iron, /area/centcom/supply) +"ZY" = ( +/obj/structure/marker_beacon, +/turf/open/floor/catwalk_floor/iron_smooth, +/area/centcom/evac) "ZZ" = ( /obj/effect/turf_decal/tile/red/fourcorners/contrasted, /turf/open/floor/iron/dark, @@ -14016,7 +15162,7 @@ Rk kq kN li -Tz +lE li mu nd @@ -14043,7 +15189,7 @@ Rk kq Av li -Tz +lE li mu nd @@ -14073,7 +15219,7 @@ Rk kq JB li -Tz +lE li mu nd @@ -14100,7 +15246,7 @@ Rk kq LL li -Tz +lE li mu nd @@ -37743,9 +38889,9 @@ aa aa aa aa -KY -KY -LG +aa +aa +aa aa aa aa @@ -37999,11 +39145,11 @@ aa aa aa aa -LA -LA -LA -LA -LA +aa +aa +aa +aa +aa aa aa aa @@ -38255,13 +39401,13 @@ aa aa aa aa -LA -LA -Lv -Lv -Lv -LA -LA +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -38511,15 +39657,15 @@ aa aa aa aa -LA -LA -Lv -KZ -KZ -KZ -Lv -LA -LA +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -38767,17 +39913,17 @@ aa aa aa aa -LA -LA -Ll -Lv -La -Lh -Lh -LP -uK -LA -LA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -39023,18 +40169,18 @@ aa aa aa aa -LA -LA -LA -Lm -Lm -LA -Lv -Lv -Lv -Ly -yL -LA +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -39280,18 +40426,18 @@ aa aa aa aa -KI -LA aa aa aa -LA -LA -LH -LA -LA -LA -LA +aa +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -39542,13 +40688,13 @@ aa aa aa aa -LA -LD -KV -LQ -cc -Or -LA +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -39799,13 +40945,13 @@ aa aa aa aa -Ls -Lb -KV -LR -LR -LR -LC +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -40055,14 +41201,14 @@ aa aa aa aa -KN -Lc -KV -KV -YZ -YX -YZ -LC +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -40313,13 +41459,13 @@ aa aa aa aa -Ls -Lb -KV -YZ -Lz -YZ -LC +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -40570,13 +41716,13 @@ aa aa aa aa -LC -LD -KV -YZ -Lz -YZ -Lm +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -40827,13 +41973,13 @@ aa aa aa aa -Ls -Lb -KV -YZ -Lz -YZ -LC +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -41083,14 +42229,14 @@ aa aa aa aa -KP -Lc -KV -KV -Xq -zR -Xq -LC +aa +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -41341,13 +42487,13 @@ aa aa aa aa -Ls -Lb -KV -ft -Ua -zc -LA +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -41598,13 +42744,13 @@ aa aa aa aa -LC -LD -KV -zm -Ua -bG -du +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -41855,13 +43001,13 @@ aa aa aa aa -Ls -Lb -KV -UY -Ua -Uu -LA +aa +aa +aa +aa +aa +aa +aa aa aa aa @@ -42111,14 +43257,6 @@ aa aa aa aa -KQ -Lc -KV -KV -de -Ua -bG -LC aa aa aa @@ -42130,9 +43268,6 @@ aa aa aa aa -"} -(116,1,1) = {" -aa aa aa aa @@ -42141,6 +43276,8 @@ aa aa aa aa +"} +(116,1,1) = {" aa aa aa @@ -42369,13 +43506,6 @@ aa aa aa aa -Ls -Lb -KV -Tk -Ua -Uu -LA aa aa aa @@ -42387,10 +43517,6 @@ aa aa aa aa -"} -(117,1,1) = {" -aa -aa aa aa aa @@ -42407,6 +43533,8 @@ aa aa aa aa +"} +(117,1,1) = {" aa aa aa @@ -42626,13 +43754,6 @@ aa aa aa aa -LA -LD -KV -ar -tY -ZR -LC aa aa aa @@ -42644,8 +43765,6 @@ aa aa aa aa -"} -(118,1,1) = {" aa aa aa @@ -42671,6 +43790,8 @@ aa aa aa aa +"} +(118,1,1) = {" aa aa aa @@ -42883,13 +44004,6 @@ aa aa aa aa -KI -KI -LI -LA -LA -KI -KI aa aa aa @@ -42901,8 +44015,6 @@ aa aa aa aa -"} -(119,1,1) = {" aa aa aa @@ -42935,6 +44047,8 @@ aa aa aa aa +"} +(119,1,1) = {" aa aa aa @@ -43140,13 +44254,6 @@ aa aa aa aa -LA -LD -KV -yO -KV -co -LC aa aa aa @@ -43158,8 +44265,6 @@ aa aa aa aa -"} -(120,1,1) = {" aa aa aa @@ -43199,6 +44304,8 @@ aa aa aa aa +"} +(120,1,1) = {" aa aa aa @@ -43398,145 +44505,12 @@ aa aa aa Ls -Lb -KV -JJ -KV -QJ -LA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -"} -(121,1,1) = {" -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -ad -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +KI +KI +KI +KI +KI +KI aa aa aa @@ -43587,6 +44561,8 @@ aa aa aa aa +"} +(121,1,1) = {" aa aa aa @@ -43653,14 +44629,6 @@ aa aa aa aa -KR -Lc -KV -KV -yO -KV -co -LC aa aa aa @@ -43672,8 +44640,6 @@ aa aa aa aa -"} -(122,1,1) = {" aa aa aa @@ -43704,6 +44670,7 @@ aa aa aa aa +ad aa aa aa @@ -43793,6 +44760,14 @@ aa aa aa aa +Ls +KI +aW +ow +Cr +WC +gr +HH aa aa aa @@ -43843,6 +44818,8 @@ aa aa aa aa +"} +(122,1,1) = {" aa aa aa @@ -43911,13 +44888,6 @@ aa aa aa aa -Ls -Lb -KV -JJ -KV -Dk -LA aa aa aa @@ -43929,9 +44899,6 @@ aa aa aa aa -"} -(123,1,1) = {" -aa aa aa aa @@ -44050,6 +45017,14 @@ aa aa aa aa +KI +pe +Bn +rP +rP +WC +gr +Lv aa aa aa @@ -44100,6 +45075,8 @@ aa aa aa aa +"} +(123,1,1) = {" aa aa aa @@ -44168,13 +45145,6 @@ aa aa aa aa -LC -LD -KV -yO -KV -co -LC aa aa aa @@ -44186,8 +45156,6 @@ aa aa aa aa -"} -(124,1,1) = {" aa aa aa @@ -44306,6 +45274,14 @@ aa aa aa aa +Ls +KI +KI +RQ +YY +Go +KI +KI aa aa aa @@ -44356,6 +45332,8 @@ aa aa aa aa +"} +(124,1,1) = {" aa aa aa @@ -44425,13 +45403,6 @@ aa aa aa aa -Ls -Lb -KV -cs -KV -QU -LA aa aa aa @@ -44443,8 +45414,6 @@ aa aa aa aa -"} -(125,1,1) = {" aa aa aa @@ -44564,6 +45533,11 @@ aa aa aa aa +KI +KI +ps +KI +KI aa aa aa @@ -44615,6 +45589,8 @@ aa aa aa aa +"} +(125,1,1) = {" aa aa aa @@ -44681,14 +45657,6 @@ aa aa aa aa -KS -Lc -KV -KV -PJ -hM -PJ -LA aa aa aa @@ -44700,8 +45668,6 @@ aa aa aa aa -"} -(126,1,1) = {" aa aa aa @@ -44824,9 +45790,19 @@ aa aa aa aa +nn +Kz +ZY +nn +Kz aa aa aa +Ls +KI +KI +KI +Ls aa aa aa @@ -44870,6 +45846,8 @@ aa aa aa aa +"} +(126,1,1) = {" aa aa aa @@ -44939,13 +45917,6 @@ aa aa aa aa -Ls -Lb -KV -KV -KV -KV -LA aa aa aa @@ -44957,12 +45928,6 @@ aa aa aa aa -"} -(127,1,1) = {" -aa -aa -aa -aa aa aa aa @@ -45082,8 +46047,20 @@ aa aa aa aa +KI +KI +Fl +KI +KI aa aa +Ls +KI +GJ +AP +VP +KI +Ls aa aa aa @@ -45126,6 +46103,8 @@ aa aa aa aa +"} +(127,1,1) = {" aa aa aa @@ -45196,13 +46175,6 @@ aa aa aa aa -LC -LD -KV -cU -dV -Gt -LA aa aa aa @@ -45214,9 +46186,6 @@ aa aa aa aa -"} -(128,1,1) = {" -aa aa aa aa @@ -45334,8 +46303,26 @@ aa aa aa aa +Ls +KI +sx +VB +Nt +KI aa aa +KI +SV +Et +of +dG +HJ +KI +KI +KI +KI +KI +Ls aa aa aa @@ -45373,6 +46360,8 @@ aa aa aa aa +"} +(128,1,1) = {" aa aa aa @@ -45453,13 +46442,6 @@ aa aa aa aa -Ls -Lb -KV -WT -Lb -Bw -LC aa aa aa @@ -45471,8 +46453,6 @@ aa aa aa aa -"} -(129,1,1) = {" aa aa aa @@ -45580,17 +46560,41 @@ aa aa aa aa +KI +zH +Da +Io +mN +KI +KI aa +KI +pM +Qt +Lg +Lg +Vr +KI +tm +QE +uR +rG +KI +Ls aa +De aa aa aa +nP aa aa aa +oi aa aa aa +Uc aa aa aa @@ -45613,6 +46617,8 @@ aa aa aa aa +"} +(129,1,1) = {" aa aa aa @@ -45709,14 +46715,6 @@ aa aa aa aa -KW -Lc -KV -KV -WI -Lb -Dy -LC aa aa aa @@ -45728,8 +46726,6 @@ aa aa aa aa -"} -(130,1,1) = {" aa aa aa @@ -45821,6 +46817,43 @@ aa aa aa aa +LC +om +Ii +rZ +mi +uo +KI +KI +KI +uM +Nn +vN +ro +qb +KI +JQ +sf +qt +Sj +Jg +KI +KI +hx +KI +KI +KI +hx +KI +KI +KI +hx +KI +KI +KI +hx +KI +Ls aa aa aa @@ -45841,6 +46874,8 @@ aa aa aa aa +"} +(130,1,1) = {" aa aa aa @@ -45967,13 +47002,6 @@ aa aa aa aa -Ls -Lb -KV -OY -Lb -NA -LC aa aa aa @@ -45985,11 +47013,6 @@ aa aa aa aa -"} -(131,1,1) = {" -aa -aa -aa aa aa aa @@ -46051,6 +47074,43 @@ aa aa aa aa +LC +PP +Oo +No +Oo +TM +KI +vo +KI +hY +Io +Io +TW +ew +LC +aL +UI +Hd +Hd +Hd +LC +pp +Ha +oS +GQ +uG +gS +Lo +NC +FY +gS +Va +kJ +GQ +Ha +qp +KI aa aa aa @@ -46071,6 +47131,8 @@ aa aa aa aa +"} +(131,1,1) = {" aa aa aa @@ -46224,13 +47286,6 @@ aa aa aa aa -LA -LD -KV -ao -Lb -aM -LA aa aa aa @@ -46242,8 +47297,6 @@ aa aa aa aa -"} -(132,1,1) = {" aa aa aa @@ -46278,6 +47331,43 @@ aa aa aa aa +LC +hV +bO +zT +kH +zT +lo +Vw +Ib +NW +NW +RN +RN +HL +Iq +Ng +rc +rc +rc +rc +EV +Of +rx +CI +Dz +ek +Sb +CI +CI +ek +qa +Dz +MP +ek +Sb +MP +KI aa aa aa @@ -46298,6 +47388,8 @@ aa aa aa aa +"} +(132,1,1) = {" aa aa aa @@ -46476,18 +47568,9 @@ aa aa aa aa -KI -LA aa aa aa -LA -LA -LJ -LA -LA -LA -LA aa aa aa @@ -46499,14 +47582,49 @@ aa aa aa aa -"} -(133,1,1) = {" aa aa aa aa aa aa +LC +pk +Ag +HQ +Zy +Zy +KI +GW +KI +oP +uB +Tv +Tv +pR +LC +dW +BT +KE +KE +BT +LC +iq +OZ +Pf +ON +JP +Bq +en +Qr +vK +OZ +ON +ON +ON +Cc +RY +KI aa aa aa @@ -46527,6 +47645,8 @@ aa aa aa aa +"} +(133,1,1) = {" aa aa aa @@ -46666,12 +47786,6 @@ aa aa aa aa -oe -oe -nT -nU -oe -oe aa aa aa @@ -46698,6 +47812,12 @@ aa aa aa aa +oe +oe +nT +nU +oe +oe aa aa aa @@ -46725,6 +47845,43 @@ aa aa aa aa +LC +Ks +Sk +PY +mq +xp +KI +KI +KI +SR +PK +PK +ml +vs +KI +yv +qt +or +qt +DY +KI +KI +rN +KI +KI +KI +rN +KI +KI +KI +rN +KI +KI +KI +rN +KI +Ls aa aa aa @@ -46733,17 +47890,6 @@ aa aa aa aa -LA -LA -LA -Lm -Lm -LA -LE -KV -KV -WW -LA aa aa aa @@ -46956,17 +48102,41 @@ aa aa aa aa +KI +sc +Da +Io +SD +KI +KI aa +KI +JR +Ip +ql +Qv +So +KI +Ns +GZ +pc +GC +KI +Ls aa +NX aa aa aa +Wf aa aa aa +cD aa aa aa +Bt aa aa aa @@ -46989,30 +48159,6 @@ aa aa aa aa -aa -aa -LA -KJ -KV -KV -KV -KV -LN -LN -MX -LA -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa "} (135,1,1) = {" aa @@ -47213,8 +48359,26 @@ aa aa aa aa +Ls +KI +Cq +VB +bo +KI aa aa +KI +Ta +Qs +ty +yt +tQ +KI +KI +KI +KI +KI +Ls aa aa aa @@ -47248,24 +48412,6 @@ aa aa aa aa -LA -KK -LF -LF -LF -LF -LO -cH -er -LA -aa -aa -aa -aa -aa -aa -aa -aa aa aa aa @@ -47471,8 +48617,20 @@ aa aa aa aa +KI +KI +Fl +KI +KI aa aa +Ls +KI +Hr +dB +zI +KI +Ls aa aa aa @@ -47505,18 +48663,6 @@ aa aa aa aa -LA -LA -KM -KM -KM -KM -KM -KM -LA -LA -aa -aa aa aa aa @@ -47728,19 +48874,19 @@ aa aa aa aa +nn +Kz +ZY +nn +Kz aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa -aa -aa +Ls +KI +KI +KI +Ls aa aa aa @@ -47985,11 +49131,11 @@ aa aa aa aa -aa -aa -aa -aa -aa +KI +KI +ps +KI +KI aa aa aa @@ -48240,14 +49386,14 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa +Ls +KI +KI +bV +rP +iY +KI +KI aa aa aa @@ -48466,7 +49612,7 @@ aa aa aa mD -Ki +uT Mq az Yg @@ -48497,14 +49643,14 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa +KI +ZB +eK +JV +rP +WC +gr +HH aa aa aa @@ -48754,14 +49900,14 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa -aa +Ls +KI +eG +oc +Cn +WC +gr +Lv aa aa aa @@ -49012,13 +50158,13 @@ aa aa aa aa -aa -aa -aa -aa -aa -aa -aa +Ls +KI +KI +KI +KI +KI +KI aa aa aa @@ -49235,7 +50381,7 @@ wq Xm uH hz -un +PB mD rs OQ @@ -50012,7 +51158,7 @@ bv GA bX ge -QH +Kx mD ss Xb @@ -50795,7 +51941,7 @@ bM AN fk df -Ke +sG mD aa aa @@ -51804,12 +52950,12 @@ mD bU Rg Yb -oj +uc ep nU rr go -eS +Bo mD uY oe @@ -52318,7 +53464,7 @@ mD hm dc Rb -kG +GU dp nT rB @@ -52331,7 +53477,7 @@ su xf ts mD -Fw +yA OQ OQ OQ @@ -53094,7 +54240,7 @@ dN qR rD bp -RG +CN mD vb oe @@ -53126,12 +54272,12 @@ Ti bK NR hg -gJ -ml +zb +Qo Ep IB ev -Sj +jX Fg ev Jv @@ -53595,7 +54741,7 @@ kw bl dK iF -QM +pw GB Fk fu @@ -53604,7 +54750,7 @@ os QG bl dK -EL +mp mD mD mD @@ -54397,7 +55543,7 @@ ap FC Xc Tf -Nz +cA io Ep EK @@ -54617,13 +55763,13 @@ ju ju hJ jN -uU +IK jN Uo hJ Fk iF -GJ +na Uo hJ fr @@ -55196,7 +56342,7 @@ JI cj wp Nr -bO +bz Iv IR Iv @@ -57481,7 +58627,7 @@ bL ND Xc MC -eh +CU io Ep EK @@ -57698,7 +58844,7 @@ iT jg iT iT -po +PZ iT iT jR @@ -58461,7 +59607,7 @@ aa aa aa io -tx +uk iD iD iV @@ -58776,7 +59922,7 @@ GN Ep Qf VN -Va +EE Ob SE MH @@ -58785,7 +59931,7 @@ eQ Ep IM BX -pM +Ws RW BX Jy @@ -60034,7 +61180,7 @@ io QD Xc bJ -oS +gx iu fo PC @@ -60045,7 +61191,7 @@ iu Rn UZ aK -hQ +Ki iu lN iu @@ -62340,7 +63486,7 @@ im fm bT Cm -Uf +ds io qx qV @@ -63129,7 +64275,7 @@ yB In At AW -ee +HO fn VB Rl @@ -64899,7 +66045,7 @@ aa io Sz Tg -Lu +nR in Wx hW @@ -64908,7 +66054,7 @@ fh hW OC Xc -pn +uw XC cS io diff --git a/beestation.dme b/beestation.dme index 12a90141e222c..e53193a6feb92 100644 --- a/beestation.dme +++ b/beestation.dme @@ -159,6 +159,7 @@ #include "code\__DEFINES\sound.dm" #include "code\__DEFINES\space.dm" #include "code\__DEFINES\spaceman_dmm.dm" +#include "code\__DEFINES\spatial_gridmap.dm" #include "code\__DEFINES\species.dm" #include "code\__DEFINES\speech_channels.dm" #include "code\__DEFINES\spell.dm" @@ -201,6 +202,7 @@ #include "code\__DEFINES\dcs\signals\signals_global.dm" #include "code\__DEFINES\dcs\signals\signals_lighting.dm" #include "code\__DEFINES\dcs\signals\signals_movable.dm" +#include "code\__DEFINES\dcs\signals\signals_spatial_grid.dm" #include "code\__DEFINES\dcs\signals\signals_turf.dm" #include "code\__DEFINES\dcs\signals\signals_atom\signals_atom.dm" #include "code\__DEFINES\dcs\signals\signals_atom\signals_atom_attack.dm" @@ -281,6 +283,7 @@ #include "code\__HELPERS\roundend.dm" #include "code\__HELPERS\sanitize_values.dm" #include "code\__HELPERS\shell.dm" +#include "code\__HELPERS\spatial_info.dm" #include "code\__HELPERS\stack_trace.dm" #include "code\__HELPERS\stat_helpers.dm" #include "code\__HELPERS\stat_tracking.dm" @@ -464,6 +467,7 @@ #include "code\controllers\subsystem\sound.dm" #include "code\controllers\subsystem\sound_loops.dm" #include "code\controllers\subsystem\sounds.dm" +#include "code\controllers\subsystem\spatial_gridmap.dm" #include "code\controllers\subsystem\stat.dm" #include "code\controllers\subsystem\stickyban.dm" #include "code\controllers\subsystem\sun.dm" @@ -1753,6 +1757,7 @@ #include "code\modules\admin\smites\dchat_democracy.dm" #include "code\modules\admin\smites\fireball.dm" #include "code\modules\admin\smites\floorcluwne.dm" +#include "code\modules\admin\smites\floorcluwne_trauma.dm" #include "code\modules\admin\smites\floorcluwne_stalker.dm" #include "code\modules\admin\smites\forcecryo.dm" #include "code\modules\admin\smites\forcesay.dm" diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm index 1d10a44148fb3..2ef50d8f420b4 100644 --- a/code/__DEFINES/dcs/signals/signals_global.dm +++ b/code/__DEFINES/dcs/signals/signals_global.dm @@ -5,7 +5,11 @@ // global signals // These are signals which can be listened to by any component on any parent // start global signals with "!", this used to be necessary but now it's just a formatting choice -#define COMSIG_GLOB_NEW_Z "!new_z" //! from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args) + +///from base of datum/controller/subsystem/mapping/proc/add_new_zlevel(): (list/args) +#define COMSIG_GLOB_NEW_Z "!new_z" +/// sent after world.maxx and/or world.maxy are expanded: (has_exapnded_world_maxx, has_expanded_world_maxy) +#define COMSIG_GLOB_EXPANDED_WORLD_BOUNDS "!expanded_world_bounds" #define COMSIG_GLOB_VAR_EDIT "!var_edit" //! called after a successful var edit somewhere in the world: (list/args) #define COMSIG_GLOB_EXPLOSION "!explosion" //! called after an explosion happened : (epicenter, devastation_range, heavy_impact_range, light_impact_range, took, orig_dev_range, orig_heavy_range, orig_light_range) #define COMSIG_GLOB_MOB_CREATED "!mob_created" //! mob was created somewhere : (mob) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm index 0ef03a089e156..34ac00a867905 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob.dm @@ -25,6 +25,8 @@ #define COMSIG_MOB_CLIENT_BLOCK_PRE_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE /// From base of /client/Move() #define COMSIG_MOB_CLIENT_MOVED "mob_client_moved" +/// From base of /mob/proc/reset_perspective() : () +#define COMSIG_MOB_RESET_PERSPECTIVE "mob_reset_perspective" /// Should we stop the current living movement attempt #define COMSIG_MOB_CLIENT_BLOCK_PRE_LIVING_MOVE COMPONENT_MOVABLE_BLOCK_PRE_MOVE diff --git a/code/__DEFINES/dcs/signals/signals_spatial_grid.dm b/code/__DEFINES/dcs/signals/signals_spatial_grid.dm new file mode 100644 index 0000000000000..82e69dfcdf8d3 --- /dev/null +++ b/code/__DEFINES/dcs/signals/signals_spatial_grid.dm @@ -0,0 +1,6 @@ +//spatial grid signals + +///Called from base of /datum/controller/subsystem/spatial_grid/proc/enter_cell: (/atom/movable) +#define SPATIAL_GRID_CELL_ENTERED(contents_type) "spatial_grid_cell_entered_[contents_type]" +///Called from base of /datum/controller/subsystem/spatial_grid/proc/exit_cell: (/atom/movable) +#define SPATIAL_GRID_CELL_EXITED(contents_type) "spatial_grid_cell_exited_[contents_type]" diff --git a/code/__DEFINES/important_recursive_contents.dm b/code/__DEFINES/important_recursive_contents.dm index 62be5b38e5398..24cca713c652f 100644 --- a/code/__DEFINES/important_recursive_contents.dm +++ b/code/__DEFINES/important_recursive_contents.dm @@ -1,2 +1,7 @@ +///the area channel of the important_recursive_contents list, everything in here will be sent a signal when their last holding object changes areas +#define RECURSIVE_CONTENTS_AREA_SENSITIVE "recursive_contents_area_sensitive" ///the hearing channel of the important_recursive_contents list, everything in here will count as a hearing atom #define RECURSIVE_CONTENTS_HEARING_SENSITIVE "recursive_contents_hearing_sensitive" +///the client mobs channel of the important_recursive_contents list, everything in here will be a mob with an attached client +///this is given to both a clients mob, and a clients eye, both point to the clients mob +#define RECURSIVE_CONTENTS_CLIENT_MOBS "recursive_contents_client_mobs" diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm index 02832600afeff..1c74f6276cc45 100644 --- a/code/__DEFINES/radio.dm +++ b/code/__DEFINES/radio.dm @@ -128,3 +128,6 @@ #define REQ_DEP_TYPE_ASSISTANCE (1<<0) #define REQ_DEP_TYPE_SUPPLIES (1<<1) #define REQ_DEP_TYPE_INFORMATION (1<<2) + +///give this to can_receive to specify that there is no restriction on what z level this signal is sent to +#define RADIO_NO_Z_LEVEL_RESTRICTION 0 diff --git a/code/__DEFINES/spatial_gridmap.dm b/code/__DEFINES/spatial_gridmap.dm new file mode 100644 index 0000000000000..858abc9d55ba3 --- /dev/null +++ b/code/__DEFINES/spatial_gridmap.dm @@ -0,0 +1,16 @@ +///each cell in a spatial_grid is this many turfs in length and width +#define SPATIAL_GRID_CELLSIZE 17 + +#define SPATIAL_GRID_CELLS_PER_SIDE(world_bounds) ROUND_UP((world_bounds) / SPATIAL_GRID_CELLSIZE) + +#define SPATIAL_GRID_CHANNELS 2 + +//grid contents channels + +///everything that is hearing sensitive is stored in this channel +#define SPATIAL_GRID_CONTENTS_TYPE_HEARING RECURSIVE_CONTENTS_HEARING_SENSITIVE +///every movable that has a client in it is stored in this channel +#define SPATIAL_GRID_CONTENTS_TYPE_CLIENTS RECURSIVE_CONTENTS_CLIENT_MOBS + +///whether movable is itself or containing something which should be in one of the spatial grid channels. +#define HAS_SPATIAL_GRID_CONTENTS(movable) (movable.important_recursive_contents && (movable.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE] || movable.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS])) diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index b024f21c04a24..b37a72da289ea 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -150,7 +150,8 @@ #define INIT_ORDER_MAPPING 50 #define INIT_ORDER_EARLY_ASSETS 48 #define INIT_ORDER_TIMETRACK 47 -#define INIT_ORDER_NETWORKS 45 +#define INIT_ORDER_NETWORKS 45 +#define INIT_ORDER_SPATIAL_GRID 43 #define INIT_ORDER_ECONOMY 40 #define INIT_ORDER_OUTPUTS 35 #define INIT_ORDER_ATOMS 30 @@ -173,7 +174,6 @@ #define INIT_ORDER_MINOR_MAPPING -40 #define INIT_ORDER_PATH -50 #define INIT_ORDER_EXPLOSIONS -69 -#define INIT_ORDER_ELEVATOR -70 #define INIT_ORDER_BAN_CACHE -98 //Near the end, logs the costs of initialize #define INIT_ORDER_INIT_PROFILER -99 diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm index 17464b44dae81..4766b3dfe661e 100644 --- a/code/__DEFINES/tgs.dm +++ b/code/__DEFINES/tgs.dm @@ -1,18 +1,19 @@ // tgstation-server DMAPI +// The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in IETF RFC 2119. -#define TGS_DMAPI_VERSION "7.1.3" +#define TGS_DMAPI_VERSION "7.2.1" // All functions and datums outside this document are subject to change with any version and should not be relied on. // CONFIGURATION -/// Create this define if you want to do TGS configuration outside of this file. +/// Consumers SHOULD create this define if you want to do TGS configuration outside of this file. #ifndef TGS_EXTERNAL_CONFIGURATION -// Comment this out once you've filled in the below. +// Consumers MUST comment this out once you've filled in the below and are not using [TGS_EXTERNAL_CONFIGURATION]. #error TGS API unconfigured -// Uncomment this if you wish to allow the game to interact with TGS 3.. +// Consumers MUST uncomment this if you wish to allow the game to interact with TGS version 3. // This will raise the minimum required security level of your game to TGS_SECURITY_TRUSTED due to it utilizing call()(). //#define TGS_V3_API @@ -52,7 +53,7 @@ #ifndef TGS_FILE2TEXT_NATIVE #ifdef file2text -#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You can fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses +#error Your codebase is re-defining the BYOND proc file2text. The DMAPI requires the native version to read the result of world.Export(). You SHOULD fix this by adding "#define TGS_FILE2TEXT_NATIVE file2text" before your override of file2text to allow the DMAPI to use the native version. This will only be used for world.Export(), not regular file accesses #endif #define TGS_FILE2TEXT_NATIVE file2text #endif @@ -152,16 +153,17 @@ //REQUIRED HOOKS /** - * Call this somewhere in [/world/proc/New] that is always run. This function may sleep! + * Consumers MUST call this somewhere in [/world/proc/New] that is always run. This function may sleep! * * * event_handler - Optional user defined [/datum/tgs_event_handler]. * * minimum_required_security_level: The minimum required security level to run the game in which the DMAPI is integrated. Can be one of [TGS_SECURITY_ULTRASAFE], [TGS_SECURITY_SAFE], or [TGS_SECURITY_TRUSTED]. + * * http_handler - Optional user defined [/datum/tgs_http_handler]. */ -/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE) +/world/proc/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler) return /** - * Call this when your initializations are complete and your game is ready to play before any player interactions happen. + * Consumers MUST call this when world initializations are complete and the game is ready to play before any player interactions happen. * * This may use [/world/var/sleep_offline] to make this happen so ensure no changes are made to it while this call is running. * Afterwards, consider explicitly setting it to what you want to avoid this BYOND bug: http://www.byond.com/forum/post/2575184 @@ -170,12 +172,10 @@ /world/proc/TgsInitializationComplete() return -/// Put this at the start of [/world/proc/Topic]. +/// Consumers MUST run this macro at the start of [/world/proc/Topic]. #define TGS_TOPIC var/tgs_topic_return = TgsTopic(args[1]); if(tgs_topic_return) return tgs_topic_return -/** - * Call this as late as possible in [world/proc/Reboot] (BEFORE ..()). - */ +/// Consumers MUST call this as late as possible in [world/proc/Reboot] (BEFORE ..()). /world/proc/TgsReboot() return @@ -269,7 +269,7 @@ /// The [/datum/tgs_chat_channel] the user was from. var/datum/tgs_chat_channel/channel -/// User definable handler for TGS events. +/// User definable handler for TGS events This abstract version SHOULD be overridden to be used. /datum/tgs_event_handler /// If the handler receieves [TGS_EVENT_HEALTH_CHECK] events. var/receive_health_checks = FALSE @@ -283,7 +283,41 @@ set waitfor = FALSE return -/// User definable chat command. +/// User definable handler for HTTP calls. This abstract version MUST be overridden to be used. +/datum/tgs_http_handler + +/** + * User definable callback for executing HTTP GET requests. + * MUST perform BYOND sleeps while the request is in flight. + * MUST return a [/datum/tgs_http_result]. + * SHOULD log its own errors + * + * url - The full URL to execute the GET request for including query parameters. + */ +/datum/tgs_http_handler/proc/PerformGet(url) + CRASH("[type]/PerformGet not implemented!") + +/// Result of a [/datum/tgs_http_handler] call. MUST NOT be overridden. +/datum/tgs_http_result + /// HTTP response as text + var/response_text + /// Boolean request success flag. Set for any 2XX response code. + var/success + +/** + * Create a [/datum/tgs_http_result]. + * + * * response_text - HTTP response as text. Must be provided in New(). + * * success - Boolean request success flag. Set for any 2XX response code. Must be provided in New(). + */ +/datum/tgs_http_result/New(response_text, success) + if(response_text && !istext(response_text)) + CRASH("response_text was not text!") + + src.response_text = response_text + src.success = success + +/// User definable chat command. This abstract version MUST be overridden to be used. /datum/tgs_chat_command /// The string to trigger this command on a chat bot. e.g `@bot name ...` or `!tgs name ...`. var/name = "" @@ -296,21 +330,27 @@ /** * Process command activation. Should return a [/datum/tgs_message_content] to respond to the issuer with. + * MUST be implemented * - * sender - The [/datum/tgs_chat_user] who issued the command. - * params - The trimmed string following the command `/datum/tgs_chat_command/var/name]. + * * sender - The [/datum/tgs_chat_user] who issued the command. + * * params - The trimmed string following the command `/datum/tgs_chat_command/var/name]. */ /datum/tgs_chat_command/proc/Run(datum/tgs_chat_user/sender, params) CRASH("[type] has no implementation for Run()") -/// User definable chat message. +/// User definable chat message. MUST NOT be overridden. /datum/tgs_message_content - /// The tring content of the message. Must be provided in New(). + /// The string content of the message. Must be provided in New(). var/text /// The [/datum/tgs_chat_embed] to embed in the message. Not supported on all chat providers. var/datum/tgs_chat_embed/structure/embed +/** + * Create a [/datum/tgs_message_content]. + * + * * text - The string content of the message. + */ /datum/tgs_message_content/New(text) ..() if(!istext(text)) @@ -319,7 +359,7 @@ src.text = text -/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/channel#embed-object-embed-structure for details. +/// User definable chat embed. Currently mirrors Discord chat embeds. See https://discord.com/developers/docs/resources/message#embed-object for details. /datum/tgs_chat_embed/structure var/title var/description @@ -331,13 +371,13 @@ /// Colour must be #AARRGGBB or #RRGGBB hex string. var/colour - /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details. + /// See https://discord.com/developers/docs/resources/message#embed-object-embed-image-structure for details. var/datum/tgs_chat_embed/media/image - /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-thumbnail-structure for details. + /// See https://discord.com/developers/docs/resources/message#embed-object-embed-thumbnail-structure for details. var/datum/tgs_chat_embed/media/thumbnail - /// See https://discord.com/developers/docs/resources/channel#embed-object-embed-image-structure for details. + /// See https://discord.com/developers/docs/resources/message#embed-object-embed-video-structure for details. var/datum/tgs_chat_embed/media/video var/datum/tgs_chat_embed/footer/footer @@ -346,7 +386,7 @@ var/list/datum/tgs_chat_embed/field/fields -/// Common datum for similar discord embed medias. +/// Common datum for similar Discord embed medias. /datum/tgs_chat_embed/media /// Must be set in New(). var/url @@ -354,6 +394,7 @@ var/height var/proxy_url +/// Create a [/datum/tgs_chat_embed]. /datum/tgs_chat_embed/media/New(url) ..() if(!istext(url)) @@ -361,13 +402,14 @@ src.url = url -/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-footer-structure for details. +/// See https://discord.com/developers/docs/resources/message#embed-object-embed-footer-structure for details. /datum/tgs_chat_embed/footer /// Must be set in New(). var/text var/icon_url var/proxy_icon_url +/// Create a [/datum/tgs_chat_embed/footer]. /datum/tgs_chat_embed/footer/New(text) ..() if(!istext(text)) @@ -375,16 +417,17 @@ src.text = text -/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-provider-structure for details. +/// See https://discord.com/developers/docs/resources/message#embed-object-embed-provider-structure for details. /datum/tgs_chat_embed/provider var/name var/url -/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-author-structure for details. Must have name set in New(). +/// See https://discord.com/developers/docs/resources/message#embed-object-embed-author-structure for details. Must have name set in New(). /datum/tgs_chat_embed/provider/author var/icon_url var/proxy_icon_url +/// Create a [/datum/tgs_chat_embed/footer]. /datum/tgs_chat_embed/provider/author/New(name) ..() if(!istext(name)) @@ -392,12 +435,15 @@ src.name = name -/// See https://discord.com/developers/docs/resources/channel#embed-object-embed-field-structure for details. Must have name and value set in New(). +/// See https://discord.com/developers/docs/resources/message#embed-object-embed-field-structure for details. /datum/tgs_chat_embed/field + /// Must be set in New(). var/name + /// Must be set in New(). var/value var/is_inline +/// Create a [/datum/tgs_chat_embed/field]. /datum/tgs_chat_embed/field/New(name, value) ..() if(!istext(name)) diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index eaa87c3b502d6..5f17209e041d1 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -290,6 +290,13 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai ///Used for managing KEEP_TOGETHER in [appearance_flags] #define TRAIT_KEEP_TOGETHER "keep-together" +//important_recursive_contents traits +/* + * Used for movables that need to be updated, via COMSIG_ENTER_AREA and COMSIG_EXIT_AREA, when transitioning areas. + * Use [/atom/movable/proc/become_area_sensitive(trait_source)] to properly enable it. How you remove it isn't as important. + */ +#define TRAIT_AREA_SENSITIVE "area-sensitive" +///every hearing sensitive atom has this trait #define TRAIT_HEARING_SENSITIVE "hearing_sensitive" // item traits diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 3be00b32151a3..70428e67f5c20 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -9,90 +9,6 @@ return null return format_text ? format_text(A.name) : A.name -/proc/get_areas_in_range(dist=0, atom/center=usr) - if(!dist) - var/turf/T = get_turf(center) - return T ? list(T.loc) : list() - if(!center) - return list() - - var/list/areas = list() - for(var/turf/T as() in RANGE_TURFS(dist, center)) - areas |= T.loc - return areas - -/proc/get_adjacent_areas(atom/center) - . = list(get_area(get_ranged_target_turf(center, NORTH, 1)), - get_area(get_ranged_target_turf(center, SOUTH, 1)), - get_area(get_ranged_target_turf(center, EAST, 1)), - get_area(get_ranged_target_turf(center, WEST, 1))) - list_clear_nulls(.) - -/proc/get_open_turf_in_dir(atom/center, dir) - var/turf/open/T = get_step(center, dir) - if(istype(T)) - return T - -/proc/get_adjacent_open_turfs(atom/center) - var/list/hand_back = list() - // Inlined get_open_turf_in_dir, just to be fast - var/turf/open/new_turf = get_step(center, NORTH) - if(istype(new_turf)) - hand_back += new_turf - new_turf = get_step(center, SOUTH) - if(istype(new_turf)) - hand_back += new_turf - new_turf = get_step(center, EAST) - if(istype(new_turf)) - hand_back += new_turf - new_turf = get_step(center, WEST) - if(istype(new_turf)) - hand_back += new_turf - return hand_back - -/proc/get_adjacent_open_areas(atom/center) - . = list() - var/list/adjacent_turfs = get_adjacent_open_turfs(center) - for(var/I in adjacent_turfs) - . |= get_area(I) - -/** - * Get a bounding box of a list of atoms. - * - * Arguments: - * - atoms - List of atoms. Can accept output of view() and range() procs. - * - * Returns: list(x1, y1, x2, y2) - */ -/proc/get_bbox_of_atoms(list/atoms) - var/list/list_x = list() - var/list/list_y = list() - for(var/_a in atoms) - var/atom/a = _a - list_x += a.x - list_y += a.y - return list( - min(list_x), - min(list_y), - max(list_x), - max(list_y)) - -// Like view but bypasses luminosity check - -/proc/get_hear(range, atom/source) - return dview(range, source) - -/proc/alone_in_area(area/the_area, mob/must_be_alone, check_type = /mob/living/carbon) - var/area/our_area = get_area(the_area) - for(var/C in GLOB.alive_mob_list) - if(!istype(C, check_type)) - continue - if(C == must_be_alone) - continue - if(our_area == get_area(C)) - return 0 - return 1 - //We used to use linear regression to approximate the answer, but Mloc realized this was actually faster. //And lo and behold, it is, and it's more accurate to boot. /proc/cheap_hypotenuse(Ax,Ay,Bx,By) @@ -128,14 +44,6 @@ //turfs += centerturf return atoms -/proc/get_dist_euclidian(atom/Loc1 as turf|mob|obj,atom/Loc2 as turf|mob|obj) - var/dx = Loc1.x - Loc2.x - var/dy = Loc1.y - Loc2.y - - var/dist = sqrt(dx**2 + dy**2) - - return dist - /proc/circlerangeturfs(center=usr,radius=3) var/turf/centerturf = get_turf(center) @@ -219,13 +127,13 @@ if(client_check && !A_tmp.client) passed=0 - if(sight_check && !isInSight(A_tmp, O)) + if(sight_check && !is_in_sight(A_tmp, O)) passed=0 else if(include_radio && istype(A, /obj/item/radio)) passed=1 - if(sight_check && !isInSight(A, O)) + if(sight_check && !is_in_sight(A, O)) passed=0 if(passed) @@ -240,98 +148,6 @@ return found_mobs -/** - * Returns a list of hearers in view(view_radius) from source (ignoring luminosity). uses important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE] - * vars: - * * view_radius is distance we look for potential hearers - * * source is obviously the source attom from where we start looking - * * invis_flags is for if we want to include invisible mobs or even ghosts etc the default value 0 means only visible mobs are included SEE_INVISIBLE_SPIRIT would also include ghosts. - */ -/proc/get_hearers_in_view(view_radius, atom/source, invis_flags = 0) - var/turf/center_turf = get_turf(source) - . = list() - if(!center_turf) - return - for(var/atom/movable/movable in dview(view_radius, center_turf, invis_flags)) - var/list/recursive_contents = LAZYACCESS(movable.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE) - if(recursive_contents) - . += recursive_contents - -/proc/get_mobs_in_radio_ranges(list/obj/item/radio/radios) - . = list() - // Returns a list of mobs who can hear any of the radios given in @radios - for(var/obj/item/radio/radio in radios) - if(radio.canhear_range != -1) - . |= get_hearers_in_view(radio.canhear_range, radio) - else - var/list/specific_hearers = radio.get_specific_hearers() - if(specific_hearers) - . |= specific_hearers - -#define SIGNV(X) ((X<0)?-1:1) - -/proc/inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5) - var/turf/T - if(X1==X2) - if(Y1==Y2) - return 1 //Light cannot be blocked on same tile - else - var/s = SIGN(Y2-Y1) - Y1+=s - while(Y1!=Y2) - T=locate(X1,Y1,Z) - if(IS_OPAQUE_TURF(T)) - return 0 - Y1+=s - else - var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1)) - var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles - var/signX = SIGN(X2-X1) - var/signY = SIGN(Y2-Y1) - if(X1 abs (dx)) //slope is above 1:1 (move horizontally in a tie) - if(dy > 0) - return get_step(start, SOUTH) - else - return get_step(start, NORTH) - else - if(dx > 0) - return get_step(start, WEST) - else - return get_step(start, EAST) - - /proc/try_move_adjacent(atom/movable/AM) var/turf/T = get_turf(AM) for(var/direction in GLOB.cardinals) diff --git a/code/__HELPERS/spatial_info.dm b/code/__HELPERS/spatial_info.dm new file mode 100644 index 0000000000000..f8e5282f0815c --- /dev/null +++ b/code/__HELPERS/spatial_info.dm @@ -0,0 +1,386 @@ +/turf + ///what /mob/oranges_ear instance is already assigned to us as there should only ever be one. + ///used for guaranteeing there is only one oranges_ear per turf when assigned, speeds up view() iteration + var/mob/oranges_ear/assigned_oranges_ear + +/** # Oranges Ear + * + * turns out view() spends a significant portion of its processing time generating lists of contents of viewable turfs which includes EVERYTHING on it visible + * and the turf itself. there is an optimization to view() which makes it only iterate through either /obj or /mob contents, as well as normal list typechecking filters + * + * a fuckton of these are generated as part of its SS's init and stored in a list, when requested for a list of movables returned by the spatial grid or by some + * superset of the final output that must be narrowed down by view(), one of these gets put on every turf that contains the movables that need filtering + * and each is given references to the movables they represent. that way you can do for(var/mob/oranges_ear/ear in view(...)) and check what they reference + * as opposed to for(var/atom/movable/target in view(...)) and checking if they have the properties you want which leads to much larger lists generated by view() + * and also leads to iterating through more movables to filter them. + * + * TLDR: iterating through just mobs is much faster than all movables when iterating through view() on average, this system leverages that to boost speed + * enough to offset the cost of allocating the mobs + * + * named because the idea was first made by oranges and i didnt know what else to call it (note that this system was originally made for get_hearers_in_view()) + */ +/mob/oranges_ear + icon_state = null + density = FALSE + move_resist = INFINITY + invisibility = 0 + mouse_opacity = MOUSE_OPACITY_TRANSPARENT + logging = null + held_items = null //all of these are list objects that should not exist for something like us + faction = null + alerts = null + screens = null + client_colours = null + hud_possible = null + /// references to everything "on" the turf we are assigned to, that we care about. populated in assign() and cleared in unassign(). + /// movables iside of other movables count as being "on" if they have get_turf(them) == our turf. intentionally not a lazylist + var/list/references = list() + +/mob/oranges_ear/Initialize(mapload) + SHOULD_CALL_PARENT(FALSE) + if(flags_1 & INITIALIZED_1) + stack_trace("Warning: [src]([type]) initialized multiple times!") + flags_1 |= INITIALIZED_1 + return INITIALIZE_HINT_NORMAL + +/mob/oranges_ear/Destroy(force) + var/old_length = length(SSspatial_grid.pregenerated_oranges_ears) + SSspatial_grid.pregenerated_oranges_ears -= src + if(length(SSspatial_grid.pregenerated_oranges_ears) < old_length) + SSspatial_grid.number_of_oranges_ears -= 1 + + var/turf/our_loc = get_turf(src) + if(our_loc && our_loc.assigned_oranges_ear == src) + our_loc.assigned_oranges_ear = null + + . = ..() + +/mob/oranges_ear/Move() + SHOULD_CALL_PARENT(FALSE) + stack_trace("SOMEHOW A /mob/oranges_ear MOVED") + return FALSE + +/mob/oranges_ear/abstract_move(atom/destination) + SHOULD_CALL_PARENT(FALSE) + stack_trace("SOMEHOW A /mob/oranges_ear MOVED") + return FALSE + +/mob/oranges_ear/Bump() + SHOULD_CALL_PARENT(FALSE) + return FALSE + +///clean this oranges_ear up for future use +/mob/oranges_ear/proc/unassign() + var/turf/turf_loc = loc + turf_loc.assigned_oranges_ear = null//trollface. our loc should ALWAYS be a turf, no exceptions. if it isnt then this doubles as an error message ;) + loc = null + references.Cut() + +/** + * returns every hearaing movable in view to the turf of source not taking into account lighting + * useful when you need to maintain always being able to hear something if a sound is emitted from it and you can see it (and youre in range). + * otherwise this is just a more expensive version of get_hearers_in_LOS() + * + * * view_radius - what radius search circle we are using, worse performance as this increases + * * source - object at the center of our search area. everything in get_turf(source) is guaranteed to be part of the search area + */ +/proc/get_hearers_in_view(view_radius, atom/source) + var/turf/center_turf = get_turf(source) + if(!center_turf) + return + + . = list() + + if(view_radius <= 0)//special case for if only source cares + for(var/atom/movable/target as anything in center_turf) + var/list/recursive_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE] + if(recursive_contents) + . += recursive_contents + return . + + var/list/hearables_from_grid = SSspatial_grid.orthogonal_range_search(source, RECURSIVE_CONTENTS_HEARING_SENSITIVE, view_radius) + + if(!length(hearables_from_grid))//we know that something is returned by the grid, but we dont know if we need to actually filter down the output + return . + + var/list/assigned_oranges_ears = SSspatial_grid.assign_oranges_ears(hearables_from_grid) + + var/old_luminosity = center_turf.luminosity + center_turf.luminosity = 6 //man if only we had an inbuilt dview() + + //this is the ENTIRE reason all this shit is worth it due to how view() and the contents list works and can be optimized + //internally, the contents list is secretly two linked lists, one for /obj's and one for /mob's (/atom/movable counts as /obj here) + //by default, for(var/atom/name in view()) iterates through both the /obj linked list then the /mob linked list of each turf + //but because what we want are only a tiny proportion of all movables, most of the things in the /obj contents list are not what we're looking for + //while every mob can hear. for this case view() has an optimization to only look through 1 of these lists if it can (eg youre only looking for mobs) + //so by representing every hearing contents on a turf with a single /mob/oranges_ear containing references to all of them, we are: + //1. making view() only go through the smallest of the two linked lists per turf, which contains the type we're looking for at the end + //2. typechecking all mobs in the output to only actually return mobs of type /mob/oranges_ear + //on a whole this can outperform iterating through all movables in view() by ~2x especially when hearables are a tiny percentage of movables in view + for(var/mob/oranges_ear/ear in view(view_radius, center_turf)) + . += ear.references + + for(var/mob/oranges_ear/remaining_ear as anything in assigned_oranges_ears)//we need to clean up our mess + remaining_ear.unassign() + + center_turf.luminosity = old_luminosity + return . + +/** + * Returns a list of movable atoms that are hearing sensitive in view_radius and line of sight to source + * the majority of the work is passed off to the spatial grid if view_radius > 0 + * because view() isnt a raycasting algorithm, this does not hold symmetry to it. something in view might not be hearable with this. + * if you want that use get_hearers_in_view() - however thats significantly more expensive + * + * * view_radius - what radius search circle we are using, worse performance as this increases but not as much as it used to + * * source - object at the center of our search area. everything in get_turf(source) is guaranteed to be part of the search area + */ +/proc/get_hearers_in_LOS(view_radius, atom/source) + var/turf/center_turf = get_turf(source) + if(!center_turf) + return + + if(view_radius <= 0)//special case for if only source cares + . = list() + for(var/atom/movable/target as anything in center_turf) + var/list/hearing_contents = target.important_recursive_contents?[RECURSIVE_CONTENTS_HEARING_SENSITIVE] + if(hearing_contents) + . += hearing_contents + return + + . = SSspatial_grid.orthogonal_range_search(source, SPATIAL_GRID_CONTENTS_TYPE_HEARING, view_radius) + + for(var/atom/movable/target as anything in .) + var/turf/target_turf = get_turf(target) + + var/distance = get_dist(center_turf, target_turf) + + if(distance > view_radius) + . -= target + continue + + else if(distance < 2) //we should always be able to see something 0 or 1 tiles away + continue + + //this turf search algorithm is the worst scaling part of this proc, scaling worse than view() for small-moderate ranges and > 50 length contents_to_return + //luckily its significantly faster than view for large ranges in large spaces and/or relatively few contents_to_return + //i can do things that would scale better, but they would be slower for low volume searches which is the vast majority of the current workload + //maybe in the future a high volume algorithm would be worth it + var/turf/inbetween_turf = center_turf + + //this is the lowest overhead way of doing a loop in dm other than a goto. distance is guaranteed to be >= steps taken to target by this algorithm + for(var/step_counter in 1 to distance) + inbetween_turf = get_step_towards(inbetween_turf, target_turf) + + if(inbetween_turf == target_turf)//we've gotten to target's turf without returning due to turf opacity, so we must be able to see target + break + + if(IS_OPAQUE_TURF(inbetween_turf))//this turf or something on it is opaque so we cant see through it + . -= target + break + +/proc/get_hearers_in_radio_ranges(list/obj/item/radio/radios) + . = list() + // Returns a list of mobs who can hear any of the radios given in @radios + for(var/obj/item/radio/radio as anything in radios) + . |= get_hearers_in_LOS(radio.canhear_range, radio, FALSE) + +///Calculate if two atoms are in sight, returns TRUE or FALSE +/proc/inLineOfSight(X1,Y1,X2,Y2,Z=1,PX1=16.5,PY1=16.5,PX2=16.5,PY2=16.5) + var/turf/T + if(X1==X2) + if(Y1==Y2) + return TRUE //Light cannot be blocked on same tile + else + var/s = SIGN(Y2-Y1) + Y1+=s + while(Y1!=Y2) + T=locate(X1,Y1,Z) + if(IS_OPAQUE_TURF(T)) + return FALSE + Y1+=s + else + var/m=(32*(Y2-Y1)+(PY2-PY1))/(32*(X2-X1)+(PX2-PX1)) + var/b=(Y1+PY1/32-0.015625)-m*(X1+PX1/32-0.015625) //In tiles + var/signX = SIGN(X2-X1) + var/signY = SIGN(Y2-Y1) + if(X1WARNING: Starlight is set to cycle, yet the colours that are set to be cycled is undefined."); log_world("WARNING: Starlight is set to cycle, yet the colours that are set to be cycled is undefined.") flags |= SS_NO_FIRE - return SS_INIT_SUCCESS + return SS_INIT_FAILURE + return SS_INIT_SUCCESS /datum/controller/subsystem/natural_light_cycle/fire(resumed) var/time = station_time() diff --git a/code/controllers/subsystem/spatial_gridmap.dm b/code/controllers/subsystem/spatial_gridmap.dm new file mode 100644 index 0000000000000..1337424866a06 --- /dev/null +++ b/code/controllers/subsystem/spatial_gridmap.dm @@ -0,0 +1,602 @@ +///the subsystem creates this many [/mob/oranges_ear] mob instances during init. allocations that require more than this create more. +#define NUMBER_OF_PREGENERATED_ORANGES_EARS 2500 + +// macros meant specifically to add/remove movables from the hearing_contents and client_contents lists of +// /datum/spatial_grid_cell, when empty they become references to a single list in SSspatial_grid and when filled they become their own list +// this is to save memory without making them lazylists as that slows down iteration through them +#define GRID_CELL_ADD(cell_contents_list, movable_or_list) \ + if(!length(cell_contents_list)) { \ + cell_contents_list = list(); \ + cell_contents_list += movable_or_list; \ + } else { \ + cell_contents_list += movable_or_list; \ + }; + +#define GRID_CELL_SET(cell_contents_list, movable_or_list) \ + if(!length(cell_contents_list)) { \ + cell_contents_list = list(); \ + cell_contents_list += movable_or_list; \ + } else { \ + cell_contents_list |= movable_or_list; \ + }; + +//dont use these outside of SSspatial_grid's scope use the procs it has for this purpose +#define GRID_CELL_REMOVE(cell_contents_list, movable_or_list) \ + cell_contents_list -= movable_or_list; \ + if(!length(cell_contents_list)) {\ + cell_contents_list = dummy_list; \ + }; + +/** + * # Spatial Grid Cell + * + * used by [/datum/controller/subsystem/spatial_grid] to cover every z level so that the coordinates of every turf in the world corresponds to one of these in + * the subsystems list of grid cells by z level. each one of these contains content lists holding all atoms meeting a certain criteria that is in our borders. + * these datums shouldnt have significant behavior, they should just hold data. the lists are filled and emptied by the subsystem. + */ +/datum/spatial_grid_cell + ///our x index in the list of cells. this is our index inside of our row list + var/cell_x + ///our y index in the list of cells. this is the index of our row list inside of our z level grid + var/cell_y + ///which z level we belong to, corresponding to the index of our gridmap in SSspatial_grid.grids_by_z_level + var/cell_z + //every data point in a grid cell is separated by usecase + + //when empty, the contents lists of these grid cell datums are just references to a dummy list from SSspatial_grid + //this is meant to allow a great compromise between memory usage and speed. + //now orthogonal_range_search() doesnt need to check if the list is null and each empty list is taking 12 bytes instead of 24 + //the only downside is that it needs to be switched over to a new list when it goes from 0 contents to > 0 contents and switched back on the opposite case + + ///every hearing sensitive movable inside this cell + var/list/hearing_contents + ///every client possessed mob inside this cell + var/list/client_contents + +/datum/spatial_grid_cell/New(cell_x, cell_y, cell_z) + . = ..() + src.cell_x = cell_x + src.cell_y = cell_y + src.cell_z = cell_z + //cache for sanic speed (lists are references anyways) + var/list/dummy_list = SSspatial_grid.dummy_list + + if(length(dummy_list)) + dummy_list.Cut() + stack_trace("SSspatial_grid.dummy_list had something inserted into it at some point! this is a problem as it is supposed to stay empty") + + hearing_contents = dummy_list + client_contents = dummy_list + +/datum/spatial_grid_cell/Destroy(force, ...) + if(force)//the response to someone trying to qdel this is a right proper fuck you + stack_trace("dont try to destroy spatial grid cells without a good reason. if you need to do it use force") + return + + . = ..() + +/** + * # Spatial Grid + * + * a gamewide grid of spatial_grid_cell datums, each "covering" [SPATIAL_GRID_CELLSIZE] ^ 2 turfs. + * each spatial_grid_cell datum stores information about what is inside its covered area, so that searches through that area dont have to literally search + * through all turfs themselves to know what is within it since view() calls are expensive, and so is iterating through stuff you dont want. + * this allows you to only go through lists of what you want very cheaply. + * + * you can also register to objects entering and leaving a spatial cell, this allows you to do things like stay idle until a player enters, so you wont + * have to use expensive view() calls or iteratite over the global list of players and call get_dist() on every one. which is fineish for a few things, but is + * k * n operations for k objects iterating through n players. + * + * currently this system is only designed for searching for relatively uncommon things, small subsets of /atom/movable. + * dont add stupid shit to the cells please, keep the information that the cells store to things that need to be searched for often + * + * as of right now this system operates on a subset of the important_recursive_contents list for atom/movable, specifically + * [RECURSIVE_CONTENTS_HEARING_SENSITIVE] and [RECURSIVE_CONTENTS_CLIENT_MOBS] because both are those are both 1. important and 2. commonly searched for + */ +SUBSYSTEM_DEF(spatial_grid) + can_fire = FALSE + init_order = INIT_ORDER_SPATIAL_GRID + name = "Spatial Grid" + + ///list of the spatial_grid_cell datums per z level, arranged in the order of y index then x index + var/list/grids_by_z_level = list() + ///everything that spawns before us is added to this list until we initialize + var/list/waiting_to_add_by_type = list(RECURSIVE_CONTENTS_HEARING_SENSITIVE = list(), RECURSIVE_CONTENTS_CLIENT_MOBS = list()) + + var/cells_on_x_axis = 0 + var/cells_on_y_axis = 0 + + ///empty spatial grid cell content lists are just a reference to this instead of a standalone list to save memory without needed to check if its null when iterating + var/list/dummy_list = list() + + ///list of all of /mob/oranges_ear instances we have pregenerated for view() iteration speedup + var/list/mob/oranges_ear/pregenerated_oranges_ears = list() + ///how many pregenerated /mob/oranges_ear instances currently exist. this should hopefully never exceed its starting value + var/number_of_oranges_ears = NUMBER_OF_PREGENERATED_ORANGES_EARS + +/datum/controller/subsystem/spatial_grid/Initialize(start_timeofday) + . = ..() + + cells_on_x_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxx) + cells_on_y_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxy) + + for(var/datum/space_level/z_level as anything in SSmapping.z_list) + propogate_spatial_grid_to_new_z(null, z_level) + CHECK_TICK_HIGH_PRIORITY + + //go through the pre init queue for anything waiting to be let in the grid + for(var/channel_type in waiting_to_add_by_type) + for(var/atom/movable/movable as anything in waiting_to_add_by_type[channel_type]) + var/turf/movable_turf = get_turf(movable) + if(movable_turf) + enter_cell(movable, movable_turf) + + UnregisterSignal(movable, COMSIG_PARENT_PREQDELETED) + waiting_to_add_by_type[channel_type] -= movable + + pregenerate_more_oranges_ears(NUMBER_OF_PREGENERATED_ORANGES_EARS) + + RegisterSignal(SSdcs, COMSIG_GLOB_NEW_Z, PROC_REF(propogate_spatial_grid_to_new_z)) + RegisterSignal(SSdcs, COMSIG_GLOB_EXPANDED_WORLD_BOUNDS, PROC_REF(after_world_bounds_expanded)) + + return SS_INIT_SUCCESS + +///add a movable to the pre init queue for whichever type is specified so that when the subsystem initializes they get added to the grid +/datum/controller/subsystem/spatial_grid/proc/enter_pre_init_queue(atom/movable/waiting_movable, type) + RegisterSignal(waiting_movable, COMSIG_PARENT_PREQDELETED, PROC_REF(queued_item_deleted), override = TRUE) + //override because something can enter the queue for two different types but that is done through unrelated procs that shouldnt know about eachother + waiting_to_add_by_type[type] += waiting_movable + +///removes an initialized and probably deleted movable from our pre init queue before we're initialized +/datum/controller/subsystem/spatial_grid/proc/remove_from_pre_init_queue(atom/movable/movable_to_remove, exclusive_type) + if(exclusive_type) + waiting_to_add_by_type[exclusive_type] -= movable_to_remove + + var/waiting_movable_is_in_other_queues = FALSE//we need to check if this movable is inside the other queues + for(var/type in waiting_to_add_by_type) + if(movable_to_remove in waiting_to_add_by_type[type]) + waiting_movable_is_in_other_queues = TRUE + + if(!waiting_movable_is_in_other_queues) + UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED) + + return + + UnregisterSignal(movable_to_remove, COMSIG_PARENT_PREQDELETED) + for(var/type in waiting_to_add_by_type) + waiting_to_add_by_type[type] -= movable_to_remove + +///if a movable is inside our pre init queue before we're initialized and it gets deleted we need to remove that reference with this proc +/datum/controller/subsystem/spatial_grid/proc/queued_item_deleted(atom/movable/movable_being_deleted) + SIGNAL_HANDLER + remove_from_pre_init_queue(movable_being_deleted, null) + +///creates the spatial grid for a new z level +/datum/controller/subsystem/spatial_grid/proc/propogate_spatial_grid_to_new_z(datum/controller/subsystem/processing/dcs/fucking_dcs, datum/space_level/z_level) + SIGNAL_HANDLER + + var/list/new_cell_grid = list() + + grids_by_z_level += list(new_cell_grid) + + for(var/y in 1 to cells_on_y_axis) + new_cell_grid += list(list()) + for(var/x in 1 to cells_on_x_axis) + var/datum/spatial_grid_cell/cell = new(x, y, z_level.z_value) + new_cell_grid[y] += cell + +///creates number_to_generate new oranges_ear's and adds them to the subsystems list of ears. +///i really fucking hope this never gets called after init :clueless: +/datum/controller/subsystem/spatial_grid/proc/pregenerate_more_oranges_ears(number_to_generate) + for(var/new_ear in 1 to number_to_generate) + pregenerated_oranges_ears += new/mob/oranges_ear(null) + + number_of_oranges_ears = length(pregenerated_oranges_ears) + +///allocate one [/mob/oranges_ear] mob per turf containing atoms_that_need_ears and give them a reference to every listed atom in their turf. +///if an oranges_ear is allocated to a turf that already has an oranges_ear then the second one fails to allocate (and gives the existing one the atom it was assigned to) +/datum/controller/subsystem/spatial_grid/proc/assign_oranges_ears(list/atoms_that_need_ears) + var/input_length = length(atoms_that_need_ears) + + if(input_length > number_of_oranges_ears) + stack_trace("somehow, for some reason, more than the preset generated number of oranges ears was requested. thats fucking [number_of_oranges_ears]. this is not good that should literally never happen") + pregenerate_more_oranges_ears(input_length - number_of_oranges_ears)//im still gonna DO IT but ill complain about it + + . = list() + + ///the next unallocated /mob/oranges_ear that we try to allocate to assigned_atom's turf + var/mob/oranges_ear/current_ear + ///the next atom in atoms_that_need_ears an ear assigned to it + var/atom/assigned_atom + ///the turf loc of the current assigned_atom. turfs are used to track oranges_ears already assigned to one location so we dont allocate more than one + ///because allocating more than one oranges_ear to a given loc wastes view iterations + var/turf/turf_loc + + for(var/current_ear_index in 1 to input_length) + assigned_atom = atoms_that_need_ears[current_ear_index] + + turf_loc = get_turf(assigned_atom) + if(!turf_loc) + continue + + current_ear = pregenerated_oranges_ears[current_ear_index] + + if(turf_loc.assigned_oranges_ear) + turf_loc.assigned_oranges_ear.references += assigned_atom + continue //if theres already an oranges_ear mob at assigned_movable's turf we give assigned_movable to it instead and dont allocate ourselves + + current_ear.references += assigned_atom + + current_ear.loc = turf_loc //normally this is bad, but since this is meant to be as fast as possible we literally just need to exist there for view() to see us + turf_loc.assigned_oranges_ear = current_ear + + . += current_ear + +///adds cells to the grid for every z level when world.maxx or world.maxy is expanded after this subsystem is initialized. hopefully this is never needed. +///because i never tested this. +/datum/controller/subsystem/spatial_grid/proc/after_world_bounds_expanded(datum/controller/subsystem/processing/dcs/fucking_dcs, has_expanded_world_maxx, has_expanded_world_maxy) + SIGNAL_HANDLER + var/old_x_axis = cells_on_x_axis + var/old_y_axis = cells_on_y_axis + + cells_on_x_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxx) + cells_on_y_axis = SPATIAL_GRID_CELLS_PER_SIDE(world.maxy) + + for(var/z_level in 1 to length(grids_by_z_level)) + var/list/z_level_gridmap = grids_by_z_level[z_level] + + for(var/cell_row_for_expanded_y_axis in 1 to cells_on_y_axis) + + if(cell_row_for_expanded_y_axis > old_y_axis)//we are past the old length of the number of rows, so add to the list + z_level_gridmap += list(list()) + + //now we know theres a row at this position, so add cells to it that need to be added and update the ones that already exist + var/list/cell_row = z_level_gridmap[cell_row_for_expanded_y_axis] + + for(var/grid_cell_for_expanded_x_axis in 1 to cells_on_x_axis) + + if(grid_cell_for_expanded_x_axis > old_x_axis) + var/datum/spatial_grid_cell/new_cell_inserted = new(grid_cell_for_expanded_x_axis, cell_row_for_expanded_y_axis, z_level) + cell_row += new_cell_inserted + continue + + //now we know the cell index we're at contains an already existing cell that needs its x and y values updated + var/datum/spatial_grid_cell/old_cell_that_needs_updating = cell_row[grid_cell_for_expanded_x_axis] + old_cell_that_needs_updating.cell_x = grid_cell_for_expanded_x_axis + old_cell_that_needs_updating.cell_y = cell_row_for_expanded_y_axis + +///the left or bottom side index of a box composed of spatial grid cells with the given actual center x or y coordinate +#define BOUNDING_BOX_MIN(center_coord) max(ROUND_UP((center_coord - range) / SPATIAL_GRID_CELLSIZE), 1) +///the right or upper side index of a box composed of spatial grid cells with the given center x or y coordinate. +///outputted value cant exceed the number of cells on that axis +#define BOUNDING_BOX_MAX(center_coord, axis_size) min(ROUND_UP((center_coord + range) / SPATIAL_GRID_CELLSIZE), axis_size) + +/** + * https://en.wikipedia.org/wiki/Range_searching#Orthogonal_range_searching + * + * searches through the grid cells intersecting a rectangular search space (with sides of length 2 * range) then returns all contents of type inside them. + * much faster than iterating through view() to find all of what you want. + * + * this does NOT return things only in range distance from center! the search space is a square not a circle, if you want only things in a certain distance + * then you need to filter that yourself + * + * * center - the atom that is the center of the searched circle + * * type - the type of grid contents you are looking for, see __DEFINES/spatial_grid.dm + * * range - the bigger this is, the more spatial grid cells the search space intersects + */ +/datum/controller/subsystem/spatial_grid/proc/orthogonal_range_search(atom/center, type, range) + var/turf/center_turf = get_turf(center) + + var/center_x = center_turf.x//used inside the macros + var/center_y = center_turf.y + + . = list() + + //cache for sanic speeds + var/cells_on_y_axis = src.cells_on_y_axis + var/cells_on_x_axis = src.cells_on_x_axis + + //technically THIS list only contains lists, but inside those lists are grid cell datums and we can go without a SINGLE var init if we do this + var/list/datum/spatial_grid_cell/grid_level = grids_by_z_level[center_turf.z] + switch(type) + if(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS) + for(var/row in BOUNDING_BOX_MIN(center_y) to BOUNDING_BOX_MAX(center_y, cells_on_y_axis)) + for(var/x_index in BOUNDING_BOX_MIN(center_x) to BOUNDING_BOX_MAX(center_x, cells_on_x_axis)) + + . += grid_level[row][x_index].client_contents + + if(SPATIAL_GRID_CONTENTS_TYPE_HEARING) + for(var/row in BOUNDING_BOX_MIN(center_y) to BOUNDING_BOX_MAX(center_y, cells_on_y_axis)) + for(var/x_index in BOUNDING_BOX_MIN(center_x) to BOUNDING_BOX_MAX(center_x, cells_on_x_axis)) + + . += grid_level[row][x_index].hearing_contents + + return . + +///get the grid cell encomapassing targets coordinates +/datum/controller/subsystem/spatial_grid/proc/get_cell_of(atom/target) + var/turf/target_turf = get_turf(target) + if(!target_turf) + return + + return grids_by_z_level[target_turf.z][ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE)][ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE)] + +///get all grid cells intersecting the bounding box around center with sides of length 2 * range +/datum/controller/subsystem/spatial_grid/proc/get_cells_in_range(atom/center, range) + var/turf/center_turf = get_turf(center) + + var/center_x = center_turf.x + var/center_y = center_turf.y + + var/list/intersecting_grid_cells = list() + + //the minimum x and y cell indexes to test + var/min_x = max(ROUND_UP((center_x - range) / SPATIAL_GRID_CELLSIZE), 1) + var/min_y = max(ROUND_UP((center_y - range) / SPATIAL_GRID_CELLSIZE), 1)//calculating these indices only takes around 2 microseconds + + //the maximum x and y cell indexes to test + var/max_x = min(ROUND_UP((center_x + range) / SPATIAL_GRID_CELLSIZE), cells_on_x_axis) + var/max_y = min(ROUND_UP((center_y + range) / SPATIAL_GRID_CELLSIZE), cells_on_y_axis) + + var/list/grid_level = grids_by_z_level[center_turf.z] + + for(var/row in min_y to max_y) + var/list/grid_row = grid_level[row] + + for(var/x_index in min_x to max_x) + intersecting_grid_cells += grid_row[x_index] + + return intersecting_grid_cells + +///find the spatial map cell that target belongs to, then add target's important_recusive_contents to it. +///make sure to provide the turf new_target is "in" +/datum/controller/subsystem/spatial_grid/proc/enter_cell(atom/movable/new_target, turf/target_turf) + if(!initialized) + return + if(QDELETED(new_target)) + CRASH("qdeleted or null target trying to enter the spatial grid!") + + if(!target_turf || !new_target.important_recursive_contents) + CRASH("null turf loc or a new_target without important_recursive_contents trying to enter the spatial grid!") + + var/x_index = ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE) + var/y_index = ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE) + var/z_index = target_turf.z + + var/datum/spatial_grid_cell/intersecting_cell = grids_by_z_level[z_index][y_index][x_index] + + if(new_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]) + GRID_CELL_SET(intersecting_cell.client_contents, new_target.important_recursive_contents[SPATIAL_GRID_CONTENTS_TYPE_CLIENTS]) + + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_ENTERED(RECURSIVE_CONTENTS_CLIENT_MOBS), new_target) + + if(new_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]) + GRID_CELL_SET(intersecting_cell.hearing_contents, new_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]) + + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_ENTERED(RECURSIVE_CONTENTS_HEARING_SENSITIVE), new_target) + +/** + * find the spatial map cell that target used to belong to, then subtract target's important_recusive_contents from it. + * make sure to provide the turf old_target used to be "in" + * + * * old_target - the thing we want to remove from the spatial grid cell + * * target_turf - the turf we use to determine the cell we're removing from + * * exclusive_type - either null or a valid contents channel. if you just want to remove a single type from the grid cell then use this + */ +/datum/controller/subsystem/spatial_grid/proc/exit_cell(atom/movable/old_target, turf/target_turf, exclusive_type) + if(!initialized) + return + if(!target_turf || !old_target?.important_recursive_contents) + CRASH("/datum/controller/subsystem/spatial_grid/proc/exit_cell() was given null arguments or a new_target without important_recursive_contents!") + + var/x_index = ROUND_UP(target_turf.x / SPATIAL_GRID_CELLSIZE) + var/y_index = ROUND_UP(target_turf.y / SPATIAL_GRID_CELLSIZE) + var/z_index = target_turf.z + + var/list/grid = grids_by_z_level[z_index] + var/datum/spatial_grid_cell/intersecting_cell = grid[y_index][x_index] + + if(exclusive_type && old_target.important_recursive_contents[exclusive_type]) + switch(exclusive_type) + if(RECURSIVE_CONTENTS_CLIENT_MOBS) + GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]) + + if(RECURSIVE_CONTENTS_HEARING_SENSITIVE) + GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]) + + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(exclusive_type), old_target) + return + + if(old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]) + GRID_CELL_REMOVE(intersecting_cell.client_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS]) + + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(SPATIAL_GRID_CONTENTS_TYPE_CLIENTS), old_target) + + if(old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]) + GRID_CELL_REMOVE(intersecting_cell.hearing_contents, old_target.important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE]) + + SEND_SIGNAL(intersecting_cell, SPATIAL_GRID_CELL_EXITED(RECURSIVE_CONTENTS_HEARING_SENSITIVE), old_target) + +///find the cell this movable is associated with and removes it from all lists +/datum/controller/subsystem/spatial_grid/proc/force_remove_from_cell(atom/movable/to_remove, datum/spatial_grid_cell/input_cell) + if(!initialized) + remove_from_pre_init_queue(to_remove)//the spatial grid doesnt exist yet, so just take it out of the queue + return + + if(!input_cell) + input_cell = get_cell_of(to_remove) + if(!input_cell) + find_hanging_cell_refs_for_movable(to_remove, TRUE) + return + + GRID_CELL_REMOVE(input_cell.client_contents, to_remove) + GRID_CELL_REMOVE(input_cell.hearing_contents, to_remove) + +///if shit goes south, this will find hanging references for qdeleting movables inside the spatial grid +/datum/controller/subsystem/spatial_grid/proc/find_hanging_cell_refs_for_movable(atom/movable/to_remove, remove_from_cells = TRUE) + + var/list/queues_containing_movable = list() + for(var/queue_channel in waiting_to_add_by_type) + var/list/queue_list = waiting_to_add_by_type[queue_channel] + if(to_remove in queue_list) + queues_containing_movable += queue_channel//just add the associative key + if(remove_from_cells) + queue_list -= to_remove + + if(!initialized) + return queues_containing_movable + + var/list/containing_cells = list() + for(var/list/z_level_grid as anything in grids_by_z_level) + for(var/list/cell_row as anything in z_level_grid) + for(var/datum/spatial_grid_cell/cell as anything in cell_row) + if(to_remove in (cell.hearing_contents | cell.client_contents)) + containing_cells += cell + if(remove_from_cells) + force_remove_from_cell(to_remove, cell) + + return containing_cells + +///debug proc for checking if a movable is in multiple cells when it shouldnt be (ie always unless multitile entering is implemented) +/atom/proc/find_all_cells_containing(remove_from_cells = FALSE) + var/datum/spatial_grid_cell/real_cell = SSspatial_grid.get_cell_of(src) + var/list/containing_cells = SSspatial_grid.find_hanging_cell_refs_for_movable(src, FALSE, remove_from_cells) + + message_admins("[src] is located in the contents of [length(containing_cells)] spatial grid cells") + + var/cell_coords = "the following cells contain [src]: " + for(var/datum/spatial_grid_cell/cell as anything in containing_cells) + cell_coords += "([cell.cell_x], [cell.cell_y], [cell.cell_z]), " + + message_admins(cell_coords) + message_admins("[src] is supposed to only be contained in the cell at indexes ([real_cell.cell_x], [real_cell.cell_y], [real_cell.cell_z]). but is contained at the cells at [cell_coords]") + +///debug proc for finding how full the cells of src's z level are +/atom/proc/find_grid_statistics_for_z_level(insert_clients = 0) + var/raw_clients = 0 + var/raw_hearables = 0 + + var/cells_with_clients = 0 + var/cells_with_hearables = 0 + + var/list/client_list = list() + var/list/hearable_list = list() + + var/total_cells = (world.maxx / SPATIAL_GRID_CELLSIZE) ** 2 + + var/average_clients_per_cell = 0 + var/average_hearables_per_cell = 0 + + var/hearable_min_x = (world.maxx / SPATIAL_GRID_CELLSIZE) + var/hearable_max_x = 1 + + var/hearable_min_y = (world.maxy / SPATIAL_GRID_CELLSIZE) + var/hearable_max_y = 1 + + var/client_min_x = (world.maxx / SPATIAL_GRID_CELLSIZE) + var/client_max_x = 1 + + var/client_min_y = (world.maxy / SPATIAL_GRID_CELLSIZE) + var/client_max_y = 1 + + var/list/inserted_clients = list() + + if(insert_clients) + var/list/turfs + var/level = SSmapping.get_level(z) + if(is_station_level(level)) + turfs = GLOB.station_turfs + + else + turfs = block(locate(1,1,z), locate(world.maxx, world.maxy, z)) + + for(var/client_to_insert in 0 to insert_clients) + var/turf/random_turf = pick(turfs) + var/mob/fake_client = new() + fake_client.important_recursive_contents = list(SPATIAL_GRID_CONTENTS_TYPE_HEARING = list(fake_client), SPATIAL_GRID_CONTENTS_TYPE_CLIENTS = list(fake_client)) + fake_client.forceMove(random_turf) + inserted_clients += fake_client + + var/list/all_z_level_cells = SSspatial_grid.get_cells_in_range(src, 1000) + + for(var/datum/spatial_grid_cell/cell as anything in all_z_level_cells) + var/client_length = length(cell.client_contents) + var/hearable_length = length(cell.hearing_contents) + + raw_clients += client_length + raw_hearables += hearable_length + + if(client_length) + cells_with_clients++ + + client_list += cell.client_contents + + if(cell.cell_x < client_min_x) + client_min_x = cell.cell_x + + if(cell.cell_x > client_max_x) + client_max_x = cell.cell_x + + if(cell.cell_y < client_min_y) + client_min_y = cell.cell_y + + if(cell.cell_y > client_max_y) + client_max_y = cell.cell_y + + if(hearable_length) + cells_with_hearables++ + + hearable_list += cell.hearing_contents + + if(cell.cell_x < hearable_min_x) + hearable_min_x = cell.cell_x + + if(cell.cell_x > hearable_max_x) + hearable_max_x = cell.cell_x + + if(cell.cell_y < hearable_min_y) + hearable_min_y = cell.cell_y + + if(cell.cell_y > hearable_max_y) + hearable_max_y = cell.cell_y + + var/total_client_distance = 0 + var/total_hearable_distance = 0 + + var/average_client_distance = 0 + var/average_hearable_distance = 0 + + for(var/hearable in hearable_list)//n^2 btw + for(var/other_hearable in hearable_list) + if(hearable == other_hearable) + continue + total_hearable_distance += get_dist(hearable, other_hearable) + + for(var/client in client_list)//n^2 btw + for(var/other_client in client_list) + if(client == other_client) + continue + total_client_distance += get_dist(client, other_client) + + if(length(hearable_list)) + average_hearable_distance = total_hearable_distance / length(hearable_list) + if(length(client_list)) + average_client_distance = total_client_distance / length(client_list) + + average_clients_per_cell = raw_clients / total_cells + average_hearables_per_cell = raw_hearables / total_cells + + for(var/mob/inserted_client as anything in inserted_clients) + qdel(inserted_client) + + message_admins("on z level [z] there are [raw_clients] clients ([insert_clients] of whom are fakes inserted to random station turfs) \ + and [raw_hearables] hearables. all of whom are inside the bounding box given by \ + clients: ([client_min_x], [client_min_y]) x ([client_max_x], [client_max_y]) \ + and hearables: ([hearable_min_x], [hearable_min_y]) x ([hearable_max_x], [hearable_max_y]) \ + on average there are [average_clients_per_cell] clients per cell and [average_hearables_per_cell] hearables per cell. \ + [cells_with_clients] cells have clients and [cells_with_hearables] have hearables, \ + the average client distance is: [average_client_distance] and the average hearable_distance is [average_hearable_distance].") + +#undef GRID_CELL_ADD +#undef GRID_CELL_REMOVE +#undef GRID_CELL_SET diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 7b3663bbf1f55..5de92c7d2911a 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -117,9 +117,8 @@ if(dc) var/all_components = dc[/datum/component] if(length(all_components)) - for(var/I in all_components) - var/datum/component/C = I - qdel(C, FALSE, TRUE) + for(var/datum/component/component as anything in all_components) + qdel(component, FALSE, TRUE) else var/datum/component/C = all_components qdel(C, FALSE, TRUE) @@ -138,8 +137,7 @@ for(var/sig in lookup) var/list/comps = lookup[sig] if(length(comps)) - for(var/i in comps) - var/datum/component/comp = i + for(var/datum/component/comp as anything in comps) comp.UnregisterSignal(src, sig) else var/datum/component/comp = comps diff --git a/code/datums/holocall.dm b/code/datums/holocall.dm index 84616342776ee..d6457fc2fa0e9 100644 --- a/code/datums/holocall.dm +++ b/code/datums/holocall.dm @@ -22,14 +22,21 @@ //this datum manages it's own references /datum/holocall - var/mob/living/user //the one that called - var/obj/machinery/holopad/calling_holopad //the one that sent the call - var/obj/machinery/holopad/connected_holopad //the one that answered the call (may be null) - var/list/dialed_holopads //all things called, will be cleared out to just connected_holopad once answered - - var/mob/camera/ai_eye/remote/holo/eye //user's eye, once connected - var/obj/effect/overlay/holo_pad_hologram/hologram //user's hologram, once connected - var/datum/action/innate/end_holocall/hangup //hangup action + ///the one that called + var/mob/living/user + ///the holopad that sent the call to another holopad + var/obj/machinery/holopad/calling_holopad + ///the one that answered the call (may be null) + var/obj/machinery/holopad/connected_holopad + ///populated with all holopads that are either being dialed or have that have answered us, will be cleared out to just connected_holopad once answered + var/list/dialed_holopads + + ///user's eye, once connected + var/mob/camera/ai_eye/remote/holo/eye + ///user's hologram, once connected + var/obj/effect/overlay/holo_pad_hologram/hologram + ///hangup action + var/datum/action/innate/end_holocall/hangup var/call_start_time @@ -41,12 +48,11 @@ calling_holopad = calling_pad dialed_holopads = list() - for(var/I in callees) - var/obj/machinery/holopad/H = I - if(!QDELETED(H) && H.is_operational) - dialed_holopads += H - H.say("Incoming call.") - LAZYADD(H.holo_calls, src) + for(var/obj/machinery/holopad/connected_holopad as anything in callees) + if(!QDELETED(connected_holopad) && connected_holopad.is_operational) + dialed_holopads += connected_holopad + connected_holopad.say("Incoming call.") + connected_holopad.set_holocall(src) if(!dialed_holopads.len) calling_pad.say("Connection failure.") @@ -74,12 +80,12 @@ QDEL_NULL(hologram) hologram = null - for(var/I in dialed_holopads) - var/obj/machinery/holopad/H = I - LAZYREMOVE(H.holo_calls, src) + for(var/obj/machinery/holopad/dialed_holopad as anything in dialed_holopads) + dialed_holopad.set_holocall(src, FALSE) + dialed_holopads.Cut() - if(calling_holopad) + if(calling_holopad)//if the call is answered, then calling_holopad wont be in dialed_holopads and thus wont have set_holocall(src, FALSE) called calling_holopad.outgoing_call = null calling_holopad.SetLightsAndPower() calling_holopad = null @@ -102,72 +108,71 @@ ConnectionFailure(H, TRUE) -//Forcefully disconnects a holopad `H` from a call. Pads not in the call are ignored. -/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/H, graceful = FALSE) +//Forcefully disconnects disconnected_holopad from a call. Pads not in the call are ignored. +/datum/holocall/proc/ConnectionFailure(obj/machinery/holopad/disconnected_holopad, graceful = FALSE) testing("Holocall connection failure: graceful [graceful]") - if(H == connected_holopad || H == calling_holopad) - if(!graceful && H != calling_holopad) + if(disconnected_holopad == connected_holopad || disconnected_holopad == calling_holopad) + if(!graceful && disconnected_holopad != calling_holopad) calling_holopad.say("Connection failure.") qdel(src) return - LAZYREMOVE(H.holo_calls, src) - dialed_holopads -= H + disconnected_holopad.set_holocall(src, FALSE) + + dialed_holopads -= disconnected_holopad if(!dialed_holopads.len) if(graceful) calling_holopad.say("Call rejected.") testing("No recipients, terminating") qdel(src) -//Answers a call made to a holopad `H` which cannot be the calling holopad. Pads not in the call are ignored -/datum/holocall/proc/Answer(obj/machinery/holopad/H) +///Answers a call made to answering_holopad which cannot be the calling holopad. Pads not in the call are ignored +/datum/holocall/proc/Answer(obj/machinery/holopad/answering_holopad) testing("Holocall answer") - if(H == calling_holopad) + if(answering_holopad == calling_holopad) CRASH("How cute, a holopad tried to answer itself.") - if(!(H in dialed_holopads)) + if(!(answering_holopad in dialed_holopads)) return if(connected_holopad) CRASH("Multi-connection holocall") - for(var/I in dialed_holopads) - if(I == H) + for(var/obj/machinery/holopad/other_dialed_holopad as anything in dialed_holopads) + if(other_dialed_holopad == answering_holopad) continue - Disconnect(I) + Disconnect(other_dialed_holopad) - for(var/I in H.holo_calls) - var/datum/holocall/HC = I - if(HC != src) - HC.Disconnect(H) + for(var/datum/holocall/previously_answered_holocall as anything in answering_holopad.holo_calls)//disconnect the other holocalls answering_holopad is occupied with + if(previously_answered_holocall != src) + previously_answered_holocall.Disconnect(answering_holopad) - connected_holopad = H + connected_holopad = answering_holopad if(!Check()) return - hologram = H.activate_holo(user) + hologram = answering_holopad.activate_holo(user) hologram.HC = src //eyeobj code is horrid, this is the best copypasta I could make eye = new - eye.origin = H + eye.origin = answering_holopad eye.eye_initialized = TRUE eye.eye_user = user eye.name = "Camera Eye ([user.name])" user.remote_control = eye user.reset_perspective(eye) - eye.setLoc(H.loc) + eye.setLoc(answering_holopad.loc) hangup = new(eye, src) hangup.Grant(user) //Checks the validity of a holocall and qdels itself if it's not. Returns TRUE if valid, FALSE otherwise /datum/holocall/proc/Check() - for(var/I in dialed_holopads) - var/obj/machinery/holopad/H = I - if(!H.is_operational) - ConnectionFailure(H) + for(var/obj/machinery/holopad/dialed_holopad as anything in dialed_holopads) + if(!dialed_holopad.is_operational) + ConnectionFailure(dialed_holopad) if(QDELETED(src)) return FALSE diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index ab67397a40d3d..e8e708c0c225d 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -133,26 +133,28 @@ /datum/wires/proc/is_dud_color(color) return is_dud(get_wire(color)) -/datum/wires/proc/cut(wire) +/// Cut a specific wire. +/// User may be null +/datum/wires/proc/cut(wire, mob/user_or_null) if(is_cut(wire)) cut_wires -= wire - on_cut(wire, mend = TRUE) + on_cut(wire, user_or_null, mend = TRUE) else cut_wires += wire - on_cut(wire, mend = FALSE) + on_cut(wire, user_or_null, mend = FALSE) ui_update() -/datum/wires/proc/cut_color(color) - cut(get_wire(color)) +/datum/wires/proc/cut_color(color, mob/user_or_null) + cut(get_wire(color), user_or_null) ui_update() -/datum/wires/proc/cut_random() - cut(wires[rand(1, wires.len)]) +/datum/wires/proc/cut_random(mob/user_or_null) + cut(wires[rand(1, wires.len)], user_or_null) ui_update() -/datum/wires/proc/cut_all() +/datum/wires/proc/cut_all(mob/user_or_null) for(var/wire in wires) - cut(wire) + cut(wire, user_or_null) ui_update() /datum/wires/proc/pulse(wire, user) @@ -208,7 +210,9 @@ /datum/wires/proc/get_status() return list() -/datum/wires/proc/on_cut(wire, mend = FALSE) +/// Called when a wire is asked to be cut +/// User accepts null +/datum/wires/proc/on_cut(wire, mob/user, mend = FALSE) return /datum/wires/proc/on_pulse(wire, user) @@ -283,7 +287,7 @@ if(I || IsAdminGhost(usr)) if(I && holder) I.play_tool_sound(holder, 20) - cut_color(target_wire) + cut_color(target_wire, usr) . = TRUE else to_chat(L, "You need wirecutters!") diff --git a/code/datums/wires/airalarm.dm b/code/datums/wires/airalarm.dm index 9959aa824087c..6831d499c84cf 100644 --- a/code/datums/wires/airalarm.dm +++ b/code/datums/wires/airalarm.dm @@ -57,7 +57,7 @@ A.post_alert(0) A.update_icon() -/datum/wires/airalarm/on_cut(wire, mend) +/datum/wires/airalarm/on_cut(wire, mob/user, mend) var/obj/machinery/airalarm/A = holder switch(wire) if(WIRE_POWER) // Short out forever. diff --git a/code/datums/wires/airlock.dm b/code/datums/wires/airlock.dm index 7514eb5068dd0..46edbc9fc9bc1 100644 --- a/code/datums/wires/airlock.dm +++ b/code/datums/wires/airlock.dm @@ -128,7 +128,7 @@ wires.ui_update() ui_update() -/datum/wires/airlock/on_cut(wire, mend) +/datum/wires/airlock/on_cut(wire, mob/user, mend) var/obj/machinery/door/airlock/A = holder switch(wire) if(WIRE_POWER1, WIRE_POWER2) // Cut to loose power, repair all to gain power. @@ -136,8 +136,8 @@ A.regainMainPower() else A.loseMainPower() - if(isliving(usr)) - A.shock(usr, 50) + if(isliving(user)) + A.shock(user, 50) if(WIRE_BACKUP1, WIRE_BACKUP2) // Cut to loose backup power, repair all to gain backup power. if(mend && !is_cut(WIRE_BACKUP1) && !is_cut(WIRE_BACKUP2)) A.regainBackupPower() @@ -160,12 +160,12 @@ if(WIRE_SHOCK) // Cut to shock the door, mend to unshock. if(mend) if(A.secondsElectrified) - A.set_electrified(MACHINE_NOT_ELECTRIFIED, usr) + A.set_electrified(MACHINE_NOT_ELECTRIFIED, user) else if(A.secondsElectrified != MACHINE_ELECTRIFIED_PERMANENT) - A.set_electrified(MACHINE_ELECTRIFIED_PERMANENT, usr) - if(isliving(usr)) - A.shock(usr, 50) + A.set_electrified(MACHINE_ELECTRIFIED_PERMANENT, user) + if(isliving(user)) + A.shock(user, 50) if(WIRE_SAFETY) // Cut to disable safeties, mend to re-enable. A.safe = mend if(WIRE_TIMING) // Cut to disable auto-close, mend to re-enable. diff --git a/code/datums/wires/airlock_cycle.dm b/code/datums/wires/airlock_cycle.dm index 7e77422f07279..bfce4c7d8c71c 100644 --- a/code/datums/wires/airlock_cycle.dm +++ b/code/datums/wires/airlock_cycle.dm @@ -38,7 +38,7 @@ A.aidisabled = TRUE addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/advanced_airlock_controller, reset), wire), 100) -/datum/wires/advanced_airlock_controller/on_cut(wire, mend) +/datum/wires/advanced_airlock_controller/on_cut(wire, mob/user, mend) var/obj/machinery/advanced_airlock_controller/A = holder switch(wire) if(WIRE_POWER) // Short out forever. diff --git a/code/datums/wires/apc.dm b/code/datums/wires/apc.dm index 2a2622b8f0d48..8d9c3cd0385e3 100644 --- a/code/datums/wires/apc.dm +++ b/code/datums/wires/apc.dm @@ -39,16 +39,18 @@ addtimer(CALLBACK(A, TYPE_PROC_REF(/obj/machinery/power/apc, reset), wire), 10) ui_update() -/datum/wires/apc/on_cut(index, mend) +/datum/wires/apc/on_cut(index, mob/user, mend) var/obj/machinery/power/apc/A = holder switch(index) if(WIRE_POWER1, WIRE_POWER2) // Short out. if(mend && !is_cut(WIRE_POWER1) && !is_cut(WIRE_POWER2)) A.shorted = FALSE - A.shock(usr, 50) + if (user) + A.shock(user, 50) else A.shorted = TRUE - A.shock(usr, 50) + if (user) + A.shock(user, 50) if(WIRE_AI) // Disable AI control. if(mend) A.aidisabled = FALSE diff --git a/code/datums/wires/autolathe.dm b/code/datums/wires/autolathe.dm index 8bf5fdd9f91a3..f0a4f60a6d64e 100644 --- a/code/datums/wires/autolathe.dm +++ b/code/datums/wires/autolathe.dm @@ -38,7 +38,7 @@ A.begin_process() ui_update() -/datum/wires/autolathe/on_cut(wire, mend) +/datum/wires/autolathe/on_cut(wire, mob/user, mend) var/obj/machinery/modular_fabricator/autolathe/A = holder switch(wire) if(WIRE_HACK) @@ -48,5 +48,6 @@ if(WIRE_DISABLE) A.disabled = !mend if(WIRE_ZAP) - A.shock(usr, 50) + if (user) + A.shock(user, 50) ui_update() diff --git a/code/datums/wires/dna_scanner.dm b/code/datums/wires/dna_scanner.dm index 8ed19a24ca1b0..6794f01bd90ef 100644 --- a/code/datums/wires/dna_scanner.dm +++ b/code/datums/wires/dna_scanner.dm @@ -44,7 +44,7 @@ S.shock(user, 50) ui_update() -/datum/wires/dna_scanner/on_cut(wire, mend) +/datum/wires/dna_scanner/on_cut(wire, mob/user, mend) var/obj/machinery/dna_scannernew/S = holder switch(wire) if(WIRE_IDSCAN) @@ -60,6 +60,6 @@ S.locked = TRUE S.update_icon() if(WIRE_ZAP1, WIRE_ZAP2) - if(isliving(usr)) - S.shock(usr, 90) + if(isliving(user)) + S.shock(user, 90) ui_update() diff --git a/code/datums/wires/ecto_sniffer.dm b/code/datums/wires/ecto_sniffer.dm index d4dcae6fb002a..90b148ba2c33d 100644 --- a/code/datums/wires/ecto_sniffer.dm +++ b/code/datums/wires/ecto_sniffer.dm @@ -12,6 +12,6 @@ our_sniffer.activate() ..() -/datum/wires/ecto_sniffer/on_cut(wire, mend) +/datum/wires/ecto_sniffer/on_cut(wire, mob/user, mend) var/obj/machinery/ecto_sniffer/our_sniffer = holder our_sniffer.sensor_enabled = mend diff --git a/code/datums/wires/explosive.dm b/code/datums/wires/explosive.dm index e91fe3f1cd4da..12aed04cb0dd8 100644 --- a/code/datums/wires/explosive.dm +++ b/code/datums/wires/explosive.dm @@ -8,7 +8,7 @@ /datum/wires/explosive/on_pulse(index) explode() -/datum/wires/explosive/on_cut(index, mend) +/datum/wires/explosive/on_cut(index, mob/user, mend) explode() /datum/wires/explosive/proc/explode() @@ -104,7 +104,7 @@ else // Boom explode() -/datum/wires/explosive/pizza/on_cut(wire, mend) +/datum/wires/explosive/pizza/on_cut(wire, mob/user, mend) var/obj/item/pizzabox/P = holder switch(wire) if(WIRE_DISARM) // Disarm and untrap the box. diff --git a/code/datums/wires/fax.dm b/code/datums/wires/fax.dm index f5eabbd7822d5..a87c16f5a3068 100644 --- a/code/datums/wires/fax.dm +++ b/code/datums/wires/fax.dm @@ -43,7 +43,7 @@ if(WIRE_LOADCHECK) machine.allow_exotic_faxes = !machine.allow_exotic_faxes -/datum/wires/fax/on_cut(wire, mend) +/datum/wires/fax/on_cut(wire, mob/user, mend) var/obj/machinery/fax/machine = holder switch(wire) if(WIRE_SHOCK) diff --git a/code/datums/wires/microwave.dm b/code/datums/wires/microwave.dm index 8c74abfa46c78..29d50e86045ae 100644 --- a/code/datums/wires/microwave.dm +++ b/code/datums/wires/microwave.dm @@ -20,7 +20,7 @@ if(WIRE_ACTIVATE) M.cook() -/datum/wires/microwave/on_cut(wire, mend) +/datum/wires/microwave/on_cut(wire, mob/user, mend) var/obj/machinery/microwave/M = holder switch(wire) if(WIRE_ACTIVATE) diff --git a/code/datums/wires/particle_accelerator.dm b/code/datums/wires/particle_accelerator.dm index 5600b0b1823c4..f012a727abf51 100644 --- a/code/datums/wires/particle_accelerator.dm +++ b/code/datums/wires/particle_accelerator.dm @@ -27,7 +27,7 @@ if(WIRE_LIMIT) C.visible_message("[icon2html(C, viewers(holder))][C] makes a large whirring noise.") -/datum/wires/particle_accelerator/control_box/on_cut(wire, mend) +/datum/wires/particle_accelerator/control_box/on_cut(wire, mob/user, mend) var/obj/machinery/particle_accelerator/control_box/C = holder switch(wire) if(WIRE_POWER) diff --git a/code/datums/wires/r_n_d.dm b/code/datums/wires/r_n_d.dm index 7aaad875faa59..5c2b2a04ace2c 100644 --- a/code/datums/wires/r_n_d.dm +++ b/code/datums/wires/r_n_d.dm @@ -31,7 +31,7 @@ if(WIRE_DISABLE) R.disabled = !R.disabled ui_update() -/datum/wires/rnd/on_cut(wire, mend) +/datum/wires/rnd/on_cut(wire, mob/user, mend) var/obj/machinery/rnd/R = holder switch(wire) if(WIRE_HACK) diff --git a/code/datums/wires/radio.dm b/code/datums/wires/radio.dm index a1118da6d73c6..e2b4192020f02 100644 --- a/code/datums/wires/radio.dm +++ b/code/datums/wires/radio.dm @@ -17,9 +17,9 @@ var/obj/item/radio/R = holder switch(index) if(WIRE_SIGNAL) - R.listening = !R.listening - R.broadcasting = R.listening + R.set_listening(!R.get_listening()) + R.set_broadcasting(R.get_listening()) if(WIRE_RX) - R.listening = !R.listening + R.set_listening(!R.get_listening()) if(WIRE_TX) - R.broadcasting = !R.broadcasting + R.set_broadcasting(!R.get_broadcasting()) diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index 9bd3c15a09325..571675320c554 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -66,13 +66,14 @@ R.visible_message("[R]'s module servos twitch.", "Your module display flickers.") ui_update() -/datum/wires/robot/on_cut(wire, mend) +/datum/wires/robot/on_cut(wire, mob/user, mend) var/mob/living/silicon/robot/R = holder switch(wire) if(WIRE_AI) // Cut the AI wire to reset AI control. if(!mend) R.notify_ai(DISCONNECT) - log_combat(usr, R, "cut AI wire on cyborg[R.connected_ai ? " and disconnected from [ADMIN_LOOKUP(R.connected_ai)]": ""]", important = FALSE) + if (user) + log_combat(user, R, "cut AI wire on cyborg[R.connected_ai ? " and disconnected from [ADMIN_LOOKUP(R.connected_ai)]": ""]", important = FALSE) if(R.shell) R.undeploy() R.connected_ai = null @@ -81,24 +82,29 @@ if(mend) if(!R.emagged) R.lawupdate = TRUE - log_combat(usr, R, "enabled lawsync via wire", important = FALSE) + if (user) + log_combat(user, R, "enabled lawsync via wire", important = FALSE) else if(!R.deployed) //AI shells must always have the same laws as the AI R.lawupdate = FALSE - log_combat(usr, R, "disabled lawsync via wire") + if (user) + log_combat(user, R, "disabled lawsync via wire") R.logevent("Lawsync Module fault [mend?"cleared":"detected"]") if (WIRE_CAMERA) // Disable the camera. if(!QDELETED(R.builtInCamera) && !R.scrambledcodes) R.builtInCamera.status = mend - R.builtInCamera.toggle_cam(usr, FALSE) + R.builtInCamera.toggle_cam(user, FALSE) R.visible_message("[R]'s camera lens focuses loudly.", "Your camera lens focuses loudly.") R.logevent("Camera Module fault [mend?"cleared":"detected"]") - log_combat(usr, R, "[mend ? "enabled" : "disabled"] cyborg camera via wire") + if (user) + log_combat(user, R, "[mend ? "enabled" : "disabled"] cyborg camera via wire") if(WIRE_LOCKDOWN) // Simple lockdown. R.SetLockdown(!mend) R.logevent("Motor Controller fault [mend?"cleared":"detected"]") - log_combat(usr, R, "[!R.lockcharge ? "locked down" : "released"] via wire", important = FALSE) + if (user) + log_combat(user, R, "[!R.lockcharge ? "locked down" : "released"] via wire", important = FALSE) if(WIRE_RESET_MODULE) if(R.has_module() && !mend) R.ResetModule() - log_combat(usr, R, "reset the cyborg module via wire", important = FALSE) + if (user) + log_combat(user, R, "reset the cyborg module via wire", important = FALSE) ui_update() diff --git a/code/datums/wires/suit_storage_unit.dm b/code/datums/wires/suit_storage_unit.dm index 7b165622effec..a0c18ba427d5c 100644 --- a/code/datums/wires/suit_storage_unit.dm +++ b/code/datums/wires/suit_storage_unit.dm @@ -34,7 +34,7 @@ SSU.shock(usr) ui_update() -/datum/wires/suit_storage_unit/on_cut(wire, mend) +/datum/wires/suit_storage_unit/on_cut(wire, mob/user, mend) var/obj/machinery/suit_storage_unit/SSU = holder switch(wire) if(WIRE_HACK) @@ -42,6 +42,6 @@ if(WIRE_SAFETY) SSU.safeties = mend if(WIRE_ZAP) - if(usr) - SSU.shock(usr) + if(user) + SSU.shock(user) ui_update() diff --git a/code/datums/wires/syndicatebomb.dm b/code/datums/wires/syndicatebomb.dm index 7e6e5fd0d4e56..22e9d8843e329 100644 --- a/code/datums/wires/syndicatebomb.dm +++ b/code/datums/wires/syndicatebomb.dm @@ -78,7 +78,7 @@ B.detonation_timer += 10 SECONDS delayed_hesitate = TRUE -/datum/wires/syndicatebomb/on_cut(wire, mend) +/datum/wires/syndicatebomb/on_cut(wire, mob/user, mend) var/obj/machinery/syndicatebomb/B = holder switch(wire) if(WIRE_BOOM) diff --git a/code/datums/wires/vending.dm b/code/datums/wires/vending.dm index c703b88105ef8..d8ed05a2685c3 100644 --- a/code/datums/wires/vending.dm +++ b/code/datums/wires/vending.dm @@ -42,7 +42,7 @@ V.shut_up = !V.shut_up ui_update() -/datum/wires/vending/on_cut(wire, mend) +/datum/wires/vending/on_cut(wire, mob/user, mend) var/obj/machinery/vending/V = holder switch(wire) if(WIRE_THROW) diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index f8ddd700d6443..ef28dc34e9189 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -2,7 +2,7 @@ layer = OBJ_LAYER glide_size = 8 appearance_flags = TILE_BOUND|PIXEL_SCALE - + var/move_stacks = 0 //how many times a this movable had movement procs called on it since Moved() was last called var/last_move = null var/last_move_time = 0 @@ -56,6 +56,9 @@ * do NOT add channels to this for little reason as it can add considerable memory usage. */ var/list/important_recursive_contents + ///contains every client mob corresponding to every client eye in this container. lazily updated by SSparallax and is sparse: + ///only the last container of a client eye has this list assuming no movement since SSparallax's last fire + var/list/client_mobs_in_contents ///Lazylist to keep track on the sources of illumination. var/list/affected_dynamic_lights ///Highest-intensity light affecting us, which determines our visibility. @@ -90,6 +93,7 @@ var/turf/T = loc T.update_above() // Z-Mimic + /atom/movable/Destroy(force) QDEL_NULL(proximity_monitor) QDEL_NULL(language_holder) @@ -124,9 +128,12 @@ if(!QDELETED(move_packet)) qdel(move_packet) move_packet = null -/* + + if(important_recursive_contents && (important_recursive_contents[RECURSIVE_CONTENTS_CLIENT_MOBS] || important_recursive_contents[RECURSIVE_CONTENTS_HEARING_SENSITIVE])) + SSspatial_grid.force_remove_from_cell(src) + LAZYCLEARLIST(client_mobs_in_contents) -*/ + . = ..() for(var/movable_content in contents) @@ -139,13 +146,13 @@ //If we clear this before the nullspace move, a ref to this object will be hung in any of its movable containers LAZYCLEARLIST(important_recursive_contents) + vis_locs = null //clears this atom out of all viscontents // Checking length(vis_contents) before cutting has significant speed benefits if (length(vis_contents)) vis_contents.Cut() - /atom/movable/proc/update_emissive_block() if(!blocks_emissive) return @@ -492,6 +499,7 @@ //Called after a successful Move(). By this point, we've alrefady moved /atom/movable/proc/Moved(atom/OldLoc, Dir, Forced = FALSE) SHOULD_CALL_PARENT(TRUE) + if(OldLoc) var/turf/old_turf = get_turf(OldLoc) var/turf/new_turf = get_turf(src) @@ -519,6 +527,23 @@ else // Not a turf, so we need to destroy immediately instead of waiting for the destruction timer to proc. qdel(bound_overlay) + var/turf/old_turf = get_turf(OldLoc) + var/turf/new_turf = get_turf(src) + + if(HAS_SPATIAL_GRID_CONTENTS(src)) + if(old_turf && new_turf && (old_turf.z != new_turf.z \ + || ROUND_UP(old_turf.x / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.x / SPATIAL_GRID_CELLSIZE) \ + || ROUND_UP(old_turf.y / SPATIAL_GRID_CELLSIZE) != ROUND_UP(new_turf.y / SPATIAL_GRID_CELLSIZE))) + + SSspatial_grid.exit_cell(src, old_turf) + SSspatial_grid.enter_cell(src, new_turf) + + else if(old_turf && !new_turf) + SSspatial_grid.exit_cell(src, old_turf) + + else if(new_turf && !old_turf) + SSspatial_grid.enter_cell(src, new_turf) + return TRUE // Make sure you know what you're doing if you call this, this is intended to only be called by byond directly. @@ -1197,23 +1222,9 @@ /atom/movable/proc/get_spawner_flavour_text() return desc -/atom/movable/proc/on_hearing_sensitive_trait_loss() - SIGNAL_HANDLER - - UnregisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_HEARING_SENSITIVE)) - for(var/atom/movable/location as anything in get_nested_locs(src) + src) - LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) - -///allows this movable to hear and adds itself to the important_recursive_contents list of itself and every movable loc its in -/atom/movable/proc/become_hearing_sensitive(trait_source = TRAIT_GENERIC) - if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE)) - RegisterSignal(src, SIGNAL_REMOVETRAIT(TRAIT_HEARING_SENSITIVE), PROC_REF(on_hearing_sensitive_trait_loss)) - for(var/atom/movable/location as anything in get_nested_locs(src) + src) - LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) - ADD_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source) - /atom/movable/Entered(atom/movable/arrived, atom/old_loc, list/atom/old_locs) . = ..() + if(LAZYLEN(arrived.important_recursive_contents)) var/list/nested_locs = get_nested_locs(src) + src for(var/channel in arrived.important_recursive_contents) @@ -1222,8 +1233,89 @@ /atom/movable/Exited(atom/movable/gone, direction) . = ..() + if(LAZYLEN(gone.important_recursive_contents)) var/list/nested_locs = get_nested_locs(src) + src for(var/channel in gone.important_recursive_contents) for(var/atom/movable/location as anything in nested_locs) LAZYREMOVEASSOC(location.important_recursive_contents, channel, gone.important_recursive_contents[channel]) + +///allows this movable to hear and adds itself to the important_recursive_contents list of itself and every movable loc its in +/atom/movable/proc/become_hearing_sensitive(trait_source = TRAIT_GENERIC) + if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE)) + for(var/atom/movable/location as anything in get_nested_locs(src) + src) + LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) + + var/turf/our_turf = get_turf(src) + if(our_turf && SSspatial_grid.initialized) + SSspatial_grid.enter_cell(src, our_turf) + + else if(our_turf && !SSspatial_grid.initialized)//SSspatial_grid isnt init'd yet, add ourselves to the queue + SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + + ADD_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source) + +/** + * removes the hearing sensitivity channel from the important_recursive_contents list of this and all nested locs containing us if there are no more sources of the trait left + * since RECURSIVE_CONTENTS_HEARING_SENSITIVE is also a spatial grid content type, removes us from the spatial grid if the trait is removed + * + * * trait_source - trait source define or ALL, if ALL, force removes hearing sensitivity. if a trait source define, removes hearing sensitivity only if the trait is removed + */ +/atom/movable/proc/lose_hearing_sensitivity(trait_source = TRAIT_GENERIC) + if(!HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE)) + return + REMOVE_TRAIT(src, TRAIT_HEARING_SENSITIVE, trait_source) + if(HAS_TRAIT(src, TRAIT_HEARING_SENSITIVE)) + return + + var/turf/our_turf = get_turf(src) + if(our_turf && SSspatial_grid.initialized) + SSspatial_grid.exit_cell(src, our_turf) + else if(our_turf && !SSspatial_grid.initialized) + SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_HEARING_SENSITIVE) + + for(var/atom/movable/location as anything in get_nested_locs(src) + src) + LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_HEARING_SENSITIVE, src) + +///allows this movable to know when it has "entered" another area no matter how many movable atoms its stuffed into, uses important_recursive_contents +/atom/movable/proc/become_area_sensitive(trait_source = TRAIT_GENERIC) + if(!HAS_TRAIT(src, TRAIT_AREA_SENSITIVE)) + for(var/atom/movable/location as anything in get_nested_locs(src) + src) + LAZYADDASSOCLIST(location.important_recursive_contents, RECURSIVE_CONTENTS_AREA_SENSITIVE, src) + ADD_TRAIT(src, TRAIT_AREA_SENSITIVE, trait_source) + +///removes the area sensitive channel from the important_recursive_contents list of this and all nested locs containing us if there are no more source of the trait left +/atom/movable/proc/lose_area_sensitivity(trait_source = TRAIT_GENERIC) + if(!HAS_TRAIT(src, TRAIT_AREA_SENSITIVE)) + return + REMOVE_TRAIT(src, TRAIT_AREA_SENSITIVE, trait_source) + if(HAS_TRAIT(src, TRAIT_AREA_SENSITIVE)) + return + + for(var/atom/movable/location as anything in get_nested_locs(src) + src) + LAZYREMOVEASSOC(location.important_recursive_contents, RECURSIVE_CONTENTS_AREA_SENSITIVE, src) + +///propogates ourselves through our nested contents, similar to other important_recursive_contents procs +///main difference is that client contents need to possibly duplicate recursive contents for the clients mob AND its eye +/mob/proc/enable_client_mobs_in_contents() + var/turf/our_turf = get_turf(src) + + if(our_turf && SSspatial_grid.initialized) + SSspatial_grid.enter_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS) + else if(our_turf && !SSspatial_grid.initialized) + SSspatial_grid.enter_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS) + + for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src) + LAZYORASSOCLIST(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, src) + +///Clears the clients channel of this mob +/mob/proc/clear_important_client_contents() + var/turf/our_turf = get_turf(src) + + if(our_turf && SSspatial_grid.initialized) + SSspatial_grid.exit_cell(src, our_turf, RECURSIVE_CONTENTS_CLIENT_MOBS) + else if(our_turf && !SSspatial_grid.initialized) + SSspatial_grid.remove_from_pre_init_queue(src, RECURSIVE_CONTENTS_CLIENT_MOBS) + + for(var/atom/movable/movable_loc as anything in get_nested_locs(src) + src) + LAZYREMOVEASSOC(movable_loc.important_recursive_contents, RECURSIVE_CONTENTS_CLIENT_MOBS, src) diff --git a/code/game/gamemodes/gangs/dominator.dm b/code/game/gamemodes/gangs/dominator.dm index b1ecf4b1a2cc7..7d9a88b0f97dd 100644 --- a/code/game/gamemodes/gangs/dominator.dm +++ b/code/game/gamemodes/gangs/dominator.dm @@ -11,6 +11,7 @@ anchored = TRUE layer = HIGH_OBJ_LAYER max_integrity = 300 + max_hit_damage = 30 integrity_failure = 0.33 move_resist = INFINITY armor = list(MELEE = 20, BULLET = 50, LASER = 50, ENERGY = 50, BOMB = 10, BIO = 100, RAD = 100, FIRE = 10, ACID = 70, STAMINA = 0, BLEED = 0) diff --git a/code/game/machinery/bank_machine.dm b/code/game/machinery/bank_machine.dm index 80ca9b102f151..94cb1dd492c8a 100644 --- a/code/game/machinery/bank_machine.dm +++ b/code/game/machinery/bank_machine.dm @@ -16,6 +16,7 @@ radio = new(src) radio.subspace_transmission = TRUE radio.canhear_range = 0 + radio.set_listening(FALSE) radio.recalculateChannels() /obj/machinery/computer/bank_machine/Destroy() diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm index 43a4d232a010f..fe6205bdde6cb 100644 --- a/code/game/machinery/computer/arcade.dm +++ b/code/game/machinery/computer/arcade.dm @@ -414,7 +414,7 @@ GLOBAL_LIST_INIT(arcade_prize_pool, list( /obj/machinery/computer/arcade/orion_trail/Initialize(mapload) . = ..() Radio = new /obj/item/radio(src) - Radio.listening = 0 + Radio.set_listening(FALSE) /obj/machinery/computer/arcade/orion_trail/kobayashi name = "Kobayashi Maru control computer" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 4ed8601855d46..c946c241ddef8 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1406,7 +1406,7 @@ /obj/machinery/door/airlock/proc/on_break() if(!panel_open) panel_open = TRUE - wires.cut_all() + wires.cut_all(null) /obj/machinery/door/airlock/proc/set_electrified(seconds, mob/user) secondsElectrified = seconds diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 54e53ac14a274..a0223969a3e88 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -31,7 +31,7 @@ . = ..() sec_radio = new/obj/item/radio(src) - sec_radio.listening = FALSE + sec_radio.set_listening(FALSE) if(id != null) for(var/obj/machinery/door/window/brigdoor/M in urange(20, src)) diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm index 70d46cfa00089..d429b35023c00 100644 --- a/code/game/machinery/firealarm.dm +++ b/code/game/machinery/firealarm.dm @@ -28,6 +28,7 @@ resistance_flags = FIRE_PROOF layer = ABOVE_WINDOW_LAYER zmm_flags = ZMM_MANGLE_PLANES + req_access = null light_power = 0 light_range = 7 @@ -37,9 +38,12 @@ var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone var/last_alarm = 0 var/area/myarea = null + var/locked = FALSE //Are we locked? /obj/machinery/firealarm/Initialize(mapload, dir, building) . = ..() + if (!req_access) + req_access = list(ACCESS_ATMOSPHERICS) if(building) buildstage = 0 panel_open = TRUE @@ -72,21 +76,27 @@ . += emissive_appearance(icon, "fire_[SEC_LEVEL_GREEN]", layer, alpha = 255) ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) - if(!detecting || !A.fire) //If this is false, leave the green light missing. A good hint to anyone paying attention. - . += "fire_off" - . += mutable_appearance(icon, "fire_off") - . += emissive_appearance(icon, "fire_off", layer, alpha = 255) - ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) - else if(obj_flags & EMAGGED) + if(obj_flags & EMAGGED) . += "fire_emagged" . += mutable_appearance(icon, "fire_emagged") . += emissive_appearance(icon, "fire_emagged", layer, alpha = 255) ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) - else + return //If it's emagged, don't do anything else for overlays. + if(locked) + . += "fire_locked" + . += mutable_appearance(icon, "fire_locked", layer + 1) //If we are locked, overlay that over the fire_off + . += emissive_appearance(icon, "fire_locked", layer, alpha = 255) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) + if(detecting && A.fire) . += "fire_on" - . += mutable_appearance(icon, "fire_on") + . += mutable_appearance(icon, "fire_on", layer + 2) //If we are locked and there is a fire, overlay the fire detection overlay ontop of the locked one. . += emissive_appearance(icon, "fire_on", layer, alpha = 255) ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) + else + . += "fire_off" + . += mutable_appearance(icon, "fire_off") + . += emissive_appearance(icon, "fire_off", layer, alpha = 255) + ADD_LUM_SOURCE(src, LUM_SOURCE_MANAGED_OVERLAY) /obj/machinery/firealarm/emp_act(severity) . = ..() @@ -113,6 +123,7 @@ /obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume) if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !machine_stat) alarm() + try_lock(null, TRUE) ..() /** @@ -135,6 +146,7 @@ var/area/A = get_area(src) A.firealert(src) playsound(loc, 'goon/sound/machinery/FireAlarm.ogg', 75) + update_appearance() if(user) log_game("[user] triggered a fire alarm at [COORD(src)]") @@ -143,9 +155,27 @@ return var/area/A = get_area(src) A.firereset(src) + update_appearance() if(user) log_game("[user] reset a fire alarm at [COORD(src)]") +/obj/machinery/firealarm/proc/try_lock(mob/user, force_lock = FALSE) + if(allowed(user) || !user || force_lock) + if(!locked || force_lock) + locked = TRUE + balloon_alert(user, "Locked") + else + locked = FALSE + balloon_alert(user, "Unlocked") + playsound(src, 'sound/machines/beep.ogg', 50, 1) + else + balloon_alert(user, "Access Denied!") + playsound(src, 'sound/machines/terminal_error.ogg', 50, 1) + update_appearance() + +/obj/machinery/firealarm/AltClick(mob/user) + try_lock(user) + /obj/machinery/firealarm/attack_hand(mob/user) if(buildstage != 2) return ..() @@ -153,6 +183,10 @@ play_click_sound("button") var/area/A = get_area(src) if(A.fire) + if(locked) + balloon_alert(user, "Cover is locked!") + playsound(loc, 'sound/effects/glassknock.ogg', 10, FALSE, frequency = 32000) + return reset(user) else alarm(user) @@ -166,6 +200,8 @@ /obj/machinery/firealarm/attackby(obj/item/W, mob/user, params) add_fingerprint(user) + if(istype(W, /obj/item/card/id)||istype(W, /obj/item/modular_computer/tablet/pda)) // trying to unlock the cover with an ID card + try_lock(user) if(W.tool_behaviour == TOOL_SCREWDRIVER && buildstage == 2) W.play_tool_sound(src) panel_open = !panel_open diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm index 2dbe5da051b91..45e5e116c44e1 100644 --- a/code/game/machinery/hologram.dm +++ b/code/game/machinery/hologram.dm @@ -1,3 +1,8 @@ +#define CAN_HEAR_MASTERS (1<<0) +#define CAN_HEAR_ACTIVE_HOLOCALLS (1<<1) +#define CAN_HEAR_RECORD_MODE (1<<2) +#define CAN_HEAR_ALL_FLAGS (CAN_HEAR_MASTERS|CAN_HEAR_ACTIVE_HOLOCALLS|CAN_HEAR_RECORD_MODE) + /* Holograms! * Contains: * Holopad @@ -59,10 +64,8 @@ Possible to do for anyone motivated enough: var/ringing = FALSE var/offset = FALSE var/on_network = TRUE - -/obj/machinery/holopad/Initialize(mapload) - . = ..() - become_hearing_sensitive() + ///bitfield. used to turn on and off hearing sensitivity depending on if we can act on Hear() at all - meant for lowering the number of unessesary hearable atoms + var/can_hear_flags = NONE /obj/machinery/holopad/tutorial resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF @@ -105,9 +108,8 @@ Possible to do for anyone motivated enough: if(outgoing_call) outgoing_call.ConnectionFailure(src) - for(var/I in holo_calls) - var/datum/holocall/HC = I - HC.ConnectionFailure(src) + for(var/datum/holocall/holocall_to_disconnect as anything in holo_calls) + holocall_to_disconnect.ConnectionFailure(src) for (var/I in masters) clear_holo(I) @@ -228,11 +230,55 @@ Possible to do for anyone motivated enough: popup.set_content(dat) popup.open() +//setters +/** + * setter for can_hear_flags. handles adding or removing the given flag on can_hear_flags and then adding hearing sensitivity or removing it depending on the final state + * this is necessary because holopads are a significant fraction of the hearable atoms on station which increases the cost of procs that iterate through hearables + * so we need holopads to not be hearable until it is needed + * + * * flag - one of the can_hear_flags flag defines + * * set_flag - boolean, if TRUE sets can_hear_flags to that flag and might add hearing sensitivity if can_hear_flags was NONE before, + * if FALSE unsets the flag and possibly removes hearing sensitivity + */ +/obj/machinery/holopad/proc/set_can_hear_flags(flag, set_flag = TRUE) + if(!(flag & CAN_HEAR_ALL_FLAGS)) + return FALSE //the given flag doesnt exist + + if(set_flag) + if(can_hear_flags == NONE)//we couldnt hear before, so become hearing sensitive + become_hearing_sensitive() + + can_hear_flags |= flag + return TRUE + + else + can_hear_flags &= ~flag + if(can_hear_flags == NONE) + lose_hearing_sensitivity() + + return TRUE + +///setter for adding/removing holocalls to this holopad. used to update the holo_calls list and can_hear_flags +///adds the given holocall if add_holocall is TRUE, removes if FALSE +/obj/machinery/holopad/proc/set_holocall(datum/holocall/holocall_to_update, add_holocall = TRUE) + if(!istype(holocall_to_update)) + return FALSE + + if(add_holocall) + set_can_hear_flags(CAN_HEAR_ACTIVE_HOLOCALLS) + LAZYADD(holo_calls, holocall_to_update) + + else + LAZYREMOVE(holo_calls, holocall_to_update) + if(!LAZYLEN(holo_calls)) + set_can_hear_flags(CAN_HEAR_ACTIVE_HOLOCALLS, FALSE) + + return TRUE + //Stop ringing the AI!! /obj/machinery/holopad/proc/hangup_all_calls() - for(var/I in holo_calls) - var/datum/holocall/HC = I - HC.Disconnect(src) + for(var/datum/holocall/holocall_to_disconnect as anything in holo_calls) + holocall_to_disconnect.Disconnect(src) /obj/machinery/holopad/Topic(href, href_list) if(..() || isAI(usr)) @@ -340,6 +386,8 @@ Possible to do for anyone motivated enough: else//If there is a hologram, remove it. clear_holo(user) +//this really should not be processing by default with how common holopads are +//everything in here can start processing if need be once first set and stop processing after being unset /obj/machinery/holopad/process() if(LAZYLEN(masters)) for(var/I in masters) @@ -456,6 +504,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ /obj/machinery/holopad/proc/set_holo(mob/living/user, var/obj/effect/overlay/holo_pad_hologram/h) LAZYSET(masters, user, h) LAZYSET(holorays, user, new /obj/effect/overlay/holoray(loc)) + set_can_hear_flags(CAN_HEAR_MASTERS) var/mob/living/silicon/ai/AI = user if(istype(AI)) AI.current_holopad = src @@ -475,6 +524,8 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ AI.current_holopad = null AI.ai_hologram = null LAZYREMOVE(masters, user) // Discard AI from the list of those who use holopad + if(!LAZYLEN(masters)) + set_can_hear_flags(CAN_HEAR_MASTERS, set_flag = FALSE) qdel(holorays[user]) LAZYREMOVE(holorays, user) SetLightsAndPower() @@ -594,6 +645,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ return disk.record = new record_mode = TRUE + set_can_hear_flags(CAN_HEAR_RECORD_MODE) record_start = world.time record_user = user disk.record.set_caller_image(user) @@ -671,6 +723,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ temp = null record_user = null updateDialog() + set_can_hear_flags(CAN_HEAR_RECORD_MODE, FALSE) /obj/machinery/holopad/proc/record_clear() if(disk && disk.record) @@ -711,3 +764,7 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/ #undef HOLOPAD_PASSIVE_POWER_USAGE #undef HOLOGRAM_POWER_USAGE +#undef CAN_HEAR_MASTERS +#undef CAN_HEAR_ACTIVE_HOLOCALLS +#undef CAN_HEAR_RECORD_MODE +#undef CAN_HEAR_ALL_FLAGS diff --git a/code/game/machinery/requests_console.dm b/code/game/machinery/requests_console.dm index ee098617fd105..0e359250bb1fe 100644 --- a/code/game/machinery/requests_console.dm +++ b/code/game/machinery/requests_console.dm @@ -160,7 +160,7 @@ GLOBAL_LIST_EMPTY(req_console_ckey_departments) GLOB.req_console_ckey_departments[ckey(department)] = department // and then we set ourselves a listed name Radio = new /obj/item/radio(src) - Radio.listening = 0 + Radio.set_listening(FALSE) /obj/machinery/requests_console/Destroy() QDEL_NULL(Radio) diff --git a/code/game/machinery/suit_storage_unit.dm b/code/game/machinery/suit_storage_unit.dm index c0e616567412b..cb3b618366e5e 100644 --- a/code/game/machinery/suit_storage_unit.dm +++ b/code/game/machinery/suit_storage_unit.dm @@ -434,7 +434,7 @@ if(storage) storage.take_damage(burn_damage * 10, BURN, FIRE) // The wires get damaged too. - wires.cut_all() + wires.cut_all(null) if(!toasted) //Special toast check to prevent a double finishing message. if(mob_occupant) visible_message("[src]'s door slides open, barraging you with the nauseating smell of charred flesh.") diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm index b0431004d0a4b..fb24f329629fb 100644 --- a/code/game/machinery/syndicatebomb.dm +++ b/code/game/machinery/syndicatebomb.dm @@ -109,6 +109,7 @@ try_detonate(TRUE) /obj/machinery/syndicatebomb/examine(mob/user) + balloon_alert(user, "[seconds_remaining()]") . = ..() . += {"A digital display on it reads "[seconds_remaining()]"."} @@ -272,7 +273,7 @@ /obj/machinery/syndicatebomb/empty/Initialize(mapload) . = ..() - wires.cut_all() + wires.cut_all(null) /obj/machinery/syndicatebomb/self_destruct name = "self-destruct device" diff --git a/code/game/machinery/telecomms/broadcasting.dm b/code/game/machinery/telecomms/broadcasting.dm index e3ad98a426b0a..96522e0f56946 100644 --- a/code/game/machinery/telecomms/broadcasting.dm +++ b/code/game/machinery/telecomms/broadcasting.dm @@ -141,35 +141,43 @@ if(compression > 0) message = Gibberish(message, compression >= 30) + var/list/signal_reaches_every_z_level = levels + + if(0 in levels) + signal_reaches_every_z_level = RADIO_NO_Z_LEVEL_RESTRICTION + // Assemble the list of radios var/list/radios = list() switch (transmission_method) if (TRANSMISSION_SUBSPACE) // Reaches any radios on the levels - for(var/obj/item/radio/R in GLOB.all_radios["[frequency]"]) - if(R.can_receive(frequency, levels)) - radios += R + var/list/all_radios_of_our_frequency = GLOB.all_radios["[frequency]"] + radios = all_radios_of_our_frequency.Copy() + + for(var/obj/item/radio/subspace_radio in radios) + if(!subspace_radio.can_receive(frequency, signal_reaches_every_z_level)) + radios -= subspace_radio // Syndicate radios can hear all well-known radio channels if (num2text(frequency) in GLOB.reverseradiochannels) - for(var/obj/item/radio/R in GLOB.all_radios["[FREQ_SYNDICATE]"]) - if(R.can_receive(FREQ_SYNDICATE, list(R.get_virtual_z_level()))) - radios |= R + for(var/obj/item/radio/syndicate_radios in GLOB.all_radios["[FREQ_SYNDICATE]"]) + if(syndicate_radios.can_receive(FREQ_SYNDICATE, RADIO_NO_Z_LEVEL_RESTRICTION)) + radios |= syndicate_radios if (TRANSMISSION_RADIO) // Only radios not currently in subspace mode - for(var/obj/item/radio/R in GLOB.all_radios["[frequency]"]) - if(!R.subspace_transmission && R.can_receive(frequency, levels)) - radios += R + for(var/obj/item/radio/non_subspace_radio in GLOB.all_radios["[frequency]"]) + if(!non_subspace_radio.subspace_transmission && non_subspace_radio.can_receive(frequency, signal_reaches_every_z_level)) + radios += non_subspace_radio if (TRANSMISSION_SUPERSPACE) // Only radios which are independent - for(var/obj/item/radio/R in GLOB.all_radios["[frequency]"]) - if(R.independent && R.can_receive(frequency, levels)) - radios += R + for(var/obj/item/radio/independent_radio in GLOB.all_radios["[frequency]"]) + if(independent_radio.independent && independent_radio.can_receive(frequency, signal_reaches_every_z_level)) + radios += independent_radio // From the list of radios, find all mobs who can hear those. - var/list/receive = get_mobs_in_radio_ranges(radios) + var/list/receive = get_hearers_in_radio_ranges(radios) // Cut out mobs with clients who are admins and have radio chatter disabled. for(var/mob/R in receive) @@ -187,7 +195,12 @@ var/list/message_mods = data["mods"] var/rendered = virt.compose_message(virt, language, message, frequency, spans) var/list/show_overhead_message_to = list() - for(var/atom/movable/hearer in receive) + + for(var/atom/movable/hearer as anything in receive) + if(!hearer) + stack_trace("null found in the hearers list returned by the spatial grid. this is bad") + continue + if(ismob(hearer)) var/mob/M = hearer if(M.should_show_chat_message(virt, language, FALSE, is_heard = TRUE)) @@ -211,7 +224,7 @@ var/log_text = "\[[get_radio_name(frequency)]\] [spans_part]\"[message]\" (language: [lang_name])" var/mob/source_mob = virt.source - if(istype(source_mob)) + if(ismob(source_mob)) source_mob.log_message(log_text, LOG_TELECOMMS) else log_telecomms("[virt.source] [log_text] [loc_name(get_turf(virt.source))]") diff --git a/code/game/machinery/telecomms/machine_interactions.dm b/code/game/machinery/telecomms/machine_interactions.dm index cd0f1fd32a5a5..25ca9b563a6e8 100644 --- a/code/game/machinery/telecomms/machine_interactions.dm +++ b/code/game/machinery/telecomms/machine_interactions.dm @@ -111,7 +111,7 @@ return else for(var/obj/machinery/telecomms/T in links) - T.links.Remove(src) + remove_link(T) T.ui_update() network = params["value"] links = list() @@ -138,24 +138,11 @@ if("unlink") var/obj/machinery/telecomms/T = links[text2num(params["value"])] if(T) - // Remove link entries from both T and src. - if(T.links) - T.links.Remove(src) - T.ui_update() - links.Remove(T) - log_game("[key_name(usr)] unlinked [src] and [T] at [AREACOORD(src)].") - . = TRUE + . = remove_link(T, usr) if("link") if(heldmultitool) var/obj/machinery/telecomms/T = heldmultitool.target - if(istype(T) && T != src) - if(!(src in T.links)) - T.links += src - T.ui_update() - if(!(T in links)) - links += T - log_game("[key_name(usr)] linked [src] for [T] at [AREACOORD(src)].") - . = TRUE + . = add_new_link(T, usr) if("buffer") STORE_IN_BUFFER(heldmultitool.parent, src) . = TRUE @@ -166,6 +153,46 @@ if(add_act(action, params)) . = TRUE +///adds new_connection to src's links list AND vice versa. also updates links_by_telecomms_type +/obj/machinery/telecomms/proc/add_new_link(obj/machinery/telecomms/new_connection, mob/user) + if(!istype(new_connection) || new_connection == src) + return FALSE + + if((new_connection in links) && (src in new_connection.links)) + return FALSE + + links |= new_connection + new_connection.links |= src + new_connection.ui_update() + + LAZYADDASSOCLIST(links_by_telecomms_type, new_connection.telecomms_type, new_connection) + LAZYADDASSOCLIST(new_connection.links_by_telecomms_type, telecomms_type, src) + + if(user) + log_game("[key_name(user)] linked [src] for [new_connection] at [AREACOORD(src)].") + return TRUE + +///removes old_connection from src's links list AND vice versa. also updates links_by_telecomms_type +/obj/machinery/telecomms/proc/remove_link(obj/machinery/telecomms/old_connection, mob/user) + if(!istype(old_connection) || old_connection == src) + return FALSE + + if(old_connection in links) + links -= old_connection + LAZYREMOVEASSOC(links_by_telecomms_type, old_connection.telecomms_type, old_connection) + + + if(src in old_connection.links) + old_connection.links -= src + LAZYREMOVEASSOC(old_connection.links_by_telecomms_type, telecomms_type, src) + + old_connection.ui_update() + + if(user) + log_game("[key_name(user)] unlinked [src] and [old_connection] at [AREACOORD(src)].") + + return TRUE + /obj/machinery/telecomms/proc/add_option() return diff --git a/code/game/machinery/telecomms/machines/broadcaster.dm b/code/game/machinery/telecomms/machines/broadcaster.dm index 3649ef47ccaaf..7ae10d4ffbbae 100644 --- a/code/game/machinery/telecomms/machines/broadcaster.dm +++ b/code/game/machinery/telecomms/machines/broadcaster.dm @@ -12,6 +12,7 @@ GLOBAL_VAR_INIT(message_delay, 0) // To make sure restarting the recentmessages name = "subspace broadcaster" icon_state = "broadcaster" desc = "A dish-shaped machine used to broadcast processed subspace signals." + telecomms_type = /obj/machinery/telecomms/broadcaster density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 25 diff --git a/code/game/machinery/telecomms/machines/bus.dm b/code/game/machinery/telecomms/machines/bus.dm index 798b43120d98c..6846d57098455 100644 --- a/code/game/machinery/telecomms/machines/bus.dm +++ b/code/game/machinery/telecomms/machines/bus.dm @@ -12,6 +12,7 @@ name = "bus mainframe" icon_state = "bus" desc = "A mighty piece of hardware used to send massive amounts of data quickly." + telecomms_type = /obj/machinery/telecomms/bus density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 50 diff --git a/code/game/machinery/telecomms/machines/hub.dm b/code/game/machinery/telecomms/machines/hub.dm index aabe884af0866..d8c9b3f478041 100644 --- a/code/game/machinery/telecomms/machines/hub.dm +++ b/code/game/machinery/telecomms/machines/hub.dm @@ -12,6 +12,7 @@ name = "telecommunication hub" icon_state = "hub" desc = "A mighty piece of hardware used to send/receive massive amounts of data." + telecomms_type = /obj/machinery/telecomms/hub density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 80 diff --git a/code/game/machinery/telecomms/machines/message_server.dm b/code/game/machinery/telecomms/machines/message_server.dm index 3f093e9ab9b60..a1c489fe4467b 100644 --- a/code/game/machinery/telecomms/machines/message_server.dm +++ b/code/game/machinery/telecomms/machines/message_server.dm @@ -73,6 +73,7 @@ icon_state = "message_server" name = "Messaging Server" desc = "A machine that processes and routes PDA and request console messages." + telecomms_type = /obj/machinery/telecomms/message_server density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 10 diff --git a/code/game/machinery/telecomms/machines/processor.dm b/code/game/machinery/telecomms/machines/processor.dm index 29871a76c1b0a..5c6a3f92a9eba 100644 --- a/code/game/machinery/telecomms/machines/processor.dm +++ b/code/game/machinery/telecomms/machines/processor.dm @@ -10,6 +10,7 @@ name = "processor unit" icon_state = "processor" desc = "This machine is used to process large quantities of information." + telecomms_type = /obj/machinery/telecomms/processor density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 30 diff --git a/code/game/machinery/telecomms/machines/receiver.dm b/code/game/machinery/telecomms/machines/receiver.dm index faddc03309177..1f0a2ec4753fe 100644 --- a/code/game/machinery/telecomms/machines/receiver.dm +++ b/code/game/machinery/telecomms/machines/receiver.dm @@ -10,6 +10,7 @@ name = "subspace receiver" icon_state = "broadcast receiver" desc = "This machine has a dish-like shape and green lights. It is designed to detect and process subspace radio activity." + telecomms_type = /obj/machinery/telecomms/receiver density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 30 diff --git a/code/game/machinery/telecomms/machines/relay.dm b/code/game/machinery/telecomms/machines/relay.dm index ddee3b3ad8b39..27652e4af2e2a 100644 --- a/code/game/machinery/telecomms/machines/relay.dm +++ b/code/game/machinery/telecomms/machines/relay.dm @@ -10,6 +10,7 @@ name = "telecommunication relay" icon_state = "relay" desc = "A mighty piece of hardware used to send massive amounts of data far away." + telecomms_type = /obj/machinery/telecomms/relay density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 30 diff --git a/code/game/machinery/telecomms/machines/server.dm b/code/game/machinery/telecomms/machines/server.dm index e293f82af4ad5..a90f707e6a7be 100644 --- a/code/game/machinery/telecomms/machines/server.dm +++ b/code/game/machinery/telecomms/machines/server.dm @@ -9,6 +9,7 @@ name = "telecommunication server" icon_state = "comm_server" desc = "A machine used to store data and network statistics." + telecomms_type = /obj/machinery/telecomms/server density = TRUE use_power = IDLE_POWER_USE idle_power_usage = 15 diff --git a/code/game/machinery/telecomms/telecomunications.dm b/code/game/machinery/telecomms/telecomunications.dm index 4c4b109df2478..183c75955b45d 100644 --- a/code/game/machinery/telecomms/telecomunications.dm +++ b/code/game/machinery/telecomms/telecomunications.dm @@ -18,26 +18,46 @@ GLOBAL_LIST_EMPTY(telecomms_list) icon = 'icons/obj/machines/telecomms.dmi' critical_machine = TRUE light_color = LIGHT_COLOR_CYAN - var/list/links = list() // list of machines this machine is linked to - var/traffic = 0 // value increases as traffic increases - var/netspeed = 2.5 // how much traffic to lose per second (50 gigabytes/second * netspeed) - var/list/autolinkers = list() // list of text/number values to link with - var/id = "NULL" // identification string - var/network = "NULL" // the network of the machinery - - var/list/freq_listening = list() // list of frequencies to tune into: if none, will listen to all + /// list of machines this machine is linked to + var/list/links = list() + /** + * associative lazylist list of the telecomms_type of linked telecomms machines and a list of said machines. + * eg list(telecomms_type1 = list(everything linked to us with that type), telecomms_type2 = list(everything linked to us with THAT type)...) + */ + var/list/links_by_telecomms_type + /// value increases as traffic increases + var/traffic = 0 + /// how much traffic to lose per second (50 gigabytes/second * netspeed) + var/netspeed = 2.5 + /// list of text/number values to link with + var/list/autolinkers = list() + /// identification string + var/id = "NULL" + /// the relevant type path of this telecomms machine eg /obj/machinery/telecomms/server but not server/preset. used for links_by_telecomms_type + var/telecomms_type = null + /// the network of the machinery + var/network = "NULL" + + // list of frequencies to tune into: if none, will listen to all + var/list/freq_listening = list() var/on = TRUE - var/toggled = TRUE // Is it toggled on - var/long_range_link = FALSE // Can you link it across Z levels or on the otherside of the map? (Relay & Hub) - var/hide = FALSE // Is it a hidden machine? - - + /// Is it toggled on + var/toggled = TRUE + /// Can you link it across Z levels or on the otherside of the map? (Relay & Hub) + var/long_range_link = FALSE + /// Is it a hidden machine? + var/hide = FALSE + +/// relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending /obj/machinery/telecomms/proc/relay_information(datum/signal/subspace/signal, filter, copysig, amount = 20) - // relay signal to all linked machinery that are of type [filter]. If signal has been sent [amount] times, stop sending if(!on) return + + if(!filter || !ispath(filter, /obj/machinery/telecomms)) + CRASH("null or non /obj/machinery/telecomms typepath given as the filter argument! given typepath: [filter]") + var/send_count = 0 // Apply some lag based on traffic rates @@ -46,24 +66,23 @@ GLOBAL_LIST_EMPTY(telecomms_list) signal.data["slow"] = netlag // Loop through all linked machines and send the signal or copy. - for(var/obj/machinery/telecomms/machine in links) - if(filter && !istype( machine, filter )) - continue - if(!machine.on) + + for(var/obj/machinery/telecomms/filtered_machine in links_by_telecomms_type?[filter]) + if(!filtered_machine.on) continue if(amount && send_count >= amount) break - if(get_virtual_z_level() != machine.loc.get_virtual_z_level() && !long_range_link && !machine.long_range_link) + if(get_virtual_z_level() != filtered_machine.loc.get_virtual_z_level() && !long_range_link && !filtered_machine.long_range_link) continue send_count++ - if(machine.is_freq_listening(signal)) - machine.traffic++ + if(filtered_machine.is_freq_listening(signal)) + filtered_machine.traffic++ if(copysig) - machine.receive_information(signal.copy(), src) + filtered_machine.receive_information(signal.copy(), src) else - machine.receive_information(signal, src) + filtered_machine.receive_information(signal, src) if(send_count > 0 && is_freq_listening(signal)) traffic++ @@ -74,12 +93,13 @@ GLOBAL_LIST_EMPTY(telecomms_list) // send signal directly to a machine machine.receive_information(signal, src) +///receive information from linked machinery /obj/machinery/telecomms/proc/receive_information(datum/signal/signal, obj/machinery/telecomms/machine_from) - // receive information from linked machinery + return /obj/machinery/telecomms/proc/is_freq_listening(datum/signal/signal) // return TRUE if found, FALSE if not found - return signal && (!freq_listening.len || (signal.frequency in freq_listening)) + return signal && (!length(freq_listening) || (signal.frequency in freq_listening)) /obj/machinery/telecomms/Initialize(mapload) . = ..() @@ -91,17 +111,17 @@ GLOBAL_LIST_EMPTY(telecomms_list) ..() for(var/obj/machinery/telecomms/telecomms_machine in GLOB.telecomms_list) if (long_range_link || IN_GIVEN_RANGE(src, telecomms_machine, 20)) - add_link(telecomms_machine) + add_automatic_link(telecomms_machine) /obj/machinery/telecomms/Destroy() GLOB.telecomms_list -= src for(var/obj/machinery/telecomms/comm in GLOB.telecomms_list) - comm.links -= src + remove_link(comm) links = list() return ..() // Used in auto linking -/obj/machinery/telecomms/proc/add_link(obj/machinery/telecomms/T) +/obj/machinery/telecomms/proc/add_automatic_link(obj/machinery/telecomms/T) var/turf/position = get_turf(src) var/turf/T_position = get_turf(T) var/same_zlevel = FALSE @@ -109,11 +129,12 @@ GLOBAL_LIST_EMPTY(telecomms_list) if(position.get_virtual_z_level() == T_position.get_virtual_z_level()) same_zlevel = TRUE if(same_zlevel || (long_range_link && T.long_range_link)) - if(src != T) - for(var/x in autolinkers) - if(x in T.autolinkers) - links |= T - T.links |= src + if(src == T) + return + for(var/autolinker_id in autolinkers) + if(autolinker_id in T.autolinkers) + add_new_link(T) + return /obj/machinery/telecomms/update_icon() diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm index bde20b4ddb8b8..72188002f4287 100644 --- a/code/game/objects/buckling.dm +++ b/code/game/objects/buckling.dm @@ -197,7 +197,7 @@ return FALSE // If we're checking the loc, make sure the target is on the thing we're bucking them to. - if(check_loc && target.loc != loc) + if(check_loc && !target.Adjacent(src)) return FALSE // Make sure the target isn't already buckled to something. diff --git a/code/game/objects/effects/effect_system/effects_sparks.dm b/code/game/objects/effects/effect_system/effects_sparks.dm index b0623b8d7fc88..8fb377e1b77f9 100644 --- a/code/game/objects/effects/effect_system/effects_sparks.dm +++ b/code/game/objects/effects/effect_system/effects_sparks.dm @@ -28,7 +28,7 @@ return INITIALIZE_HINT_LATELOAD /obj/effect/particle_effect/sparks/LateInitialize() - flick("sparks", src) // replay the animation + flick(icon_state, src) // replay the animation playsound(src, "sparks", 100, TRUE) var/turf/T = loc if(isturf(T)) @@ -59,3 +59,17 @@ /datum/effect_system/lightning_spread effect_type = /obj/effect/particle_effect/sparks/electricity + +// shield sparks +/obj/effect/particle_effect/sparks/shield + name = "shield sparks" + icon_state = "shieldsparkles" + +/obj/effect/particle_effect/sparks/shield/Initialize(mapload) + . = ..() + // every particle has a little different color + var/generator/gen_color = generator("color", LIGHT_COLOR_WHITE, LIGHT_COLOR_ELECTRIC_CYAN) + var/rand_color = gen_color.Rand() + color = rand_color + set_light_color(rand_color) + diff --git a/code/game/objects/items/crab17.dm b/code/game/objects/items/crab17.dm index 86c70df846b98..60b1769475811 100644 --- a/code/game/objects/items/crab17.dm +++ b/code/game/objects/items/crab17.dm @@ -39,6 +39,7 @@ pixel_z = -8 layer = LARGE_MOB_LAYER max_integrity = 600 + max_hit_damage = 30 /// when this gets at this hp, it will run away! oh no! var/next_health_to_teleport var/mob/living/carbon/human/bogdanoff diff --git a/code/game/objects/items/devices/paicard.dm b/code/game/objects/items/devices/paicard.dm index d3fda33147799..8ff8fb726f7e7 100644 --- a/code/game/objects/items/devices/paicard.dm +++ b/code/game/objects/items/devices/paicard.dm @@ -156,7 +156,7 @@ pai.can_transmit = !pai.can_transmit else //receiving pai.can_receive = !pai.can_receive - pai.radio.wires.cut(transmit_holder)//wires.cut toggles cut and uncut states + pai.radio.wires.cut(transmit_holder, usr)//wires.cut toggles cut and uncut states transmit_holder = (transmitting ? pai.can_transmit : pai.can_receive) //recycling can be fun! to_chat(usr, "You [transmit_holder ? "enable" : "disable"] your pAI's [transmitting ? "outgoing" : "incoming"] radio transmissions!") to_chat(pai, "Your owner has [transmit_holder ? "enabled" : "disabled"] your [transmitting ? "outgoing" : "incoming"] radio transmissions!") diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 4a9b7645e2e74..0c8205c248871 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -29,8 +29,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( var/bang_protect = 0 //this isn't technically clothing so it needs its own bang_protect var slot_flags = ITEM_SLOT_EARS - var/obj/item/encryptionkey/keyslot2 = null dog_fashion = null + var/obj/item/encryptionkey/keyslot2 = null /obj/item/radio/headset/suicide_act(mob/living/carbon/user) user.visible_message("[user] begins putting \the [src]'s antenna up [user.p_their()] nose! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer!") @@ -59,26 +59,24 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/Initialize(mapload) . = ..() + set_listening(TRUE) recalculateChannels() + possibly_deactivate_in_loc() + +/obj/item/radio/headset/proc/possibly_deactivate_in_loc() + if(ismob(loc)) + set_listening(should_be_listening) + else + set_listening(FALSE, actual_setting = FALSE) + +/obj/item/radio/headset/Moved(atom/OldLoc, Dir) + . = ..() + possibly_deactivate_in_loc() /obj/item/radio/headset/Destroy() QDEL_NULL(keyslot2) return ..() -/obj/item/radio/headset/talk_into(mob/living/M, message, channel, list/spans, datum/language/language, list/message_mods) - if (!listening) - return ITALICS | REDUCE_RANGE - return ..() - -/obj/item/radio/headset/can_receive(freq, level, AIuser) - if(ishuman(src.loc)) - var/mob/living/carbon/human/H = src.loc - if(H.ears == src) - return ..(freq, level) - else if(AIuser) - return ..(freq, level) - return FALSE - /obj/item/radio/headset/ui_data(mob/user) . = ..() .["headset"] = TRUE @@ -101,6 +99,7 @@ GLOBAL_LIST_INIT(channel_tokens, list( make_syndie() /obj/item/radio/headset/binary + /obj/item/radio/headset/binary/Initialize(mapload) . = ..() qdel(keyslot) @@ -315,9 +314,6 @@ GLOBAL_LIST_INIT(channel_tokens, list( keyslot2 = new /obj/item/encryptionkey/ai command = TRUE -/obj/item/radio/headset/silicon/can_receive(freq, level) - return ..(freq, level, TRUE) - /obj/item/radio/headset/attackby(obj/item/W, mob/user, params) user.set_machine(src) @@ -364,11 +360,11 @@ GLOBAL_LIST_INIT(channel_tokens, list( /obj/item/radio/headset/recalculateChannels() - ..() + . = ..() if(keyslot2) for(var/ch_name in keyslot2.channels) if(!(ch_name in src.channels)) - channels[ch_name] = keyslot2.channels[ch_name] + LAZYSET(channels, ch_name, keyslot2.channels[ch_name]) if(keyslot2.translate_binary) translate_binary = TRUE @@ -379,8 +375,8 @@ GLOBAL_LIST_INIT(channel_tokens, list( if (keyslot2.amplification) command = TRUE - for(var/ch_name in channels) - secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) + for(var/ch_name in channels) + secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) /obj/item/radio/headset/AltClick(mob/living/user) if(!istype(user) || !Adjacent(user) || user.incapacitated()) diff --git a/code/game/objects/items/devices/radio/intercom.dm b/code/game/objects/items/devices/radio/intercom.dm index e448d54434215..fe6f1f5c34c79 100644 --- a/code/game/objects/items/devices/radio/intercom.dm +++ b/code/game/objects/items/devices/radio/intercom.dm @@ -76,17 +76,11 @@ return GLOB.physical_state // But monkeys can't use default state, and they can already use hotkeys -/obj/item/radio/intercom/can_receive(freq, level) - if(!on) - return FALSE - if(wires.is_cut(WIRE_RX)) - return FALSE - if(!(0 in level)) +/obj/item/radio/intercom/can_receive(freq, list/levels) + if(levels != RADIO_NO_Z_LEVEL_RESTRICTION) var/turf/position = get_turf(src) - if(isnull(position) || !(position.get_virtual_z_level() in level)) + if(isnull(position) || !(position.get_virtual_z_level() in levels)) return FALSE - if(!listening) - return FALSE if(freq == FREQ_SYNDICATE) if(!(syndie)) return FALSE//Prevents broadcast of messages over devices lacking the encryption @@ -143,9 +137,9 @@ var/area/current_area = get_area(src) if(!current_area) - on = FALSE + set_on(FALSE) else - on = current_area.powered(AREA_USAGE_EQUIP) // set "on" to the equipment power status of our area. + set_on(current_area.powered(AREA_USAGE_EQUIP)) // set "on" to the equipment power status of our area. update_icon() /obj/item/radio/intercom/add_blood_DNA(list/blood_dna) @@ -165,8 +159,11 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom, 26) /obj/item/radio/intercom/chapel name = "Confessional intercom" anonymize = TRUE - frequency = 1481 - broadcasting = TRUE + +/obj/item/radio/intercom/chapel/Initialize(mapload, ndir, building) + . = ..() + set_frequency(1481) + set_broadcasting(TRUE) //MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/prison, 26) MAPPING_DIRECTIONAL_HELPERS(/obj/item/radio/intercom/chapel, 26) diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm index 93241ea271168..e6ceb83e751dd 100644 --- a/code/game/objects/items/devices/radio/radio.dm +++ b/code/game/objects/items/devices/radio/radio.dm @@ -17,38 +17,90 @@ custom_materials = list(/datum/material/iron=75, /datum/material/glass=25) obj_flags = USES_TGUI - var/on = TRUE - var/frequency = FREQ_COMMON - var/canhear_range = 3 // The range around the radio in which mobs can hear what it receives. - var/emped = 0 // Tracks the number of EMPs currently stacked. - var/headset = FALSE + ///if FALSE, broadcasting and listening dont matter and this radio shouldnt do anything + VAR_PRIVATE/on = TRUE + ///the "default" radio frequency this radio is set to, listens and transmits to this frequency by default. wont work if the channel is encrypted + VAR_PRIVATE/frequency = FREQ_COMMON + + /// Whether the radio will transmit dialogue it hears nearby into its radio channel. + VAR_PRIVATE/broadcasting = FALSE + /// Whether the radio is currently receiving radio messages from its radio frequencies. + VAR_PRIVATE/listening = TRUE + + //the below three vars are used to track listening and broadcasting should they be forced off for whatever reason but "supposed" to be active + //eg player sets the radio to listening, but an emp or whatever turns it off, its still supposed to be activated but was forced off, + //when it wears off it sets listening to should_be_listening + + ///used for tracking what broadcasting should be in the absence of things forcing it off, eg its set to broadcast but gets emp'd temporarily + var/should_be_broadcasting = FALSE + ///used for tracking what listening should be in the absence of things forcing it off, eg its set to listen but gets emp'd temporarily + var/should_be_listening = TRUE + + /// Both the range around the radio in which mobs can hear what it receives and the range the radio can hear + var/canhear_range = 3 + /// Tracks the number of EMPs currently stacked. + var/emped = 0 + + /// If true, the transmit wire starts cut. + var/prison_radio = FALSE + /// Whether wires are accessible. Toggleable by screwdrivering. + var/unscrewed = FALSE + /// If true, the radio has access to the full spectrum. + var/freerange = FALSE + /// If true, the radio transmits and receives on subspace exclusively. + var/subspace_transmission = FALSE + /// If true, subspace_transmission can be toggled at will. + var/subspace_switchable = FALSE + /// Frequency lock to stop the user from untuning specialist radios. + var/freqlock = FALSE + /// If true, broadcasts will be large and BOLD. + var/use_command = FALSE + /// If true, use_command can be toggled at will. + var/command = FALSE + - var/broadcasting = FALSE // Whether the radio will transmit dialogue it hears nearby. - var/listening = TRUE // Whether the radio is currently receiving. - var/prison_radio = FALSE // If true, the transmit wire starts cut. - var/unscrewed = FALSE // Whether wires are accessible. Toggleable by screwdrivering. - var/freerange = FALSE // If true, the radio has access to the full spectrum. - var/subspace_transmission = FALSE // If true, the radio transmits and receives on subspace exclusively. - var/subspace_switchable = FALSE // If true, subspace_transmission can be toggled at will. - var/freqlock = FALSE // Frequency lock to stop the user from untuning specialist radios. - var/use_command = FALSE // If true, broadcasts will be large and BOLD. - var/command = FALSE // If true, use_command can be toggled at will. + var/headset = FALSE ///makes anyone who is talking through this anonymous. var/anonymize = FALSE // Encryption key handling var/obj/item/encryptionkey/keyslot - var/translate_binary = FALSE // If true, can hear the special binary channel. - var/independent = FALSE // If true, can say/hear on the special CentCom channel. - var/syndie = FALSE // If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel. - var/list/channels = list() // Map from name (see communications.dm) to on/off. First entry is current department (:h). + /// If true, can hear the special binary channel. + var/translate_binary = FALSE + /// If true, can say/hear on the special CentCom channel. + var/independent = FALSE + /// If true, hears all well-known channels automatically, and can say/hear on the Syndicate channel. + var/syndie = FALSE + /// associative list of the encrypted radio channels this radio is currently set to listen/broadcast to, of the form: list(channel name = TRUE or FALSE) + var/list/channels + /// associative list of the encrypted radio channels this radio can listen/broadcast to, of the form: list(channel name = channel frequency) var/list/secure_radio_connections - var/radio_silent = FALSE // If true, radio doesn't make sound effects (ie for Syndicate internal radio implants) + // If true, radio doesn't make sound effects (ie for Syndicate internal radio implants) + var/radio_silent = FALSE -/obj/item/radio/suicide_act(mob/living/user) - user.visible_message("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") - return BRUTELOSS +/obj/item/radio/Initialize(mapload) + wires = new /datum/wires/radio(src) + if(prison_radio) + wires.cut(WIRE_TX, null) // OH GOD WHY + secure_radio_connections = list() + . = ..() + + for(var/ch_name in channels) + secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) + + set_listening(listening) + set_broadcasting(broadcasting) + set_frequency(sanitize_frequency(frequency, freerange)) + set_on(on) + + AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES) + +/obj/item/radio/Destroy() + remove_radio_all(src) //Just to be sure + QDEL_NULL(wires) + QDEL_NULL(keyslot) + return ..() /obj/item/radio/proc/set_frequency(new_frequency) SEND_SIGNAL(src, COMSIG_RADIO_NEW_FREQUENCY, args) @@ -56,16 +108,13 @@ frequency = add_radio(src, new_frequency) /obj/item/radio/proc/recalculateChannels() - channels = list() - translate_binary = FALSE - syndie = FALSE - independent = FALSE + resetChannels() command = initial(command) if(keyslot) - for(var/ch_name in keyslot.channels) - if(!(ch_name in channels)) - channels[ch_name] = keyslot.channels[ch_name] + for(var/channel_name in keyslot.channels) + if(!(channel_name in channels)) + channels[channel_name] = keyslot.channels[channel_name] if(keyslot.translate_binary) translate_binary = TRUE @@ -82,37 +131,27 @@ for(var/ch_name in channels) secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) +/obj/item/radio/proc/resetChannels() + channels = list() + secure_radio_connections = list() + translate_binary = FALSE + syndie = FALSE + independent = FALSE + +///goes through all radio channels we should be listening for and readds them to the global list +/obj/item/radio/proc/readd_listening_radio_channels() + for(var/channel_name in channels) + add_radio(src, GLOB.radiochannels[channel_name]) + + add_radio(src, FREQ_COMMON) + /obj/item/radio/proc/make_syndie() // Turns normal radios into Syndicate radios! qdel(keyslot) keyslot = new /obj/item/encryptionkey/syndicate - syndie = 1 + syndie = TRUE recalculateChannels() ui_update() -/obj/item/radio/Destroy() - remove_radio_all(src) //Just to be sure - QDEL_NULL(wires) - QDEL_NULL(keyslot) - return ..() - -/obj/item/radio/Initialize(mapload) - wires = new /datum/wires/radio(src) - if(prison_radio) - wires.cut(WIRE_TX) // OH GOD WHY - secure_radio_connections = new - . = ..() - frequency = sanitize_frequency(frequency, freerange) - set_frequency(frequency) - - for(var/ch_name in channels) - secure_radio_connections[ch_name] = add_radio(src, GLOB.radiochannels[ch_name]) - - become_hearing_sensitive(ROUNDSTART_TRAIT) - -/obj/item/radio/ComponentInitialize() - . = ..() - AddElement(/datum/element/empprotection, EMP_PROTECT_WIRES) - /obj/item/radio/AltClick(mob/user) if(headset) . = ..() @@ -136,90 +175,73 @@ else ..() -/obj/item/radio/ui_state(mob/user) - return GLOB.inventory_state - -/obj/item/radio/ui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) - . = ..() - ui = SStgui.try_update_ui(user, src, ui) - if(!ui) - ui = new(user, src, "Radio") - if(state) - ui.state = state - ui.open() - -/obj/item/radio/ui_data(mob/user) - var/list/data = list() - - data["broadcasting"] = broadcasting - data["listening"] = listening - data["frequency"] = frequency - data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ - data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ - data["freqlock"] = freqlock - data["channels"] = list() - for(var/channel in channels) - data["channels"][channel] = channels[channel] & FREQ_LISTENING - data["command"] = command - data["useCommand"] = use_command - data["subspace"] = subspace_transmission - data["subspaceSwitchable"] = subspace_switchable - data["headset"] = FALSE - - return data - -/obj/item/radio/ui_act(action, params, datum/tgui/ui) - if(..()) - return - switch(action) - if("frequency") - if(freqlock) - return - var/tune = params["tune"] - var/adjust = text2num(params["adjust"]) - if(tune == "input") - var/min = format_frequency(freerange ? MIN_FREE_FREQ : MIN_FREQ) - var/max = format_frequency(freerange ? MAX_FREE_FREQ : MAX_FREQ) - tune = input("Tune frequency ([min]-[max]):", name, format_frequency(frequency)) as null|num - if(!isnull(tune) && !..()) - if (tune < MIN_FREE_FREQ && tune <= MAX_FREE_FREQ / 10) - // allow typing 144.7 to get 1447 - tune *= 10 - . = TRUE - else if(adjust) - tune = frequency + adjust * 10 - . = TRUE - else if(text2num(tune) != null) - tune = tune * 10 - . = TRUE - if(.) - set_frequency(sanitize_frequency(tune, freerange)) - if("listen") - listening = !listening - . = TRUE - if("broadcast") - broadcasting = !broadcasting - . = TRUE - if("channel") - var/channel = params["channel"] - if(!(channel in channels)) - return - if(channels[channel] & FREQ_LISTENING) - channels[channel] &= ~FREQ_LISTENING - else - channels[channel] |= FREQ_LISTENING - . = TRUE - if("command") - use_command = !use_command - . = TRUE - if("subspace") - if(subspace_switchable) - subspace_transmission = !subspace_transmission - if(!subspace_transmission) - channels = list() - else - recalculateChannels() - . = TRUE +//simple getters only because i NEED to enforce complex setter use for these vars for caching purposes but VAR_PROTECTED requires getter usage as well. +//if another decorator is made that doesnt require getters feel free to nuke these and change these vars over to that + +///simple getter for the on variable. necessary due to VAR_PROTECTED +/obj/item/radio/proc/is_on() + return on + +///simple getter for the frequency variable. necessary due to VAR_PROTECTED +/obj/item/radio/proc/get_frequency() + return frequency + +///simple getter for the broadcasting variable. necessary due to VAR_PROTECTED +/obj/item/radio/proc/get_broadcasting() + return broadcasting + +///simple getter for the listening variable. necessary due to VAR_PROTECTED +/obj/item/radio/proc/get_listening() + return listening + +//now for setters for the above protected vars + +/** + * setter for the listener var, adds or removes this radio from the global radio list if we are also on + * + * * new_listening - the new value we want to set listening to + * * actual_setting - whether or not the radio is supposed to be listening, sets should_be_listening to the new listening value if true, otherwise just changes listening + */ +/obj/item/radio/proc/set_listening(new_listening, actual_setting = TRUE) + + listening = new_listening + if(actual_setting) + should_be_listening = listening + + if(listening && on) + readd_listening_radio_channels() + else if(!listening) + remove_radio_all(src) + +/** + * setter for broadcasting that makes us not hearing sensitive if not broadcasting and hearing sensitive if broadcasting + * hearing sensitive in this case only matters for the purposes of listening for words said in nearby tiles, talking into us directly bypasses hearing + * + * * new_broadcasting- the new value we want to set broadcasting to + * * actual_setting - whether or not the radio is supposed to be broadcasting, sets should_be_broadcasting to the new value if true, otherwise just changes broadcasting + */ +/obj/item/radio/proc/set_broadcasting(new_broadcasting, actual_setting = TRUE) + + broadcasting = new_broadcasting + if(actual_setting) + should_be_broadcasting = broadcasting + + if(broadcasting && on) //we dont need hearing sensitivity if we arent broadcasting, because talk_into doesnt care about hearing + become_hearing_sensitive(INNATE_TRAIT) + else if(!broadcasting) + lose_hearing_sensitivity(INNATE_TRAIT) + +///setter for the on var that sets both broadcasting and listening to off or whatever they were supposed to be +/obj/item/radio/proc/set_on(new_on) + + on = new_on + + if(on) + set_broadcasting(should_be_broadcasting)//set them to whatever theyre supposed to be + set_listening(should_be_listening) + else + set_broadcasting(FALSE, actual_setting = FALSE)//fake set them to off + set_listening(FALSE, actual_setting = FALSE) /obj/item/radio/talk_into(atom/movable/talking_movable, message, channel, list/spans, datum/language/language, list/message_mods) if(!spans) @@ -336,29 +358,104 @@ talk_into(speaker, raw_message, , spans, language=message_language, message_mods=filtered_mods) // Checks if this radio can receive on the given frequency. -/obj/item/radio/proc/can_receive(freq, level) +/obj/item/radio/proc/can_receive(input_frequency, list/levels) // deny checks - if (!on || !listening || wires.is_cut(WIRE_RX)) - return FALSE - if (freq == FREQ_SYNDICATE && !syndie) - return FALSE - if (freq == FREQ_CENTCOM) - return independent // hard-ignores the z-level check - if (!(0 in level)) + if (levels != RADIO_NO_Z_LEVEL_RESTRICTION) var/turf/position = get_turf(src) - if(!position || !(position.get_virtual_z_level() in level)) + if(!position || !(position.get_virtual_z_level() in levels)) return FALSE + if (input_frequency == FREQ_SYNDICATE && !syndie) + return FALSE + // allow checks: are we listening on that frequency? - if (freq == frequency) + if (input_frequency == frequency) return TRUE for(var/ch_name in channels) if(channels[ch_name] & FREQ_LISTENING) - //the GLOB.radiochannels list is located in communications.dm - if(GLOB.radiochannels[ch_name] == text2num(freq) || syndie) + if(GLOB.radiochannels[ch_name] == text2num(input_frequency) || syndie) return TRUE return FALSE +/obj/item/radio/ui_state(mob/user) + return GLOB.inventory_state + +/obj/item/radio/ui_interact(mob/user, datum/tgui/ui, datum/ui_state/state) + ui = SStgui.try_update_ui(user, src, ui) + if(!ui) + ui = new(user, src, "Radio", name) + if(state) + ui.set_state(state) + ui.open() + +/obj/item/radio/ui_data(mob/user) + var/list/data = list() + + data["broadcasting"] = broadcasting + data["listening"] = listening + data["frequency"] = frequency + data["minFrequency"] = freerange ? MIN_FREE_FREQ : MIN_FREQ + data["maxFrequency"] = freerange ? MAX_FREE_FREQ : MAX_FREQ + data["freqlock"] = freqlock + data["channels"] = list() + for(var/channel in channels) + data["channels"][channel] = channels[channel] & FREQ_LISTENING + data["command"] = command + data["useCommand"] = use_command + data["subspace"] = subspace_transmission + data["subspaceSwitchable"] = subspace_switchable + data["headset"] = FALSE + + return data + +/obj/item/radio/ui_act(action, params, datum/tgui/ui) + . = ..() + if(.) + return + switch(action) + if("frequency") + if(freqlock) + return + var/tune = params["tune"] + var/adjust = text2num(params["adjust"]) + if(adjust) + tune = frequency + adjust * 10 + . = TRUE + else if(text2num(tune) != null) + tune = tune * 10 + . = TRUE + if(.) + set_frequency(sanitize_frequency(tune, freerange)) + if("listen") + set_listening(!listening) + . = TRUE + if("broadcast") + set_broadcasting(!broadcasting) + . = TRUE + if("channel") + var/channel = params["channel"] + if(!(channel in channels)) + return + if(channels[channel] & FREQ_LISTENING) + channels[channel] &= ~FREQ_LISTENING + else + channels[channel] |= FREQ_LISTENING + . = TRUE + if("command") + use_command = !use_command + . = TRUE + if("subspace") + if(subspace_switchable) + subspace_transmission = !subspace_transmission + if(!subspace_transmission) + channels = list() + else + recalculateChannels() + . = TRUE + +/obj/item/radio/suicide_act(mob/living/user) + user.visible_message("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS /obj/item/radio/examine(mob/user) . = ..() @@ -390,14 +487,24 @@ var/curremp = emped //Remember which EMP this was if (listening && ismob(loc)) // if the radio is turned on and on someone's person they notice to_chat(loc, "\The [src] overloads.") - on = FALSE + set_on(FALSE) addtimer(CALLBACK(src, PROC_REF(end_emp_effect), curremp), 200) +/obj/item/radio/suicide_act(mob/living/user) + user.visible_message("[user] starts bouncing [src] off [user.p_their()] head! It looks like [user.p_theyre()] trying to commit suicide!") + return BRUTELOSS + +/obj/item/radio/Destroy() + remove_radio_all(src) //Just to be sure + QDEL_NULL(wires) + QDEL_NULL(keyslot) + return ..() + /obj/item/radio/proc/end_emp_effect(curremp) if(emped != curremp) //Don't fix it if it's been EMP'd again return FALSE emped = FALSE - on = TRUE + set_on(TRUE) return TRUE /obj/item/radio/proc/get_specific_hearers() @@ -419,7 +526,7 @@ . = ..() /obj/item/radio/borg/syndicate - syndie = 1 + syndie = TRUE keyslot = new /obj/item/encryptionkey/syndicate /obj/item/radio/borg/syndicate/Initialize(mapload) @@ -463,7 +570,8 @@ /obj/item/radio/off // Station bounced radios, their only difference is spawning with the speakers off, this was made to help the lag. - listening = 0 // And it's nice to have a subtype too for future features. dog_fashion = /datum/dog_fashion/back - +/obj/item/radio/off/Initialize() + . = ..() + set_listening(FALSE) diff --git a/code/game/objects/items/robot/ai_upgrades.dm b/code/game/objects/items/robot/ai_upgrades.dm index 322a4eefeb7a1..21d196bcda291 100644 --- a/code/game/objects/items/robot/ai_upgrades.dm +++ b/code/game/objects/items/robot/ai_upgrades.dm @@ -38,7 +38,7 @@ return ..() var/mob/living/silicon/ai/AI = A if(AI.eyeobj) - AI.eyeobj.set_relay_speech(TRUE) + AI.eyeobj.relay_speech = TRUE to_chat(AI, "[user] has upgraded you with surveillance software!") to_chat(AI, "Via a combination of hidden microphones and lip reading software, you are able to use your cameras to listen in on conversations.") to_chat(user, "You upgrade [AI]. [src] is consumed in the process.") diff --git a/code/game/objects/items/weaponry.dm b/code/game/objects/items/weaponry.dm index b2bbb5945c85b..2c34e1f6cca52 100644 --- a/code/game/objects/items/weaponry.dm +++ b/code/game/objects/items/weaponry.dm @@ -947,16 +947,17 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 /obj/item/club name = "Billy club" - desc = "Used to bash heads and break down defenses." + desc = "A club designed for breaching enclosed spaces, with an insulated handle-guard to prevent shocks." icon_state = "billyclub" item_state = "classic_baton" lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' - force = 10 + force = 12 throwforce = 5 attack_verb_continuous = list("clubs", "bludgeons") attack_verb_simple = list("club", "bludgeon") item_flags = ISWEAPON + siemens_coefficient = 0 var/breakforce = 30 var/stamforce = 15 @@ -970,17 +971,21 @@ for further reading, please see: https://github.com/tgstation/tgstation/pull/301 H.apply_damage(stamforce, STAMINA, blocked = def_check) return ..() -/obj/item/club/afterattack(atom/A, mob/user, proximity) - . = ..() - if(!proximity) - return - if(istype(A, /obj/structure/window) || istype(A, /obj/machinery/door/window)\ - || istype(A, /obj/structure/windoor_assembly) || istype(A, /obj/structure/table/glass)) //Bonus damage to windows, windoors, and windoor assemblies - var/obj/W = A - W.take_damage(30, BRUTE, MELEE, 0) - else if(istype(A, /obj/structure/grille)) //Bonus damage to grilles - var/obj/structure/grille/G = A - G.take_damage(20, BRUTE, MELEE, 0) +/obj/item/club/pre_attack(atom/A, mob/living/user, params) + force = initial(force) + armour_penetration = initial(armour_penetration) + if(isstructure(A) || ismachinery(A) || isturf(A)) + force *= 4 + armour_penetration += 50 + // To prevent unnecessary force string calculation (we want this to be treated + // as if it wasn't changed) + last_force_string_check = force + return ..() + +/obj/item/club/set_force_string() + // If we do need to calculate the new force string, make sure we are using the original force + force = initial(force) + return ..() /obj/item/club/tailclub name = "tail club" diff --git a/code/game/objects/obj_defense.dm b/code/game/objects/obj_defense.dm index 3aeaa50a71511..4fee093fd8c17 100644 --- a/code/game/objects/obj_defense.dm +++ b/code/game/objects/obj_defense.dm @@ -14,6 +14,8 @@ damage_amount = run_obj_armor(damage_amount, damage_type, damage_flag, attack_dir, armour_penetration) if(damage_amount < DAMAGE_PRECISION) return + if (!isnull(max_hit_damage)) + damage_amount = min(damage_amount, max_hit_damage) //Object is basssiiiiccaalllyyy guaranteed to take damage by this point, lets run our signal if(SEND_SIGNAL(src, COMSIG_OBJ_TAKE_DAMAGE, damage_amount, damage_type, damage_flag, sound_effect, attack_dir, armour_penetration) & COMPONENT_NO_TAKE_DAMAGE) return diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm index b9dcdeb11204b..b2613c87ab729 100644 --- a/code/game/objects/objs.dm +++ b/code/game/objects/objs.dm @@ -18,8 +18,10 @@ var/max_integrity = 500 /// The object will break once obj_integrity reaches this amount in take_damage(). 0 if we have no special broken behavior, otherwise is a percentage of at what point the obj breaks. 0.5 being 50% var/integrity_failure = 0 - ///Damage under this value will be completely ignored + /// Damage under this value will be completely ignored var/damage_deflection = 0 + /// Maximum damage that can be taken in a single hit + var/max_hit_damage = null /// INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | ON_FIRE | UNACIDABLE | ACID_PROOF var/resistance_flags = NONE diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index edb692aa3e896..8bc88789f6ab5 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -27,6 +27,7 @@ return move_delay = TRUE var/oldloc = loc + step(src, direction) if(oldloc != loc) addtimer(CALLBACK(src, PROC_REF(ResetMoveDelay)), CONFIG_GET(number/movedelay/walk_delay) * move_speed_multiplier) else diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 8d68cfdb57219..5d5f99b5e0f8a 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -149,11 +149,11 @@ user.changeNext_move(CLICK_CD_MELEE) add_fingerprint(user) if(W.tool_behaviour == TOOL_WIRECUTTER) - if(!shock(user, 100)) + if(!shock(user, 100 * W.siemens_coefficient)) W.play_tool_sound(src, 100) deconstruct() else if((W.tool_behaviour == TOOL_SCREWDRIVER) && (isturf(loc) || anchored)) - if(!shock(user, 90)) + if(!shock(user, 90 * W.siemens_coefficient)) W.play_tool_sound(src, 100) set_anchored(!anchored) user.visible_message("[user] [anchored ? "fastens" : "unfastens"] [src].", \ @@ -161,7 +161,7 @@ return else if(istype(W, /obj/item/stack/rods) && broken) var/obj/item/stack/rods/R = W - if(!shock(user, 90)) + if(!shock(user, 90 * W.siemens_coefficient)) user.visible_message("[user] rebuilds the broken grille.", \ "You rebuild the broken grille.") new grille_type(src.loc) @@ -210,7 +210,7 @@ return //window placing end - else if(istype(W, /obj/item/shard) || !shock(user, 70)) + else if(istype(W, /obj/item/shard) || !shock(user, 70 * W.siemens_coefficient)) return ..() /obj/structure/grille/play_attack_sound(damage_amount, damage_type = BRUTE, damage_flag = 0) diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm index f24d4caef73ad..282b2bf827d74 100644 --- a/code/game/objects/structures/morgue.dm +++ b/code/game/objects/structures/morgue.dm @@ -350,6 +350,11 @@ GLOBAL_LIST_EMPTY(crematoriums) else to_chat(user, "That's not connected to anything!") +/obj/structure/tray/attack_robot(mob/user) + if(!user.Adjacent(src)) + return + return attack_hand(user) + /obj/structure/tray/attackby(obj/P, mob/user, params) if(!istype(P, /obj/item/riding_offhand)) return ..() @@ -390,6 +395,10 @@ GLOBAL_LIST_EMPTY(crematoriums) desc = "Apply body before burning." icon_state = "cremat" +/obj/structure/tray/c_tray/attack_robot(mob/user) //copied behaviour from /obj/structure/bodycontainer/crematorium + to_chat(user, "[src] is locked against you.") + return + /* * Morgue tray */ @@ -397,7 +406,7 @@ GLOBAL_LIST_EMPTY(crematoriums) name = "morgue tray" desc = "Apply corpse before closing." icon_state = "morguet" - pass_flags_self = PASSTABLE + pass_flags_self = PASSTABLE|LETPASSTHROW /obj/structure/tray/m_tray/CanAllowThrough(atom/movable/mover, border_dir) . = ..() diff --git a/code/game/say.dm b/code/game/say.dm index d84297a372947..c2bf41f9c50ea 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -36,15 +36,18 @@ GLOBAL_LIST_INIT(freqtospan, list( //SHOULD_BE_PURE(TRUE) // TODO: Make calls to this actually pure. Its a lot of work, best done in its own PR. return TRUE -/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language = null, list/message_mods = list()) +/atom/movable/proc/send_speech(message, range = 7, obj/source = src, bubble_type, list/spans, datum/language/message_language, list/message_mods = list()) var/rendered = compose_message(src, message_language, message, , spans, message_mods) var/list/show_overhead_message_to = list() - for(var/atom/movable/AM as() in get_hearers_in_view(range, source, SEE_INVISIBLE_MAXIMUM)) - if(ismob(AM)) - var/mob/M = AM + for(var/atom/movable/hearing_movable as anything in get_hearers_in_view(range, source, SEE_INVISIBLE_MAXIMUM)) + if(!hearing_movable)//theoretically this should use as anything because it shouldnt be able to get nulls but there are reports that it does. + stack_trace("somehow theres a null returned from get_hearers_in_view() in send_speech!") + continue + if(ismob(hearing_movable)) + var/mob/M = hearing_movable if(M.should_show_chat_message(source, message_language, FALSE, is_heard = TRUE)) show_overhead_message_to += M - AM.Hear(rendered, src, message_language, message, , spans, message_mods) + hearing_movable.Hear(rendered, src, message_language, message, , spans, message_mods) if(length(show_overhead_message_to)) create_chat_message(src, message_language, show_overhead_message_to, message, spans, message_mods) diff --git a/code/modules/admin/smites/floorcluwne_stalker.dm b/code/modules/admin/smites/floorcluwne_stalker.dm index 1f4b69a4f7919..09a41fab47ec6 100644 --- a/code/modules/admin/smites/floorcluwne_stalker.dm +++ b/code/modules/admin/smites/floorcluwne_stalker.dm @@ -1,6 +1,6 @@ /// Spawns the evil floor cluwne to terrorize people /datum/smite/floorcluwne_stalker - name = "Floor Cluwne (Stalker)" + name = "Floor Cluwne (Stalker, Non-Lethal)" /datum/smite/floorcluwne_stalker/effect(client/user, mob/living/target) . = ..() @@ -8,3 +8,4 @@ var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(get_turf(target)) FC.force_target(H) FC.delete_after_target_killed = TRUE + FC.dontkill = TRUE diff --git a/code/modules/admin/smites/floorcluwne_trauma.dm b/code/modules/admin/smites/floorcluwne_trauma.dm new file mode 100644 index 0000000000000..51be259cf09ff --- /dev/null +++ b/code/modules/admin/smites/floorcluwne_trauma.dm @@ -0,0 +1,24 @@ +/// Spawns the evil floor cluwne to terrorize people +/datum/smite/floorcluwne_trauma + name = "Floor Cluwne (Traumatize, Non-Lethal)" + var/floorcluwne_trauma_level_generated + +/datum/smite/floorcluwne_trauma/effect(client/user, mob/living/target) + . = ..() + if(!floorcluwne_trauma_level_generated) + floorcluwne_trauma_level_generated = TRUE + message_admins("Generating z-level for Floorcluwne sacrifices...") + INVOKE_ASYNC(src, PROC_REF(generate_floorcluwne_z_level)) + + var/mob/living/carbon/human/H = target + var/mob/living/simple_animal/hostile/floor_cluwne/FC = new /mob/living/simple_animal/hostile/floor_cluwne(get_turf(target)) + FC.force_target(H) + FC.delete_after_target_killed = FALSE + FC.terrorize = TRUE + +/// Generate the z-level. +/datum/smite/floorcluwne_trauma/proc/generate_floorcluwne_z_level() + var/datum/map_template/heretic_sacrifice_level/new_level = new() //re-using heretic level + if(!new_level.load_new_z()) + message_admins("The floorcluwne_trauma z-level failed to load.") + CRASH("Failed to initialize floorcluwne_trauma z-level!") diff --git a/code/modules/antagonists/blob/structures/core.dm b/code/modules/antagonists/blob/structures/core.dm index 1840b272ed2c7..5ed9ce87c3833 100644 --- a/code/modules/antagonists/blob/structures/core.dm +++ b/code/modules/antagonists/blob/structures/core.dm @@ -4,6 +4,7 @@ icon_state = "blank_blob" desc = "A huge, pulsating yellow mass." max_integrity = 400 + max_hit_damage = 40 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 75, ACID = 90, STAMINA = 0, BLEED = 0) explosion_block = 6 point_return = -1 diff --git a/code/modules/antagonists/blob/structures/factory.dm b/code/modules/antagonists/blob/structures/factory.dm index 39532b48b750f..0bd47d7a1acd5 100644 --- a/code/modules/antagonists/blob/structures/factory.dm +++ b/code/modules/antagonists/blob/structures/factory.dm @@ -4,6 +4,7 @@ icon_state = "blob_factory" desc = "A thick spire of tendrils." max_integrity = 200 + max_hit_damage = 40 health_regen = 1 point_return = 25 resistance_flags = LAVA_PROOF diff --git a/code/modules/antagonists/blob/structures/node.dm b/code/modules/antagonists/blob/structures/node.dm index 7657d896696e4..89ba25e521558 100644 --- a/code/modules/antagonists/blob/structures/node.dm +++ b/code/modules/antagonists/blob/structures/node.dm @@ -4,6 +4,7 @@ icon_state = "blank_blob" desc = "A large, pulsating yellow mass." max_integrity = 200 + max_hit_damage = 40 armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 0, BOMB = 0, BIO = 0, RAD = 0, FIRE = 65, ACID = 90, STAMINA = 0, BLEED = 0) health_regen = 3 point_return = 25 diff --git a/code/modules/antagonists/clock_cult/clockwork_massive.dm b/code/modules/antagonists/clock_cult/clockwork_massive.dm index aa19c1480fbce..ee2fed63dd048 100644 --- a/code/modules/antagonists/clock_cult/clockwork_massive.dm +++ b/code/modules/antagonists/clock_cult/clockwork_massive.dm @@ -6,6 +6,7 @@ GLOBAL_LIST_INIT(clockwork_portals, list()) clockwork_desc = "Nezbere's magnum opus: a hulking clockwork machine capable of combining bluespace and steam power to summon Ratvar. Once activated, \ its instability will cause one-way bluespace rifts to open across the station to the City of Cogs, so be prepared to defend it at all costs." max_integrity = 1000 + max_hit_damage = 25 icon = 'icons/effects/96x96.dmi' icon_state = "clockwork_gateway_components" pixel_x = -32 diff --git a/code/modules/antagonists/clock_cult/mobs/eminence.dm b/code/modules/antagonists/clock_cult/mobs/eminence.dm index 751b249b7bea7..5dbc2d84ff6ce 100644 --- a/code/modules/antagonists/clock_cult/mobs/eminence.dm +++ b/code/modules/antagonists/clock_cult/mobs/eminence.dm @@ -332,4 +332,8 @@ canhear_range = 0 radio_silent = TRUE prison_radio = TRUE - broadcasting = TRUE + + +/obj/item/radio/borg/eminence/Initialize(mapload) + . = ..() + set_broadcasting(TRUE) diff --git a/code/modules/antagonists/space_dragon/carp_rift.dm b/code/modules/antagonists/space_dragon/carp_rift.dm index c16d71bd6d90f..643119e949ebc 100644 --- a/code/modules/antagonists/space_dragon/carp_rift.dm +++ b/code/modules/antagonists/space_dragon/carp_rift.dm @@ -62,6 +62,7 @@ desc = "A rift akin to the ones space carp use to travel long distances." armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 50, BIO = 100, RAD = 100, FIRE = 100, ACID = 100, STAMINA = 0, BLEED = 0) max_integrity = 300 + max_hit_damage = 50 icon = 'icons/obj/carp_rift.dmi' icon_state = "carp_rift_carpspawn" light_color = LIGHT_COLOR_PURPLE diff --git a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm index c9a15ce60686e..c55a951d8f374 100644 --- a/code/modules/antagonists/traitor/equipment/Malf_Modules.dm +++ b/code/modules/antagonists/traitor/equipment/Malf_Modules.dm @@ -891,7 +891,7 @@ GLOBAL_LIST_INIT(blacklisted_malf_machines, typecacheof(list( /datum/AI_Module/large/eavesdrop/upgrade(mob/living/silicon/ai/AI) if(AI.eyeobj) - AI.eyeobj.set_relay_speech(TRUE) + AI.eyeobj.relay_speech = TRUE //Fake Alert: Overloads a random number of lights across the station. One use. diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index 0760e9e5d0ba0..1fdd34360450f 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -1803,7 +1803,7 @@ /obj/item/reagent_containers/medspray/sterilizine, /obj/item/rollerbed) crate_name = "surgical supplies crate" - + /datum/supply_pack/medical/implants name = "Surplus Implants Crate" desc = "Do you want implants, but those R&D folks hasn't learnt how to do their job? Just get started with this crate containing several of our dusty surplus implants. (Surgical tools not included)" @@ -2803,6 +2803,13 @@ /mob/living/simple_animal/hostile/retaliate/poison/snake) crate_name = "snake crate" +/datum/supply_pack/critter/capybara + name = "Capybara Crate" + desc = "Coconut doggy" + cost = 10000 + contains = list(/mob/living/simple_animal/pet/dog/corgi/capybara) + crate_name = "capybara crate" + ////////////////////////////////////////////////////////////////////////////// //////////////////////////// Costumes & Toys ///////////////////////////////// ////////////////////////////////////////////////////////////////////////////// diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm index 0972273f30368..c9b85025d240e 100644 --- a/code/modules/client/client_procs.dm +++ b/code/modules/client/client_procs.dm @@ -555,6 +555,14 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( ////////////// /client/Del() + if(!gc_destroyed) + Destroy() //Clean up signals and timers. + return ..() + +/client/Destroy() + GLOB.clients -= src + GLOB.directory -= ckey + GLOB.mentors -= src log_access("Logout: [key_name(src)]") GLOB.ahelp_tickets.ClientLogout(src) GLOB.mhelp_tickets.ClientLogout(src) @@ -586,14 +594,9 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( var/atom/eye_thing = eye LAZYREMOVE(eye_thing.eye_users, src) GLOB.requests.client_logout(src) - GLOB.directory -= ckey - GLOB.clients -= src - GLOB.mentors -= src + SSambience.remove_ambience_client(src) Master.UpdateTickRate() - return ..() - -/client/Destroy() ..() //Even though we're going to be hard deleted there are still some things that want to know the destroy is happening return QDEL_HINT_HARDDEL_NOW @@ -985,7 +988,7 @@ GLOBAL_LIST_INIT(blacklisted_builds, list( if(isatom(new_eye)) LAZYADD(new_eye.eye_users, src) - // SEND_SIGNAL(src, COMSIG_CLIENT_SET_EYE, old_eye, new_eye) // use this when you want a thing from TG + // SEND_SIGNAL(src, COMSIG_CLIENT_SET_EYE, old_eye, new_eye) // use this when you want a thing from TG //This is from planecube pr, dragon, we most certainly dont want from that pr /client/proc/add_verbs_from_config() diff --git a/code/modules/elevator/elevator_controller.dm b/code/modules/elevator/elevator_controller.dm index 42eb3da2c76d9..856a60eddcf0f 100644 --- a/code/modules/elevator/elevator_controller.dm +++ b/code/modules/elevator/elevator_controller.dm @@ -1,7 +1,6 @@ SUBSYSTEM_DEF(elevator_controller) name = "Elevator Controller" - flags = SS_NO_FIRE - init_order = INIT_ORDER_ELEVATOR + flags = SS_NO_FIRE | SS_NO_INIT ///List of elevator groups var/list/elevator_groups = list() ///List of elevator group positional stuff @@ -26,7 +25,7 @@ SUBSYSTEM_DEF(elevator_controller) if(!elevator_groups[id]) elevator_groups[id] = list() elevator_groups[id] |= EV - + /datum/controller/subsystem/elevator_controller/proc/move_elevator(id, destination_z, calltime, force) . = TRUE elevator_group_timers[id] = addtimer(CALLBACK(src, PROC_REF(finish_timer), id), calltime || 2 SECONDS, TIMER_STOPPABLE) @@ -46,7 +45,7 @@ SUBSYSTEM_DEF(elevator_controller) var/turf/T = locate(ES.x, ES.y, i) T.ChangeTurf(/turf/open/openspace) crashing = TRUE - + if(S.get_virtual_z_level() != destination_z) playsound(S, 'sound/effects/turbolift/turbolift.ogg', 45) SEND_SIGNAL(src, COMSIG_ELEVATOR_MOVE, id, destination_z, calltime, crashing) diff --git a/code/modules/holoparasite/abilities/lesser/radio.dm b/code/modules/holoparasite/abilities/lesser/radio.dm index b96dbe03680ed..f078d0c97cecc 100644 --- a/code/modules/holoparasite/abilities/lesser/radio.dm +++ b/code/modules/holoparasite/abilities/lesser/radio.dm @@ -34,7 +34,7 @@ binary = TRUE radio.keyslot.translate_binary = TRUE if(!can_talk) - radio.wires.cut(WIRE_TX) + radio.wires.cut(WIRE_TX, null) radio.recalculateChannels() generate_regex() diff --git a/code/modules/jobs/job_types/security_officer.dm b/code/modules/jobs/job_types/security_officer.dm index 05b9f5aef5aa2..0d107f05ae756 100644 --- a/code/modules/jobs/job_types/security_officer.dm +++ b/code/modules/jobs/job_types/security_officer.dm @@ -173,7 +173,7 @@ GLOBAL_LIST_INIT(available_depts, list(SEC_DEPT_ENGINEERING, SEC_DEPT_MEDICAL, S /obj/item/radio/headset/headset_sec/alt/department/Initialize(mapload) . = ..() wires = new/datum/wires/radio(src) - secure_radio_connections = new + secure_radio_connections = list() recalculateChannels() /obj/item/radio/headset/headset_sec/alt/department/engi diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index fac6a30c9361e..b5c3d7ae0534f 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -331,6 +331,11 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava) var/pipe_color = "" var/hide = FALSE + FASTDMM_PROP(\ + pipe_type = PIPE_TYPE_AUTO,\ + pipe_interference_group = "atmos-[piping_layer]"\ + ) + var/list/pipe_types = list( /obj/machinery/atmospherics/pipe/simple/general/visible, /obj/machinery/atmospherics/pipe/simple/general/visible, diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 31d2e0c0b0f99..d2a88419b2c4f 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -313,6 +313,7 @@ if(expanded_x || expanded_y || expanded_z) world.refresh_atmos_grid() + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_EXPANDED_WORLD_BOUNDS, expanded_x, expanded_y) #ifdef TESTING if(turfsSkipped) diff --git a/code/modules/mapping/space_management/zlevel_manager.dm b/code/modules/mapping/space_management/zlevel_manager.dm index c5f6ecdba883b..d43aedc2a225d 100644 --- a/code/modules/mapping/space_management/zlevel_manager.dm +++ b/code/modules/mapping/space_management/zlevel_manager.dm @@ -19,7 +19,6 @@ generate_z_level_linkages() // Default Zs don't use add_new_zlevel() so they don't automatically generate z-linkages. /datum/controller/subsystem/mapping/proc/add_new_zlevel(name, traits = list(), z_type = /datum/space_level, orbital_body_type, contain_turfs = TRUE) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_Z, args) var/new_z = z_list.len + 1 if (world.maxz < new_z) world.incrementMaxZ() @@ -28,6 +27,7 @@ var/datum/space_level/S = new z_type(new_z, name, traits, orbital_body_type) manage_z_level(S, filled_with_space = TRUE, contain_turfs = contain_turfs) generate_linkages_for_z_level(new_z) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_NEW_Z, S) return S /datum/controller/subsystem/mapping/proc/get_level(z) diff --git a/code/modules/mining/laborcamp/laborstacker.dm b/code/modules/mining/laborcamp/laborstacker.dm index 6582b176f9d3f..9197e2c73deef 100644 --- a/code/modules/mining/laborcamp/laborstacker.dm +++ b/code/modules/mining/laborcamp/laborstacker.dm @@ -17,7 +17,7 @@ GLOBAL_LIST(labor_sheet_values) /obj/machinery/mineral/labor_claim_console/Initialize(mapload) . = ..() integrated_radio = new /obj/item/radio(src) - integrated_radio.listening = FALSE + integrated_radio.set_listening(FALSE) locate_stacking_machine() //If we can't find a stacking machine end it all ok? if(!stacking_machine) diff --git a/code/modules/mob/dead/new_player/new_player.dm b/code/modules/mob/dead/new_player/new_player.dm index fcb7218c8905c..4b89f530f17bc 100644 --- a/code/modules/mob/dead/new_player/new_player.dm +++ b/code/modules/mob/dead/new_player/new_player.dm @@ -1,16 +1,13 @@ #define LINKIFY_READY(string, value) "[string]" /mob/dead/new_player - var/ready = 0 - var/spawning = 0//Referenced when you want to delete the new_player later on in the code. - flags_1 = NONE - invisibility = INVISIBILITY_ABSTRACT - density = FALSE stat = DEAD + var/ready = 0 + var/spawning = 0//Referenced when you want to delete the new_player later on in the code. var/mob/living/new_character //for instant transfer once the round is set up ///Used to make sure someone doesn't get spammed with messages if they're ineligible for roles. var/ineligible_for_roles = FALSE @@ -555,3 +552,5 @@ + "\nThis is only required once and only for the duration that the panic bunker is active." \ + "\nIf the interview interface is not open, use the Open Interview verb in the top right.") +/mob/dead/new_player/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null) + return diff --git a/code/modules/mob/living/brain/MMI.dm b/code/modules/mob/living/brain/MMI.dm index 1cd2ac78d6863..143c013c4aefa 100644 --- a/code/modules/mob/living/brain/MMI.dm +++ b/code/modules/mob/living/brain/MMI.dm @@ -17,7 +17,7 @@ /obj/item/mmi/Initialize(mapload) . = ..() radio = new(src) //Spawns a radio inside the MMI. - radio.broadcasting = FALSE //researching radio mmis turned the robofabs into radios because this didnt start as 0. + radio.set_broadcasting(FALSE) //researching radio mmis turned the robofabs into radios because this didnt start as 0. laws.set_laws_config() /obj/item/mmi/Destroy() @@ -101,8 +101,8 @@ /obj/item/mmi/attack_self(mob/user) if(!brain) - radio.on = !radio.on - to_chat(user, "You toggle [src]'s radio system [radio.on==1 ? "on" : "off"].") + radio.set_on(!radio.is_on()) + to_chat(user, "You toggle [src]'s radio system [radio.is_on() == TRUE ? "on" : "off"].") else log_attack("[key_name(user)] ejected \the [brainmob] from \the [src] at [AREACOORD(src)].") eject_brain(user) @@ -197,12 +197,12 @@ if(brainmob.stat) to_chat(brainmob, "Can't do that while incapacitated or dead!") - if(!radio.on) + if(!radio.is_on()) to_chat(brainmob, "Your radio is disabled!") return - radio.listening = !radio.listening - to_chat(brainmob, "Radio is [radio.listening ? "now" : "no longer"] receiving broadcast.") + radio.set_listening(!radio.get_listening()) + to_chat(brainmob, "Radio is [radio.get_listening() ? "now" : "no longer"] receiving broadcast.") /obj/item/mmi/emp_act(severity) . = ..() @@ -227,7 +227,7 @@ /obj/item/mmi/examine(mob/user) . = ..() - . += "There is a switch to toggle the radio system [radio.on ? "off" : "on"].[brain ? " It is currently being covered by [brain]." : null]" + . += "There is a switch to toggle the radio system [radio.is_on() ? "off" : "on"].[brain ? " It is currently being covered by [brain]." : null]" if(brainmob) var/mob/living/brain/B = brainmob if(!B.key || !B.mind || B.stat == DEAD) @@ -278,4 +278,4 @@ /obj/item/mmi/syndie/Initialize(mapload) . = ..() laws = new /datum/ai_laws/syndicate_override() - radio.on = FALSE + radio.set_on(FALSE) diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm index 2e521d1b91055..6c2324f0f8bf5 100644 --- a/code/modules/mob/living/carbon/carbon.dm +++ b/code/modules/mob/living/carbon/carbon.dm @@ -509,9 +509,10 @@ /mob/living/carbon/update_stamina(extend_stam_crit = FALSE) var/stam = getStaminaLoss() - if(stam >= DAMAGE_PRECISION && (maxHealth - stam) <= crit_threshold && !stat && !HAS_TRAIT(src, TRAIT_NOSTAMCRIT)) + if(stam >= DAMAGE_PRECISION && (maxHealth - stam) <= crit_threshold && !HAS_TRAIT(src, TRAIT_NOSTAMCRIT)) if(!stat) - enter_stamcrit() + if(extend_stam_crit && !HAS_TRAIT_FROM(src, TRAIT_INCAPACITATED, STAMINA)) + enter_stamcrit() else if(HAS_TRAIT_FROM(src, TRAIT_INCAPACITATED, STAMINA)) REMOVE_TRAIT(src, TRAIT_INCAPACITATED, STAMINA) REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, STAMINA) diff --git a/code/modules/mob/living/carbon/human/species_types/dullahan.dm b/code/modules/mob/living/carbon/human/species_types/dullahan.dm index 9539e0a6cb596..5fb33bdc9412d 100644 --- a/code/modules/mob/living/carbon/human/species_types/dullahan.dm +++ b/code/modules/mob/living/carbon/human/species_types/dullahan.dm @@ -25,7 +25,7 @@ /datum/species/dullahan/on_species_gain(mob/living/carbon/human/H, datum/species/old_species) . = ..() - REMOVE_TRAIT(src, TRAIT_HEARING_SENSITIVE, TRAIT_GENERIC) + H.lose_hearing_sensitivity(TRAIT_GENERIC) var/obj/item/bodypart/head/head = H.get_bodypart(BODY_ZONE_HEAD) if(head) head.drop_limb() @@ -160,6 +160,9 @@ START_PROCESSING(SSobj, src) become_hearing_sensitive(ROUNDSTART_TRAIT) +/obj/item/dullahan_relay/Hear(message, atom/movable/speaker, message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) + owner.Hear(arglist(args)) + /obj/item/dullahan_relay/process() if(!istype(loc, /obj/item/bodypart/head) || QDELETED(owner)) . = PROCESS_KILL diff --git a/code/modules/mob/living/say.dm b/code/modules/mob/living/say.dm index 87de7f252b1de..fe44f472f868a 100644 --- a/code/modules/mob/living/say.dm +++ b/code/modules/mob/living/say.dm @@ -189,7 +189,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( // radios don't pick up whispers very well radio_message = stars(radio_message) spans |= SPAN_ITALICS - var/radio_return = radio(radio_message, message_mods, spans, language) + var/radio_return = radio(radio_message, message_mods, spans, language)//roughly 27% of living/say()'s total cost if(radio_return & ITALICS) spans |= SPAN_ITALICS if(radio_return & REDUCE_RANGE) @@ -213,7 +213,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(pressure < ONE_ATMOSPHERE*0.4) //Thin air, let's italicise the message spans |= SPAN_ITALICS - send_speech(message, message_range, src, bubble_type, spans, language, message_mods) + send_speech(message, message_range, src, bubble_type, spans, language, message_mods)//roughly 58% of living/say()'s total cost if(succumbed) succumb(TRUE) @@ -263,7 +263,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( if(!M.client || !client) //client is so that ghosts don't have to listen to mice listening -= M // remove (added by SEE_INVISIBLE_MAXIMUM) continue - if(get_dist(M, src) > 7 || M.get_virtual_z_level() != get_virtual_z_level()) //they're out of range of normal hearing + if(M.get_virtual_z_level() != get_virtual_z_level() || get_dist(M, src) > 7 ) //they're out of range of normal hearing if(M.client?.prefs && eavesdrop_range && !M.client.prefs.read_player_preference(/datum/preference/toggle/chat_ghostwhisper)) //they're whispering and we have hearing whispers at any range off listening -= M // remove (added by SEE_INVISIBLE_MAXIMUM) continue @@ -282,7 +282,10 @@ GLOBAL_LIST_INIT(department_radio_keys, list( var/list/show_overhead_message_to = list() var/list/show_overhead_message_to_eavesdrop = list() var/rendered = compose_message(src, message_language, message, , spans, message_mods) - for(var/atom/movable/AM as() in listening) + for(var/atom/movable/AM as anything in listening) + if(!AM) + stack_trace("somehow theres a null returned from get_hearers_in_view() in send_speech!") + continue if(eavesdrop_range && get_dist(source, AM) > message_range && !(the_dead[AM])) if(ismob(AM)) var/mob/M = AM @@ -382,7 +385,7 @@ GLOBAL_LIST_INIT(department_radio_keys, list( /mob/living/proc/radio(message, list/message_mods = list(), list/spans, language) var/obj/item/implant/radio/imp = locate() in src - if(imp && imp.radio.on) + if(imp?.radio.is_on()) if(message_mods[MODE_HEADSET]) imp.radio.talk_into(src, message, , spans, language, message_mods) return ITALICS | REDUCE_RANGE diff --git a/code/modules/mob/living/silicon/ai/freelook/eye.dm b/code/modules/mob/living/silicon/ai/freelook/eye.dm index f19df8bec98f7..68fedd1598a24 100644 --- a/code/modules/mob/living/silicon/ai/freelook/eye.dm +++ b/code/modules/mob/living/silicon/ai/freelook/eye.dm @@ -11,6 +11,7 @@ hud_possible = list(ANTAG_HUD, AI_DETECT_HUD = HUD_LIST_LIST) var/list/visibleCameraChunks = list() var/mob/living/silicon/ai/ai = null + var/relay_speech = FALSE var/use_static = TRUE var/static_visibility_range = 16 var/ai_detector_visible = TRUE @@ -22,12 +23,6 @@ update_ai_detect_hud() setLoc(loc, TRUE) -/mob/camera/ai_eye/proc/set_relay_speech(relay) - if(relay) - become_hearing_sensitive() - else - REMOVE_TRAIT(src, TRAIT_HEARING_SENSITIVE, TRAIT_GENERIC) - /mob/camera/ai_eye/proc/update_ai_detect_hud() var/datum/atom_hud/ai_detector/hud = GLOB.huds[DATA_HUD_AI_DETECT] var/list/old_images = hud_list[AI_DETECT_HUD] @@ -218,7 +213,7 @@ /mob/camera/ai_eye/Hear(message, atom/movable/speaker, datum/language/message_language, raw_message, radio_freq, list/spans, list/message_mods = list()) . = ..() - if(speaker && ai && !radio_freq && speaker != ai && near_camera(speaker)) + if(relay_speech && speaker && ai && !radio_freq && speaker != ai && near_camera(speaker)) ai.relay_speech(message, speaker, message_language, raw_message, radio_freq, spans, message_mods) /obj/effect/overlay/ai_detect_hud diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 2936cf2ca3ee4..c87e661c05e05 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -391,7 +391,7 @@ return if(Autochan == "Default") //Autospeak on whatever frequency to which the radio is set, usually Common. radiomod = ";" - Autochan += " ([radio.frequency])" + Autochan += " ([radio.get_frequency()])" else if(Autochan == "None") //Prevents use of the radio for automatic annoucements. radiomod = "" else //For department channels, if any, given by the internal radio. diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 55c9fff6eb1e9..5f6949d226a05 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -216,9 +216,9 @@ qdel(src) if(2) for(var/i = 1; i < 3; i++) - wires.cut_random() + wires.cut_random(null) if(3) - wires.cut_random() + wires.cut_random(null) /mob/living/simple_animal/bot/mulebot/bullet_act(obj/projectile/Proj) @@ -228,7 +228,7 @@ unload(0) if(prob(25)) visible_message("Something shorts out inside [src]!") - wires.cut_random() + wires.cut_random(null) /mob/living/simple_animal/bot/mulebot/interact(mob/user) if(open && !isAI(user)) diff --git a/code/modules/mob/living/simple_animal/friendly/dog.dm b/code/modules/mob/living/simple_animal/friendly/dog.dm index 5536376f15248..5e575caa5da00 100644 --- a/code/modules/mob/living/simple_animal/friendly/dog.dm +++ b/code/modules/mob/living/simple_animal/friendly/dog.dm @@ -749,3 +749,37 @@ GLOBAL_LIST_INIT(strippable_corgi_items, create_strippable_list(list( mob_size = MOB_SIZE_SMALL collar_type = "puppy" worn_slot_flags = ITEM_SLOT_HEAD + +/mob/living/simple_animal/pet/dog/corgi/capybara + name = "\improper capybara" + real_name = "capybara" + desc = "It's a capybara." + icon_state = "capybara" + icon_living = "capybara" + icon_dead = "capybara_dead" + held_state = null + can_be_held = FALSE + butcher_results = list() + childtype = list() + + animal_species = /mob/living/simple_animal/pet/dog + +/mob/living/simple_animal/pet/dog/corgi/capybara/update_corgi_fluff() + // First, change back to defaults + name = real_name + desc = initial(desc) + // BYOND/DM doesn't support the use of initial on lists. + speak = list("Bark!", "Squee!", "Squee.") + speak_emote = list("barks", "squeaks") + emote_hear = list("barks!", "squees!", "squeaks!", "yaps.", "squeaks.") + emote_see = list("shakes its head.", "medidates on peace.", "looks to be in peace.", "shivers.") + desc = initial(desc) + set_light(0) + + if(inventory_head && inventory_head.dog_fashion) + var/datum/dog_fashion/DF = new inventory_head.dog_fashion(src) + DF.apply(src) + + if(inventory_back && inventory_back.dog_fashion) + var/datum/dog_fashion/DF = new inventory_back.dog_fashion(src) + DF.apply(src) diff --git a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm index 6bebc3e09797c..166a0c327b95f 100644 --- a/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm +++ b/code/modules/mob/living/simple_animal/hostile/floor_cluwne.dm @@ -41,6 +41,9 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0) var/invalid_area_typecache = list(/area/space, /area/lavaland, /area/centcom, /area/shuttle/syndicate) var/eating = FALSE var/dontkill = FALSE //for if we just wanna curse a fucker + var/terrorize = FALSE //for Heretic curse, rather than kill + var/terror_count = 0 + var/return_timers var/obj/effect/dummy/floorcluwne_orbit/poi var/obj/effect/temp_visual/fcluwne_manifest/cluwnehole move_resist = INFINITY @@ -183,9 +186,9 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0) interest = 0 stage = STAGE_HAUNT return target = current_victim - - message_admins("Floor Cluwne was deleted due to a lack of valid targets, if this was a manually targeted instance please re-evaluate your choice.") - qdel(src) + if(!terrorize) + message_admins("Floor Cluwne was deleted due to a lack of valid targets, if this was a manually targeted instance please re-evaluate your choice.") + qdel(src) /mob/living/simple_animal/hostile/floor_cluwne/proc/Manifest()//handles disappearing and appearance anim @@ -388,10 +391,13 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0) for(var/turf/open/T in RANGE_TURFS(4, H)) H.add_splatter_floor(T) if(do_after(src, 50, target = H)) - H.unequip_everything()//more runtime prevention - if(prob(75)) + if(terrorize) + begin_trauma(H) + else if(prob(75)) + H.unequip_everything() //runtime prevention H.gib(FALSE) else + H.unequip_everything() //runtime prevention H.cluwneify() H.adjustBruteLoss(30) H.adjustOrganLoss(ORGAN_SLOT_BRAIN, 100) @@ -443,6 +449,185 @@ GLOBAL_VAR_INIT(floor_cluwnes, 0) name += " ([GLOB.floor_cluwnes])" AddElement(/datum/element/point_of_interest) +/mob/living/simple_animal/hostile/floor_cluwne/proc/begin_trauma(mob/living/carbon/human/sac_target) + if(!LAZYLEN(GLOB.heretic_sacrifice_landmarks)) + CRASH("[type] - begin_trauma was called, but no floorcluwne_trauma landmarks were found!") + + var/obj/effect/landmark/heretic/destination_landmark = GLOB.heretic_sacrifice_landmarks[HERETIC_PATH_ASH] + if(!destination_landmark) + CRASH("[type] - begin_trauma could not find a destination landmark to send the target!") + + var/turf/destination = get_turf(destination_landmark) + + sac_target.handcuffed = new /obj/item/restraints/handcuffs/energy/cult(sac_target) + sac_target.update_handcuffed() + sac_target.do_jitter_animation(100) + + if(sac_target.legcuffed) + sac_target.legcuffed.forceMove(sac_target.drop_location()) + sac_target.legcuffed.dropped(sac_target) + sac_target.legcuffed = null + sac_target.update_inv_legcuffed() + + addtimer(CALLBACK(sac_target, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 100), SACRIFICE_SLEEP_DURATION * (1/3)) + addtimer(CALLBACK(sac_target, TYPE_PROC_REF(/mob/living/carbon, do_jitter_animation), 100), SACRIFICE_SLEEP_DURATION * (2/3)) + + // Grab their ghost, just in case they're dead or something. + sac_target.grab_ghost() + // If our target is dead, try to revive them + // and if we fail to revive them, don't proceede the chain + if(!sac_target.heal_and_revive(50, "[sac_target]'s heart begins to beat with an unholy force as they return from death!")) + return + + if(sac_target.AdjustUnconscious(SACRIFICE_SLEEP_DURATION)) + to_chat(sac_target, "Your mind feels torn apart as you fall into a shallow slumber...") + else + to_chat(sac_target, "Your mind begins to tear apart as you watch dark tendrils envelop you.") + + sac_target.AdjustParalyzed(SACRIFICE_SLEEP_DURATION * 1.2) + sac_target.AdjustImmobilized(SACRIFICE_SLEEP_DURATION * 1.2) + + addtimer(CALLBACK(src, PROC_REF(after_target_sleeps), sac_target, destination), SACRIFICE_SLEEP_DURATION * 0.5) // Teleport to the minigame + + return TRUE + +/mob/living/simple_animal/hostile/floor_cluwne/proc/after_target_sleeps(mob/living/carbon/human/sac_target, turf/destination) + if(QDELETED(sac_target)) + return + + // Grab ghost again, just to be safe. + sac_target.grab_ghost() + // The target disconnected or something, we shouldn't bother sending them along. + if(!sac_target.client || !sac_target.mind) + return + + // Send 'em to the destination. If the teleport fails, do nothing. + if(!destination || !do_teleport(sac_target, destination, asoundin = 'sound/magic/repulse.ogg', asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_MAGIC, forced = TRUE, no_wake = TRUE)) + return + + // If our target died during the (short) wait timer, + // and we fail to revive them (using a lower number than before), do nothing. + if(!sac_target.heal_and_revive(75, "[sac_target]'s heart begins to beat with an unholy force as they return from death!")) + return + + sac_target.cure_blind(null) + sac_target.invisibility = initial(sac_target.invisibility) + sac_target.density = initial(sac_target.density) + sac_target.set_anchored(initial(sac_target.anchored)) + to_chat(sac_target, "Unnatural forces begin to claw at your very being from beyond the veil.") + + sac_target.apply_status_effect(/datum/status_effect/unholy_determination, SACRIFICE_REALM_DURATION) + addtimer(CALLBACK(src, PROC_REF(after_target_wakes), sac_target), SACRIFICE_SLEEP_DURATION * 0.5) // Begin the minigame + +/mob/living/simple_animal/hostile/floor_cluwne/proc/after_target_wakes(mob/living/carbon/human/sac_target) + if(QDELETED(sac_target)) + return + + // About how long should the helgrasp last? (1 metab a tick = helgrasp_time / 2 ticks (so, 1 minute = 60 seconds = 30 ticks)) + var/helgrasp_time = 1 MINUTES + + sac_target.reagents?.add_reagent(/datum/reagent/helgrasp/heretic, helgrasp_time / 20) + sac_target.apply_necropolis_curse(CURSE_BLINDING | CURSE_GRASPING) + + SEND_SIGNAL(sac_target, COMSIG_ADD_MOOD_EVENT, "shadow_realm", /datum/mood_event/shadow_realm) + + sac_target.flash_act() + sac_target.blur_eyes(15) + sac_target.Jitter(10) + sac_target.Dizzy(10) + sac_target.hallucination += 12 + sac_target.emote("scream") + + to_chat(sac_target, "The grasping hands reveal themselves to you!") + to_chat(sac_target, "You feel invigorated! Fight to survive!") + // When it runs out, let them know they're almost home free + addtimer(CALLBACK(src, PROC_REF(after_helgrasp_ends), sac_target), helgrasp_time) + // Win condition + var/win_timer = addtimer(CALLBACK(src, PROC_REF(return_target), sac_target), SACRIFICE_REALM_DURATION, TIMER_STOPPABLE) + LAZYSET(return_timers, REF(sac_target), win_timer) + +/** + * This proc is called from [proc/after_target_wakes] after the helgrasp runs out in the [sac_target]. + * + * It gives them a message letting them know it's getting easier and they're almost free. + */ +/mob/living/simple_animal/hostile/floor_cluwne/proc/after_helgrasp_ends(mob/living/carbon/human/sac_target) + if(QDELETED(sac_target) || sac_target.stat == DEAD) + return + + to_chat(sac_target, "The worst is behind you... Not much longer! Hold fast, or expire!") + +/mob/living/simple_animal/hostile/floor_cluwne/proc/return_target(mob/living/carbon/human/sac_target) + if(QDELETED(sac_target)) + return + + var/current_timer = LAZYACCESS(return_timers, REF(sac_target)) + if(current_timer) + deltimer(current_timer) + LAZYREMOVE(return_timers, REF(sac_target)) + + UnregisterSignal(sac_target, COMSIG_MOVABLE_Z_CHANGED) + UnregisterSignal(sac_target, COMSIG_MOB_DEATH) + sac_target.remove_status_effect(/datum/status_effect/necropolis_curse) + sac_target.remove_status_effect(/datum/status_effect/unholy_determination) + sac_target.reagents?.del_reagent(/datum/reagent/helgrasp/heretic) + SEND_SIGNAL(sac_target, COMSIG_CLEAR_MOOD_EVENT, "shadow_realm") + + // Wherever we end up, we sure as hell won't be able to explain + sac_target.slurring += 20 + sac_target.cultslurring += 20 + sac_target.stuttering += 20 + + // They're already back on the station for some reason, don't bother teleporting + if(is_station_level(sac_target.z)) + return + + // Teleport them to a random safe coordinate on the station z level. + var/turf/open/floor/safe_turf = find_safe_turf(extended_safety_checks = TRUE) + var/obj/effect/landmark/observer_start/backup_loc = locate(/obj/effect/landmark/observer_start) in GLOB.landmarks_list + if(!safe_turf) + safe_turf = get_turf(backup_loc) + stack_trace("[type] - return_target was unable to find a safe turf for [sac_target] to return to. Defaulting to observer start turf.") + + if(!do_teleport(sac_target, safe_turf, asoundout = 'sound/magic/blind.ogg', no_effects = TRUE, channel = TELEPORT_CHANNEL_FREE, forced = TRUE, no_wake = TRUE)) + safe_turf = get_turf(backup_loc) + sac_target.forceMove(safe_turf) + stack_trace("[type] - return_target was unable to teleport [sac_target] to the observer start turf. Forcemoving.") + + after_return_live_target(sac_target) + + +/** + * This proc is called from [proc/return_target] if the [sac_target] survives the shadow realm. + * + * Gives the sacrifice target some after effects upon ariving back to reality. + */ +/mob/living/simple_animal/hostile/floor_cluwne/proc/after_return_live_target(mob/living/carbon/human/sac_target) + if(sac_target.stat == DEAD) + sac_target.revive(TRUE, TRUE) + sac_target.grab_ghost() + to_chat(sac_target, "The fight is over, but at great cost. You have been returned to the station in one piece.") + to_chat(sac_target, "You don't remember anything leading up to the experience - All you can think about are those horrific hands...") + + // Oh god where are we? + sac_target.flash_act() + sac_target.Jitter(60) + sac_target.blur_eyes(50) + sac_target.Dizzy(30) + sac_target.AdjustKnockdown(80) + sac_target.adjustStaminaLoss(120) + + // Glad i'm outta there, though! + SEND_SIGNAL(sac_target, COMSIG_ADD_MOOD_EVENT, "shadow_realm_survived", /datum/mood_event/shadow_realm_live) + SEND_SIGNAL(sac_target, COMSIG_ADD_MOOD_EVENT, "shadow_realm_survived_sadness", /datum/mood_event/shadow_realm_live_sad) + + // Could use a little pick-me-up... + sac_target.reagents?.add_reagent(/datum/reagent/eldritchkiss, 12) //this used to kill toxinlovers, hence the snowflake reagent + terror_count += 1 + if(terror_count == 2) + message_admins("Floor Cluwne was deleted due to reaching its max terror count") + qdel(src) + #undef STAGE_HAUNT #undef STAGE_SPOOK #undef STAGE_TORMENT diff --git a/code/modules/mob/login.dm b/code/modules/mob/login.dm index b1438706f2dae..e1a0aa58098e2 100644 --- a/code/modules/mob/login.dm +++ b/code/modules/mob/login.dm @@ -10,6 +10,8 @@ * * tells the world to update it's status (for player count) * * create mob huds for the mob if needed * * reset next_move to 1 + * * Set statobj to our mob + * * NOT the parent call. The only unique thing it does is a very obtuse move op, see the comment lower down * * parent call * * if the client exists set the perspective to the mob loc * * call on_log on the loc (sigh) @@ -51,11 +53,27 @@ next_move = 1 - ..() + client.statobj = src + + // DO NOT CALL PARENT HERE + // BYOND's internal implementation of login does two things + // 1: Set statobj to the mob being logged into (We got this covered) + // 2: And I quote "If the mob has no location, place it near (1,1,1) if possible" + // See, near is doing an agressive amount of legwork there + // What it actually does is takes the area that (1,1,1) is in, and loops through all those turfs + // If you successfully move into one, it stops + // Because we want Move() to mean standard movements rather then just what byond treats it as (ALL moves) + // We don't allow moves from nullspace -> somewhere. This means the loop has to iterate all the turfs in (1,1,1)'s area + // For us, (1,1,1) is a space tile. This means roughly 200,000! calls to Move() + // You do not want this if(!client) return FALSE + //We do this here to prevent hanging refs from ghostize or whatever, since if we were in another mob before this'll take care of it + clear_important_client_contents(client) + enable_client_mobs_in_contents(client) + SEND_SIGNAL(src, COMSIG_MOB_LOGIN) if (key != client.key) diff --git a/code/modules/mob/logout.dm b/code/modules/mob/logout.dm index f6ce3190fa126..290e2fa7ded2f 100644 --- a/code/modules/mob/logout.dm +++ b/code/modules/mob/logout.dm @@ -17,4 +17,6 @@ for (var/datum/component/comp in GetComponents(/datum/component/moved_relay)) qdel(comp) + clear_important_client_contents(client) + return TRUE diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index 09ced6b2d584a..db43fd25105f0 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -36,8 +36,7 @@ for (var/alert in alerts) clear_alert(alert, TRUE) if(observers?.len) - for(var/M in observers) - var/mob/dead/observe = M + for(var/mob/dead/observe as anything in observers) observe.reset_perspective(null) qdel(hud_used) for(var/cc in client_colours) @@ -445,18 +444,24 @@ */ /mob/proc/reset_perspective(atom/new_eye) SHOULD_CALL_PARENT(TRUE) + /* + *In the future, this signal may need to be moved to the end of the proc, after the eye has been given a chance to fully updated. + *No issues atm, but if one occurs, try that solution first + */ + SEND_SIGNAL(src, COMSIG_MOB_RESET_PERSPECTIVE) if(!client) return if(new_eye) if(ismovable(new_eye)) - //Set the the thing unless it's us + //Set the new eye unless it's us if(new_eye != src) client.perspective = EYE_PERSPECTIVE client.set_eye(new_eye) else client.set_eye(client.mob) client.perspective = MOB_PERSPECTIVE + else if(isturf(new_eye)) //Set to the turf unless it's our current turf if(new_eye != loc) @@ -466,7 +471,7 @@ client.set_eye(client.mob) client.perspective = MOB_PERSPECTIVE else - //Do nothing + return TRUE //no setting eye to stupid things like areas or whatever else //Reset to common defaults: mob if on turf, otherwise current loc if(isturf(loc)) diff --git a/code/modules/paperwork/fax.dm b/code/modules/paperwork/fax.dm index a584b1e503590..a5872a9add45b 100644 --- a/code/modules/paperwork/fax.dm +++ b/code/modules/paperwork/fax.dm @@ -74,7 +74,7 @@ radio.subspace_transmission = TRUE radio.canhear_range = 0 // Override in subtypes - radio.on = FALSE + radio.set_on(FALSE) // Mapping Error checking if(!mapload) @@ -511,7 +511,7 @@ /obj/machinery/fax/centcom/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_cent radio.recalculateChannels() @@ -522,7 +522,7 @@ /obj/machinery/fax/bridge/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_com radio.recalculateChannels() @@ -533,7 +533,7 @@ /obj/machinery/fax/cargo/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_cargo radio.recalculateChannels() @@ -544,7 +544,7 @@ /obj/machinery/fax/eng/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_eng radio.recalculateChannels() @@ -555,7 +555,7 @@ /obj/machinery/fax/law/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_srvsec radio.recalculateChannels() @@ -566,7 +566,7 @@ /obj/machinery/fax/med/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_med radio.recalculateChannels() @@ -577,7 +577,7 @@ /obj/machinery/fax/sci/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_sci radio.recalculateChannels() @@ -588,7 +588,7 @@ /obj/machinery/fax/sec/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_sec radio.recalculateChannels() @@ -599,6 +599,6 @@ /obj/machinery/fax/service/Initialize(mapload) . = ..() - radio.on = TRUE + radio.set_on(TRUE) radio.keyslot = new /obj/item/encryptionkey/headset_service radio.recalculateChannels() diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm index 0a3799447ca66..687f9da811192 100644 --- a/code/modules/power/power.dm +++ b/code/modules/power/power.dm @@ -131,8 +131,8 @@ update_appearance() // connect the machine to a powernet if a node cable is present on the turf -/obj/machinery/power/proc/connect_to_network() - var/turf/T = src.loc +/obj/machinery/power/proc/connect_to_network(var/turf/turf = loc) + var/turf/T = turf if(!T || !istype(T)) return FALSE diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm index 5e0d5df5189ab..ef3a9592a5ee5 100644 --- a/code/modules/power/supermatter/supermatter.dm +++ b/code/modules/power/supermatter/supermatter.dm @@ -149,7 +149,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal) AddElement(/datum/element/point_of_interest) radio = new(src) radio.keyslot = new radio_key - radio.listening = 0 + radio.set_listening(FALSE) radio.recalculateChannels() distort = new(src) add_emitter(/obj/emitter/sparkle, "supermatter_sparkle") diff --git a/code/modules/power/terminal.dm b/code/modules/power/terminal.dm index 9c47ddb47c5d5..a36f29624d4a5 100644 --- a/code/modules/power/terminal.dm +++ b/code/modules/power/terminal.dm @@ -65,3 +65,7 @@ /obj/machinery/power/terminal/wirecutter_act(mob/living/user, obj/item/I) dismantle(user, I) return TRUE + +/obj/machinery/power/terminal/invisible + name = "" + icon_state = "" diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm index 2248ac3b96fd8..42b7bc6dfc2b9 100644 --- a/code/modules/projectiles/projectile.dm +++ b/code/modules/projectiles/projectile.dm @@ -305,7 +305,7 @@ if(firer && HAS_TRAIT(firer, TRAIT_NICE_SHOT)) best_angle += NICE_SHOT_RICOCHET_BONUS for(var/mob/living/L in range(ricochet_auto_aim_range, src.loc)) - if(L.stat == DEAD || !isInSight(src, L)) + if(L.stat == DEAD || !is_in_sight(src, L)) continue var/our_angle = abs(closer_angle_difference(Angle, get_angle(src.loc, L.loc))) if(our_angle < best_angle) diff --git a/code/modules/projectiles/projectile/bullets/shotgun.dm b/code/modules/projectiles/projectile/bullets/shotgun.dm index 86a443b61519b..64550fa036a23 100644 --- a/code/modules/projectiles/projectile/bullets/shotgun.dm +++ b/code/modules/projectiles/projectile/bullets/shotgun.dm @@ -146,8 +146,8 @@ bleed_force = BLEED_SURFACE /obj/projectile/bullet/shotgun_breaching/on_hit(atom/target) - if(istype(target, /obj/structure/window) || istype(target, /obj/structure/grille) || istype(target, /obj/machinery/door) || istype(target, /obj/structure/door_assembly)) + if(isstructure(target) || ismachinery(target)) damage = 500 //one shot to break a window or grille, or 3 shots to breach an airlock door if (isturf(target)) - damage = 300 + damage = 700 ..() diff --git a/code/modules/security/genpop.dm b/code/modules/security/genpop.dm index 307b984cff784..c0833b6db92ab 100644 --- a/code/modules/security/genpop.dm +++ b/code/modules/security/genpop.dm @@ -382,7 +382,7 @@ build_static_information() Radio = new/obj/item/radio(src) - Radio.listening = 0 + Radio.set_listening(FALSE) Radio.set_frequency(FREQ_SECURITY) /obj/machinery/genpop_interface/proc/build_static_information() diff --git a/code/modules/station_goals/bsa.dm b/code/modules/station_goals/bsa.dm index 4fb1b79746a18..fa168fb5d3b29 100644 --- a/code/modules/station_goals/bsa.dm +++ b/code/modules/station_goals/bsa.dm @@ -25,7 +25,7 @@ GLOBAL_VAR_INIT(bsa_unlock, FALSE) /datum/station_goal/bluespace_cannon/check_completion() if(..()) return TRUE - var/obj/machinery/bsa/full/B = locate() + var/obj/machinery/power/bsa/full/B = locate() if(B && !B.machine_stat) return TRUE return FALSE @@ -129,26 +129,51 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) return WEST -/obj/machinery/bsa/full +/obj/machinery/power/bsa/full name = "Bluespace Artillery" desc = "Long range bluespace artillery." icon = 'icons/obj/lavaland/cannon.dmi' icon_state = "cannon_west" + var/base_battery_icon_state = "bsa_west_capacitor" var/static/mutable_appearance/top_layer var/ex_power = 3 - var/power_used_per_shot = 2000000 //enough to kil standard apc - todo : make this use wires instead and scale explosion power with it var/ready + + var/power_used_per_shot = 5000000 + var/obj/item/stock_parts/cell/cell + var/obj/machinery/power/terminal/invisible/terminal + use_power = NO_POWER_USE + idle_power_usage = 50 // when idle + active_power_usage = INFINITY // how much you can charge at once + var/charge_efficiency = 0.6 // 60% of power is stored in the cell + pixel_y = -32 pixel_x = -192 bound_width = 352 bound_x = -192 + density = TRUE appearance_flags = NONE //Removes default TILE_BOUND resistance_flags = LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF -/obj/machinery/bsa/full/wrench_act(mob/living/user, obj/item/I) + var/sound/select_sound = 'sound/machines/bsa/bsa_charge.ogg' + var/select_sound_length = 17 SECONDS + + var/sound/fire_sound = 'sound/machines/bsa/bsa_fire.ogg' + var/winding_up = FALSE // if true, sparks will be generated in the bullseye + + var/last_charge_quarter = 0 + + + +/obj/machinery/power/bsa/full/wrench_act(mob/living/user, obj/item/I) return FALSE -/obj/machinery/bsa/full/proc/get_front_turf() +/obj/machinery/power/bsa/full/Destroy() + . = ..() + QDEL_NULL(cell) + QDEL_NULL(terminal) + +/obj/machinery/power/bsa/full/proc/get_front_turf() switch(dir) if(WEST) return locate(x - 7,y,z) @@ -156,7 +181,7 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) return locate(x + 4,y,z) return get_turf(src) -/obj/machinery/bsa/full/proc/get_back_turf() +/obj/machinery/power/bsa/full/proc/get_back_turf() switch(dir) if(WEST) return locate(x + 4,y,z) @@ -164,7 +189,7 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) return locate(x - 6,y,z) return get_turf(src) -/obj/machinery/bsa/full/proc/get_target_turf() +/obj/machinery/power/bsa/full/proc/get_target_turf() switch(dir) if(WEST) return locate(1,y,z) @@ -172,25 +197,73 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) return locate(world.maxx,y,z) return get_turf(src) -/obj/machinery/bsa/full/Initialize(mapload, cannon_direction = WEST) +/obj/machinery/power/bsa/full/proc/make_terminal(turf/T) + // create a terminal object at the same position as original turf loc + // wires will attach to this + terminal = new /obj/machinery/power/terminal/invisible(T) + terminal.master = src + +/obj/machinery/power/bsa/full/Initialize(mapload, cannon_direction = WEST) . = ..() + cell = new /obj/item/stock_parts/cell(src, 5000000) + cell.charge = 0 top_layer = top_layer || mutable_appearance(icon, layer = ABOVE_MOB_LAYER) switch(cannon_direction) if(WEST) setDir(WEST) pixel_x = -192 - top_layer.icon_state = "top_west" - icon_state = "cannon_west" if(EAST) setDir(EAST) - top_layer.icon_state = "top_east" - icon_state = "cannon_east" - add_overlay(top_layer) - reload() + update_icon_state() + make_terminal(get_back_turf()) + + +/obj/machinery/power/bsa/full/update_icon_state() + . = ..() + icon_state = "cannon_[dir2text(dir)]" + base_battery_icon_state = "bsa_[dir2text(dir)]_capacitor" -/obj/machinery/bsa/full/proc/fire(mob/user, turf/bullseye) - reload() +/obj/machinery/power/bsa/full/update_overlays() + . = ..() + cut_overlays() + add_overlay(top_layer) + top_layer.icon_state = "top_[dir2text(dir)]" + + var/charge_quarter = FLOOR(cell.percent() / 25, 1) + var/charge_sound = 'sound/machines/apc/PowerSwitch_Off.ogg' + if(charge_quarter >= 1) + add_overlay("[base_battery_icon_state]_25") + if(charge_quarter >= 2) + add_overlay("[base_battery_icon_state]_50") + if(charge_quarter >= 3) + add_overlay("[base_battery_icon_state]_75") + if(charge_quarter >= 4) + add_overlay("[base_battery_icon_state]_100") + charge_sound = 'sound/machines/apc/PowerUp_001.ogg' + if(charge_quarter > last_charge_quarter) + playsound(get_turf(src), charge_sound, 25, 1) + + +/obj/machinery/power/bsa/full/proc/charge_up(mob/user, turf/bullseye) + if(!cell.use(power_used_per_shot)) + return FALSE + var/sound/charge_up = sound(select_sound) + playsound(get_turf(src), charge_up, 50, 1) + var/timerid = addtimer(CALLBACK(src, PROC_REF(fire), user, bullseye), select_sound_length, TIMER_STOPPABLE) + winding_up = TRUE + var/list/turfs = spiral_range_turfs(ex_power * 2, bullseye) + var/base_cooldown = 2 SECONDS + var/cooldown = base_cooldown + while(winding_up) + if(QDELETED(src)) + break + new /obj/effect/particle_effect/sparks/shield(pick(turfs)) + cooldown = base_cooldown * ((timeleft(timerid)) / select_sound_length) + sleep(cooldown) +/obj/machinery/power/bsa/full/proc/fire(mob/user, turf/bullseye) + winding_up = FALSE + playsound(get_turf(src), fire_sound, 50, 1, world.maxx) var/turf/point = get_front_turf() var/turf/target = get_target_turf() var/atom/movable/blocker @@ -222,16 +295,26 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) log_game("[key_name(user)] has launched an artillery strike targeting [AREACOORD(bullseye)] but it was blocked by [blocker] at [AREACOORD(target)].") -/obj/machinery/bsa/full/proc/reload() +/obj/machinery/power/bsa/full/proc/reload() ready = FALSE - use_power(power_used_per_shot) ui_update() addtimer(CALLBACK(src,"ready_cannon"),600) -/obj/machinery/bsa/full/proc/ready_cannon() +/obj/machinery/power/bsa/full/proc/ready_cannon() ready = TRUE ui_update() +/obj/machinery/power/bsa/full/process(delta_time) + if(cell.percent() >= 100 || terminal.surplus() < 1) + return + terminal.add_load(idle_power_usage) + var/charge = clamp(terminal.surplus() * delta_time, 0, active_power_usage) + terminal.add_load(charge) + cell.give(charge * charge_efficiency) + update_appearance(UPDATE_OVERLAYS) + last_charge_quarter = FLOOR(cell.percent() / 25, 1) + ui_update() + /obj/structure/filler name = "big machinery part" density = TRUE @@ -254,7 +337,6 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) canSmoothWith = null - var/datum/weakref/cannon_ref var/notice var/target @@ -272,12 +354,14 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) //Missing updates for: target GPS name changes /obj/machinery/computer/bsa_control/ui_data() - var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve() + var/obj/machinery/power/bsa/full/cannon = cannon_ref?.resolve() var/list/data = list() data["ready"] = cannon ? cannon.ready : FALSE data["connected"] = cannon data["notice"] = notice data["unlocked"] = GLOB.bsa_unlock + data["charge"] = cannon ? cannon.cell.charge : 0 + data["max_charge"] = cannon ? cannon.cell.maxcharge : 0 if(target) data["target"] = get_target_name() else @@ -303,20 +387,20 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) /obj/machinery/computer/bsa_control/proc/calibrate(mob/user) if(!GLOB.bsa_unlock) return - var/list/gps_locators = list() - for(var/datum/component/gps/G in GLOB.GPS_list) //nulls on the list somehow + var/list/targets = list() + // Find all active GPS + for(var/datum/component/gps/G in GLOB.GPS_list) if(G.tracking) - gps_locators[G.gpstag] = G + targets[G.gpstag] = G - var/list/options = gps_locators if(area_aim) - options += GLOB.teleportlocs - var/victim = tgui_input_list(user, "Select target", "Artillery Targeting", options) + targets += GLOB.teleportlocs + var/victim = tgui_input_list(user, "Select target", "Artillery Targeting", targets) if(isnull(victim)) return - if(isnull(options[victim])) + if(isnull(targets[victim])) return - target = options[victim] + target = targets[victim] var/datum/component/gps/log_target = target log_game("[key_name(user)] has aimed the bluespace artillery strike (BSA) at [get_area_name(log_target.parent)].") @@ -335,19 +419,20 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) var/datum/component/gps/G = target return get_turf(G.parent) + /obj/machinery/computer/bsa_control/proc/fire(mob/user) - var/obj/machinery/bsa/full/cannon = cannon_ref?.resolve() + var/obj/machinery/power/bsa/full/cannon = cannon_ref?.resolve() if(!cannon) notice = "No Cannon Exists!" return - if(cannon.machine_stat) - notice = "Cannon unpowered!" + if(cannon.cell.percent() < 100) + notice = "Cannon doesn't have enough charge!" return notice = null - cannon.fire(user, get_impact_turf()) + cannon.charge_up(user, get_impact_turf()) /obj/machinery/computer/bsa_control/proc/deploy(force=FALSE) - var/obj/machinery/bsa/full/prebuilt = locate() in range(7) //In case of adminspawn + var/obj/machinery/power/bsa/full/prebuilt = locate() in range(7) //In case of adminspawn if(prebuilt) return prebuilt @@ -362,7 +447,7 @@ DEFINE_BUFFER_HANDLER(/obj/machinery/bsa/middle) var/datum/effect_system/smoke_spread/s = new s.set_up(4,get_turf(centerpiece)) s.start() - var/obj/machinery/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction()) + var/obj/machinery/power/bsa/full/cannon = new(get_turf(centerpiece),centerpiece.get_cannon_direction()) QDEL_NULL(centerpiece.front_ref) QDEL_NULL(centerpiece.back_ref) qdel(centerpiece) diff --git a/code/modules/tgs/core/README.md b/code/modules/tgs/core/README.md index b82d8f49e297f..965e21b549a3e 100644 --- a/code/modules/tgs/core/README.md +++ b/code/modules/tgs/core/README.md @@ -3,7 +3,7 @@ This folder contains all DMAPI code not directly involved in an API. - [_definitions.dm](./definitions.dm) contains defines needed across DMAPI internals. +- [byond_world_export.dm](./byond_world_export.dm) contains the default `/datum/tgs_http_handler` implementation which uses `world.Export()`. - [core.dm](./core.dm) contains the implementations of the `/world/proc/TgsXXX()` procs. Many map directly to the `/datum/tgs_api` functions. It also contains the /datum selection and setup code. - [datum.dm](./datum.dm) contains the `/datum/tgs_api` declarations that all APIs must implement. - [tgs_version.dm](./tgs_version.dm) contains the `/datum/tgs_version` definition -- diff --git a/code/modules/tgs/core/byond_world_export.dm b/code/modules/tgs/core/byond_world_export.dm new file mode 100644 index 0000000000000..6ef8d841b8f76 --- /dev/null +++ b/code/modules/tgs/core/byond_world_export.dm @@ -0,0 +1,22 @@ +/datum/tgs_http_handler/byond_world_export + +/datum/tgs_http_handler/byond_world_export/PerformGet(url) + // This is an infinite sleep until we get a response + var/export_response = world.Export(url) + TGS_DEBUG_LOG("byond_world_export: Export complete") + + if(!export_response) + TGS_ERROR_LOG("byond_world_export: Failed request: [url]") + return new /datum/tgs_http_result(null, FALSE) + + var/content = export_response["CONTENT"] + if(!content) + TGS_ERROR_LOG("byond_world_export: Failed request, missing content!") + return new /datum/tgs_http_result(null, FALSE) + + var/response_json = TGS_FILE2TEXT_NATIVE(content) + if(!response_json) + TGS_ERROR_LOG("byond_world_export: Failed request, failed to load content!") + return new /datum/tgs_http_result(null, FALSE) + + return new /datum/tgs_http_result(response_json, TRUE) diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm index 15622228e91fe..63cb5a2c35147 100644 --- a/code/modules/tgs/core/core.dm +++ b/code/modules/tgs/core/core.dm @@ -1,4 +1,4 @@ -/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE) +/world/TgsNew(datum/tgs_event_handler/event_handler, minimum_required_security_level = TGS_SECURITY_ULTRASAFE, datum/tgs_http_handler/http_handler = null) var/current_api = TGS_READ_GLOBAL(tgs) if(current_api) TGS_ERROR_LOG("API datum already set (\ref[current_api] ([current_api]))! Was TgsNew() called more than once?") @@ -55,7 +55,10 @@ TGS_ERROR_LOG("Invalid parameter for event_handler: [event_handler]") event_handler = null - var/datum/tgs_api/new_api = new api_datum(event_handler, version) + if(!http_handler) + http_handler = new /datum/tgs_http_handler/byond_world_export + + var/datum/tgs_api/new_api = new api_datum(event_handler, version, http_handler) TGS_WRITE_GLOBAL(tgs, new_api) diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm index f734fd0527f0e..3ca53e9bf7c65 100644 --- a/code/modules/tgs/core/datum.dm +++ b/code/modules/tgs/core/datum.dm @@ -6,7 +6,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null) var/list/warned_deprecated_command_runs -/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version) +/datum/tgs_api/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version, datum/tgs_http_handler/http_handler) ..() src.event_handler = event_handler src.version = version diff --git a/code/modules/tgs/includes.dm b/code/modules/tgs/includes.dm index 23b714f9d0643..f5118ed55a3c2 100644 --- a/code/modules/tgs/includes.dm +++ b/code/modules/tgs/includes.dm @@ -1,4 +1,5 @@ #include "core\_definitions.dm" +#include "core\byond_world_export.dm" #include "core\core.dm" #include "core\datum.dm" #include "core\tgs_version.dm" diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm index 05d0dee25b3c2..3e328fc7c27d5 100644 --- a/code/modules/tgs/v5/api.dm +++ b/code/modules/tgs/v5/api.dm @@ -31,9 +31,12 @@ var/detached = FALSE -/datum/tgs_api/v5/New() + var/datum/tgs_http_handler/http_handler + +/datum/tgs_api/v5/New(datum/tgs_event_handler/event_handler, datum/tgs_version/version, datum/tgs_http_handler/http_handler) . = ..() interop_version = version + src.http_handler = http_handler TGS_DEBUG_LOG("V5 API created: [json_encode(args)]") /datum/tgs_api/v5/ApiVersion() diff --git a/code/modules/tgs/v5/bridge.dm b/code/modules/tgs/v5/bridge.dm index 0c5e701a32b60..62201fcc9e58b 100644 --- a/code/modules/tgs/v5/bridge.dm +++ b/code/modules/tgs/v5/bridge.dm @@ -78,27 +78,24 @@ WaitForReattach(FALSE) TGS_DEBUG_LOG("Bridge request start") - // This is an infinite sleep until we get a response - var/export_response = world.Export(bridge_request) + var/datum/tgs_http_result/result = http_handler.PerformGet(bridge_request) TGS_DEBUG_LOG("Bridge request complete") - if(!export_response) - TGS_ERROR_LOG("Failed bridge request: [bridge_request]") + if(isnull(result)) + TGS_ERROR_LOG("Failed bridge request, handler returned null!") return - var/content = export_response["CONTENT"] - if(!content) - TGS_ERROR_LOG("Failed bridge request, missing content!") + if(!istype(result) || result.type != /datum/tgs_http_result) + TGS_ERROR_LOG("Failed bridge request, handler returned non-[/datum/tgs_http_result]!") return - var/response_json = TGS_FILE2TEXT_NATIVE(content) - if(!response_json) - TGS_ERROR_LOG("Failed bridge request, failed to load content!") + if(!result.success) + TGS_DEBUG_LOG("Failed bridge request, HTTP request failed!") return - var/list/bridge_response = json_decode(response_json) + var/list/bridge_response = json_decode(result.response_text) if(!bridge_response) - TGS_ERROR_LOG("Failed bridge request, bad json: [response_json]") + TGS_ERROR_LOG("Failed bridge request, bad json: [result.response_text]") return var/error = bridge_response[DMAPI5_RESPONSE_ERROR_MESSAGE] diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index a2690fdc500e9..b779b9b932278 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -2492,7 +2492,7 @@ GLOBAL_LIST_INIT(illegal_tech_blacklist, typecacheof(list( item = /obj/item/storage/backpack/duffelbag/clown/syndie /datum/uplink_item/badass/surprise_cake - name = "Rigged towering cake" + name = "Rigged Towering Cake" desc = "For hosting a surprise birthday party for the Captain, with a flashy surprise." item = /obj/structure/popout_cake/nukeop cost = 4 diff --git a/code/modules/vehicles/mecha/mecha_topic.dm b/code/modules/vehicles/mecha/mecha_topic.dm index 789cb783953e7..26b09a97e3bc2 100644 --- a/code/modules/vehicles/mecha/mecha_topic.dm +++ b/code/modules/vehicles/mecha/mecha_topic.dm @@ -120,14 +120,14 @@ Radio settings:
Microphone: [radio? "\ - [radio.broadcasting?"Engaged":"Disengaged"]":"Error"]
+ [radio.get_broadcasting()?"Engaged":"Disengaged"]":"Error"]
Speaker: [radio? "\ - [radio.listening?"Engaged":"Disengaged"]":"Error"]
+ [radio.get_listening()?"Engaged":"Disengaged"]":"Error"]
Frequency: [radio? "-":"-"] [radio? "-":"-"] - [radio?"[format_frequency(radio.frequency)]":"Error"] + [radio?"[format_frequency(radio.get_frequency())]":"Error"] [radio? "+":"+"] [radio? "+":"+"]
@@ -326,21 +326,21 @@ //Toggles radio broadcasting if(href_list["rmictoggle"]) - radio.broadcasting = !radio.broadcasting - send_byjax(usr,"exosuit.browser","rmicstate",(radio.broadcasting?"Engaged":"Disengaged")) + radio.set_broadcasting(!radio.get_broadcasting()) + send_byjax(usr,"exosuit.browser","rmicstate",(radio.get_broadcasting()?"Engaged":"Disengaged")) return //Toggles radio listening if(href_list["rspktoggle"]) - radio.listening = !radio.listening - send_byjax(usr,"exosuit.browser","rspkstate",(radio.listening?"Engaged":"Disengaged")) + radio.set_listening(!radio.get_listening()) + send_byjax(usr,"exosuit.browser","rspkstate",(radio.get_listening()?"Engaged":"Disengaged")) return //Changes radio freqency. if(href_list["rfreq"]) - var/new_frequency = radio.frequency + text2num(href_list["rfreq"]) + var/new_frequency = radio.get_frequency() + text2num(href_list["rfreq"]) radio.set_frequency(sanitize_frequency(new_frequency, radio.freerange)) - send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.frequency)]") + send_byjax(usr,"exosuit.browser","rfreq","[format_frequency(radio.get_frequency())]") return //Changes the exosuit name. diff --git a/code/modules/wiremod/shell/airlock.dm b/code/modules/wiremod/shell/airlock.dm index 358d4dcd9610d..89d58ec5992a0 100644 --- a/code/modules/wiremod/shell/airlock.dm +++ b/code/modules/wiremod/shell/airlock.dm @@ -2,7 +2,7 @@ holder_type = /obj/machinery/door/airlock/shell proper_name = "Circuit Airlock" -/datum/wires/airlock/shell/on_cut(wire, mend) +/datum/wires/airlock/shell/on_cut(wire, mob/user, mend) // Don't allow them to re-enable autoclose. if(wire == WIRE_TIMING) return diff --git a/html/changelog.html b/html/changelog.html index cbdda934477c6..15cf284762194 100644 --- a/html/changelog.html +++ b/html/changelog.html @@ -56,7 +56,81 @@ -->
+

22 August 2024

+

Dejaku51 updated:

+
    +
  • Zfall and Elevator controller doesn't init anymore
  • +
  • Natural Light Cycle subsystem inits correctly
  • +
+

Ivniinvi updated:

+
    +
  • fixed capitalization of cake in uplink
  • +
+ +

21 August 2024

+

HowToLoLu updated:

+
    +
  • FastDMM2 is usable once again for map editing
  • +
+ +

20 August 2024

+

ro5490 updated:

+
    +
  • Added a new Floor Cluwne Smite, and interaction
  • +
  • fixed the stalker smite from killing people
  • +
+ +

16 August 2024

+

Dejaku51 updated:

+
    +
  • BSA now has a windup with sparks on target location
  • +
  • BSA now has integrated battery and is powered with a cable attached to the end of BSA
  • +
  • BSA shows amount of charge in quarters on the capacitor part of the BSA
  • +
  • BSA requires 5MW to shoot
  • +
  • BSA now makes a sound when winding up and shooting
  • +
  • BSA makes a sound on quarters charged with unique one on full charge
  • +
+

Sarchutar updated:

+
    +
  • ability to close morgues when adjacent without having to click on the tray
  • +
  • cyborgs can now close morgues by clicking on the tray
  • +
+

Spockye updated:

+
    +
  • Remakes the escape pod shuttle
  • +
  • Ports Capybaras from Shiptest
  • +
+

rkz, Kylerace, LemonInTheDark, Tastyfish, Mat05usz updated:

+
    +
  • Adds new subsystem to optimize radio and searching areas
  • +
+ +

15 August 2024

+

Tsar-Salat updated:

+
    +
  • you can buckle to stuff from adjacent turfs again
  • +
  • adds missing step() hook in cardboard box relaymove. Boxes (and traitor stealth implant boxes) will now move when the player moves.
  • +
+

XeonMations updated:

+
    +
  • Examining a syndicate bomb now shows a balloon popup with the time remaining
  • +
  • Gave fire alarms a toggleable lock. (Requires atmospherics access)
  • +
  • Fire alarms now lock themselves when they detect a fire.
  • +
+

rkz updated:

+
    +
  • possibly fixes stamina healing
  • +
+

14 August 2024

+

PowerfulBacon updated:

+
    +
  • Billy clubs will now deal bonus to damage all structures and machines.
  • +
  • Billy clubs no longer conduct electricity.
  • +
  • Breaching rounds will now deal bonus damage all structures and machines. Increases damage against turfs.
  • +
  • Added a maximum damage to prevent important structures in defense gamemodes from being killed in a single shot (Space dragons & Clock Cult).
  • +
  • Airlocks will no longer shock the target upon being broken due to an unintentional side-effect of using usr.
  • +

ro5490 updated:

  • sorted out keypress log clutter
  • @@ -768,78 +842,6 @@

    Gilgaxx updated:

    • fixed the metallic arm sprite turning you into a white square.
    - -

    20 June 2024

    -

    Gilgaxx updated:

    -
      -
    • Added a HUD button to access the Spawners Menu for ghosts
    • -
    • Added missing text description for swarmer in the Spawners Menu
    • -
    -

    PowerfulBacon updated:

    -
      -
    • Fixes being unable to use items while buckled.
    • -
    • Fixes inconsistencies between when you can and can't use items, resulting in hotkeys bypassing some item use checks.
    • -
    -

    ToasterBan updated:

    -
      -
    • Rust Heretic's Mark of Rust can no longer damage grenades
    • -
    - -

    19 June 2024

    -

    Gilgaxx updated:

    -
      -
    • Removed one time limitation on Reactivate Cameras module for Malf AI but lowered the cameras fixed (30 -> 20)
    • -
    • Action buttons for malf powers with multiple uses now correctly update
    • -
    • Purchasing more uses of a Malf Module now gives feedback in chat and with noise
    • -
    • Removed a malf power logging runtime
    • -
    -

    PowerfulBacon updated:

    -
      -
    • Mechs now take damage from xenomorph attacks
    • -
    -

    XeonMations updated:

    -
      -
    • Fixed a bug where any projectile would delete the singularity instead of being deleted itself.
    • -
    - -

    18 June 2024

    -

    PowerfulBacon updated:

    -
      -
    • You will now be hit by projectiles when moving, preventing abuse of inertia mechanics, lying and guns in space.
    • -
    -

    Tsar-Salat updated:

    -
      -
    • resolve build error
    • -
    - -

    17 June 2024

    -

    EvilDragonfiend updated:

    -
      -
    • Improved job datum access list readibility. "base_access" will be given always. if "jobs_have_minimal_access" config is turned on, "extra_access" will be given additionally.
    • -
    • added a investigate_list() proc. This returns a text form of a list, good to investigate a list at a glance. This will be useful when you want to investigate TGUI list.
    • -
    -

    MarkusLarsson421 updated:

    -
      -
    • Made nanite mindshield unobtainable.
    • -
    • Classified Nanites category (mindshield).
    • -
    -

    Miliviu updated:

    -
      -
    • Antag Token coin is now visible
    • -
    -

    PestoVerde322 updated:

    -
      -
    • fixed the Iansuit's and Beesuit's head icon not rendering.
    • -
    -

    PowerfulBacon updated:

    -
      -
    • Removes gravity auras from carp rifts due to lag.
    • -
    • Durand shield will no longer block projectiles shot from behind.
    • -
    -

    XeonMations updated:

    -
      -
    • Fixed candles being able to create unnatural darkness.
    • -
GoonStation 13 Development Team diff --git a/html/changelogs/.all_changelog.yml b/html/changelogs/.all_changelog.yml index 2ea381cba22cc..bb9ccc18756a0 100644 --- a/html/changelogs/.all_changelog.yml +++ b/html/changelogs/.all_changelog.yml @@ -43913,5 +43913,56 @@ DO NOT EDIT THIS FILE BY HAND! AUTOMATICALLY GENERATED BY ss13_genchangelog.py. - rscadd: personalized combat messages. Expect much more "you attack player" than "playername attacks player" 2024-08-14: + PowerfulBacon: + - balance: Billy clubs will now deal bonus to damage all structures and machines. + - balance: Billy clubs no longer conduct electricity. + - balance: Breaching rounds will now deal bonus damage all structures and machines. + Increases damage against turfs. + - tweak: Added a maximum damage to prevent important structures in defense gamemodes + from being killed in a single shot (Space dragons & Clock Cult). + - bugfix: Airlocks will no longer shock the target upon being broken due to an unintentional + side-effect of using usr. ro5490: - admin: sorted out keypress log clutter +2024-08-15: + Tsar-Salat: + - bugfix: you can buckle to stuff from adjacent turfs again + - bugfix: adds missing step() hook in cardboard box relaymove. Boxes (and traitor + stealth implant boxes) will now move when the player moves. + XeonMations: + - rscadd: Examining a syndicate bomb now shows a balloon popup with the time remaining + - rscadd: Gave fire alarms a toggleable lock. (Requires atmospherics access) + - balance: Fire alarms now lock themselves when they detect a fire. + rkz: + - bugfix: possibly fixes stamina healing +2024-08-16: + Dejaku51: + - rscadd: BSA now has a windup with sparks on target location + - rscadd: BSA now has integrated battery and is powered with a cable attached to + the end of BSA + - rscadd: BSA shows amount of charge in quarters on the capacitor part of the BSA + - balance: BSA requires 5MW to shoot + - soundadd: BSA now makes a sound when winding up and shooting + - soundadd: BSA makes a sound on quarters charged with unique one on full charge + Sarchutar: + - bugfix: ability to close morgues when adjacent without having to click on the + tray + - bugfix: cyborgs can now close morgues by clicking on the tray + Spockye: + - bugfix: Remakes the escape pod shuttle + - rscadd: Ports Capybaras from Shiptest + rkz, Kylerace, LemonInTheDark, Tastyfish, Mat05usz: + - code_imp: Adds new subsystem to optimize radio and searching areas +2024-08-20: + ro5490: + - rscadd: Added a new Floor Cluwne Smite, and interaction + - bugfix: fixed the stalker smite from killing people +2024-08-21: + HowToLoLu: + - bugfix: FastDMM2 is usable once again for map editing +2024-08-22: + Dejaku51: + - code_imp: Zfall and Elevator controller doesn't init anymore + - bugfix: Natural Light Cycle subsystem inits correctly + Ivniinvi: + - spellcheck: fixed capitalization of cake in uplink diff --git a/icons/mob/pets.dmi b/icons/mob/pets.dmi index 7a1739d5f76c5..ca3517ddcb1c5 100644 Binary files a/icons/mob/pets.dmi and b/icons/mob/pets.dmi differ diff --git a/icons/obj/lavaland/cannon.dmi b/icons/obj/lavaland/cannon.dmi index c434be513b1d7..3006ba03f3c2c 100644 Binary files a/icons/obj/lavaland/cannon.dmi and b/icons/obj/lavaland/cannon.dmi differ diff --git a/icons/obj/monitors.dmi b/icons/obj/monitors.dmi index ca919d0b9672c..8f24658c76135 100644 Binary files a/icons/obj/monitors.dmi and b/icons/obj/monitors.dmi differ diff --git a/sound/machines/bsa/bsa_charge.ogg b/sound/machines/bsa/bsa_charge.ogg new file mode 100644 index 0000000000000..2c255d11c846b Binary files /dev/null and b/sound/machines/bsa/bsa_charge.ogg differ diff --git a/sound/machines/bsa/bsa_fire.ogg b/sound/machines/bsa/bsa_fire.ogg new file mode 100644 index 0000000000000..70610b800138b Binary files /dev/null and b/sound/machines/bsa/bsa_fire.ogg differ diff --git a/tgui/packages/tgui/interfaces/BluespaceArtillery.js b/tgui/packages/tgui/interfaces/BluespaceArtillery.js index e2bf47d7ba2be..763b51fa30e4b 100644 --- a/tgui/packages/tgui/interfaces/BluespaceArtillery.js +++ b/tgui/packages/tgui/interfaces/BluespaceArtillery.js @@ -1,16 +1,26 @@ import { useBackend } from '../backend'; -import { Box, Button, LabeledList, NoticeBox, Section } from '../components'; +import { Box, Button, LabeledList, NoticeBox, ProgressBar, Section } from '../components'; import { Window } from '../layouts'; export const BluespaceArtillery = (props, context) => { const { act, data } = useBackend(context); - const { notice, connected, unlocked, target } = data; + const { notice, connected, unlocked, target, charge, max_charge } = data; return ( - + {!!notice && {notice}} {connected ? ( <> +
+ +
act('recalibrate')} />}>