diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 25141a232c003..7f2a071eec9bd 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -338,6 +338,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/station/engineering/atmos/project)
+"agF" = (
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/chair/sofa/bamboo/right{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"agI" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/simple/purple/visible{
@@ -567,8 +574,9 @@
/turf/open/floor/iron,
/area/station/hallway/primary/starboard)
"alg" = (
-/obj/structure/altar_of_gods,
-/obj/item/book/bible,
+/obj/structure/table/wood,
+/obj/item/paper_bin,
+/obj/item/pen,
/turf/open/floor/carpet/lone,
/area/station/service/chapel/office)
"alh" = (
@@ -2383,7 +2391,7 @@
/obj/structure/flora/bush/sunny/style_random,
/obj/machinery/light/small/directional/west,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"aWC" = (
/obj/machinery/computer/department_orders/engineering{
dir = 8
@@ -4591,7 +4599,7 @@
"bOl" = (
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"bOp" = (
/obj/effect/spawner/random/vending/snackvend,
/obj/effect/turf_decal/tile/blue{
@@ -6017,7 +6025,7 @@
},
/obj/structure/flora/bush/flowers_pp/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"css" = (
/obj/effect/turf_decal/stripes/white/line{
dir = 10
@@ -7248,7 +7256,7 @@
},
/obj/structure/flora/bush/flowers_yw/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"cPi" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 1
@@ -8810,10 +8818,9 @@
"dty" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/turf_decal/siding/wood,
/obj/machinery/light/floor,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"dtC" = (
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/effect/turf_decal/siding/purple{
@@ -20389,7 +20396,7 @@
},
/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"hpQ" = (
/obj/structure/closet/crate/coffin,
/obj/structure/window/spawner/directional/south,
@@ -21684,7 +21691,7 @@
},
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"hNY" = (
/obj/structure/cable,
/obj/structure/disposalpipe/segment,
@@ -25955,7 +25962,7 @@
},
/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"jsc" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/stripes/red/line{
@@ -26693,6 +26700,13 @@
},
/turf/open/floor/iron,
/area/station/cargo/office)
+"jEU" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/obj/effect/landmark/start/chaplain,
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"jEZ" = (
/obj/structure/hedge,
/obj/effect/decal/cleanable/dirt,
@@ -36544,7 +36558,7 @@
/obj/machinery/camera/autoname/directional/north,
/obj/machinery/light/small/directional/north,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"mYT" = (
/obj/structure/table,
/obj/item/assembly/igniter{
@@ -40246,7 +40260,7 @@
},
/obj/structure/flora/bush/flowers_yw/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"oqI" = (
/obj/structure/cable,
/obj/machinery/door/airlock{
@@ -43260,7 +43274,7 @@
},
/obj/machinery/airalarm/directional/north,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"pug" = (
/obj/structure/cable,
/obj/structure/disposalpipe/segment{
@@ -44160,7 +44174,7 @@
/obj/structure/flora/bush/sunny/style_random,
/obj/machinery/newscaster/directional/south,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"pHQ" = (
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
dir = 4
@@ -44442,7 +44456,7 @@
dir = 9
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"pMr" = (
/obj/structure/rack,
/obj/effect/spawner/random/maintenance/two,
@@ -44459,7 +44473,7 @@
dir = 1
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"pMA" = (
/obj/machinery/light/small/directional/east,
/turf/open/floor/catwalk_floor/iron_dark,
@@ -45274,7 +45288,7 @@
/obj/structure/flora/bush/flowers_yw/style_random,
/obj/effect/landmark/start/hangover,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"pYG" = (
/obj/structure/disposalpipe/segment{
dir = 5
@@ -45345,9 +45359,11 @@
/area/station/cargo/storage)
"qaA" = (
/obj/structure/disposalpipe/segment,
-/obj/structure/flora/bush/flowers_br/style_random,
-/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"qaH" = (
/obj/structure/cable,
/obj/effect/turf_decal/siding/dark_red/corner{
@@ -45408,8 +45424,11 @@
"qbr" = (
/obj/structure/flora/bush/flowers_pp/style_random,
/obj/effect/landmark/start/hangover,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qbw" = (
/obj/structure/disposalpipe/segment,
/obj/structure/cable,
@@ -46051,19 +46070,13 @@
/area/station/maintenance/starboard/greater)
"qkv" = (
/obj/structure/disposalpipe/segment,
-/obj/effect/turf_decal/siding/wood{
- dir = 1
- },
/obj/machinery/light/floor,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qkw" = (
-/obj/effect/turf_decal/siding/wood{
- dir = 1
- },
/obj/machinery/light/floor,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qkF" = (
/turf/open/floor/iron,
/area/station/commons)
@@ -46633,10 +46646,10 @@
/area/station/maintenance/aft)
"quJ" = (
/obj/effect/turf_decal/siding/wood,
-/obj/structure/flora/tree/stump,
/obj/machinery/light/small/directional/south,
+/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"quS" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -47131,15 +47144,11 @@
},
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qCi" = (
/obj/structure/disposalpipe/segment,
-/obj/structure/chair/sofa/bamboo/right{
- dir = 8
- },
-/obj/effect/landmark/start/assistant,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qCq" = (
/obj/structure/cable,
/obj/structure/window/reinforced/spawner/directional/north,
@@ -47170,12 +47179,8 @@
/turf/open/floor/iron/large,
/area/station/command/heads_quarters/hop)
"qCR" = (
-/obj/structure/chair/sofa/bamboo/left{
- dir = 4
- },
-/obj/effect/landmark/start/assistant,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qCU" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/structure/table/reinforced,
@@ -47811,6 +47816,11 @@
},
/turf/open/floor/plating,
/area/station/commons/storage/tools)
+"qOp" = (
+/obj/structure/table/wood,
+/obj/item/book/bible,
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"qOt" = (
/obj/item/kirbyplants/random,
/obj/effect/turf_decal/tile/neutral/fourcorners,
@@ -48553,7 +48563,7 @@
dir = 4
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"qZG" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/broken_flooring/corner/directional/south,
@@ -48602,7 +48612,7 @@
"ram" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"raz" = (
/obj/machinery/door/airlock/public/glass{
name = "Lavatorie"
@@ -48612,12 +48622,12 @@
/area/station/commons/toilet/restrooms)
"raC" = (
/obj/structure/disposalpipe/segment,
+/obj/effect/landmark/start/assistant,
/obj/structure/chair/sofa/bamboo/left{
- dir = 8
+ dir = 1
},
-/obj/effect/landmark/start/assistant,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"raE" = (
/obj/machinery/duct,
/turf/open/floor/iron,
@@ -48637,16 +48647,16 @@
/turf/open/floor/iron,
/area/station/hallway/secondary/dock)
"raX" = (
+/obj/effect/landmark/start/assistant,
/obj/structure/chair/sofa/bamboo/right{
- dir = 4
+ dir = 1
},
-/obj/effect/landmark/start/chaplain,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rba" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rbc" = (
/obj/structure/transport/linear/tram,
/obj/structure/tram,
@@ -48662,7 +48672,7 @@
},
/obj/machinery/power/apc/auto_name/directional/east,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rbo" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/door/firedoor,
@@ -50067,7 +50077,7 @@
dir = 5
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"ryt" = (
/obj/machinery/light/dim/directional/north,
/obj/effect/turf_decal/tile/neutral{
@@ -50110,10 +50120,9 @@
/area/station/science/breakroom)
"rzu" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/turf_decal/siding/wood,
/obj/machinery/light/floor,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rzG" = (
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/tile/dark_red/half/contrasted{
@@ -50157,7 +50166,7 @@
dir = 9
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rAg" = (
/obj/structure/cable,
/obj/effect/mapping_helpers/broken_floor,
@@ -50927,7 +50936,7 @@
/obj/effect/turf_decal/siding/wood/corner,
/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"rMa" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -52068,7 +52077,7 @@
dir = 4
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"sdm" = (
/obj/effect/mapping_helpers/broken_floor,
/turf/open/floor/plating,
@@ -53396,9 +53405,8 @@
/area/station/security/warden)
"syv" = (
/obj/structure/disposalpipe/segment,
-/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"syx" = (
/obj/structure/cable,
/obj/structure/disposalpipe/segment,
@@ -53424,7 +53432,7 @@
"syG" = (
/obj/effect/spawner/xmastree,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"syN" = (
/obj/effect/spawner/random/trash,
/turf/open/floor/plating,
@@ -53450,7 +53458,7 @@
"szy" = (
/obj/effect/spawner/random/engineering/tracking_beacon,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"szz" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -54153,7 +54161,7 @@
},
/obj/effect/decal/cleanable/cobweb,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"sMq" = (
/obj/machinery/light/warm/directional/west,
/turf/open/floor/iron,
@@ -54887,14 +54895,14 @@
dir = 4
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"sYK" = (
/obj/effect/turf_decal/siding/wood{
dir = 5
},
/obj/structure/flora/bush/sunny/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"sZn" = (
/obj/structure/table,
/obj/effect/turf_decal/siding/wood{
@@ -55129,7 +55137,7 @@
/obj/effect/turf_decal/siding/wood,
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"tdh" = (
/obj/structure/chair/sofa/corp/right{
dir = 4
@@ -56419,7 +56427,7 @@
"tzJ" = (
/obj/structure/flora/bush/flowers_yw/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"tAq" = (
/obj/structure/rack,
/obj/effect/spawner/random/maintenance,
@@ -56585,7 +56593,7 @@
},
/obj/machinery/light/directional/east,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"tCm" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/turf_decal/tile/red{
@@ -56744,7 +56752,7 @@
},
/obj/machinery/light/small/directional/east,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"tEW" = (
/obj/structure/disposalpipe/segment{
dir = 6
@@ -57578,7 +57586,7 @@
/obj/structure/flora/bush/flowers_pp/style_random,
/obj/machinery/firealarm/directional/east,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"tTR" = (
/obj/effect/spawner/structure/window/reinforced/plasma,
/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible,
@@ -58013,7 +58021,7 @@
dir = 6
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"uab" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -58032,7 +58040,7 @@
},
/obj/structure/flora/tree/stump,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"uax" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -58048,7 +58056,7 @@
},
/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"uaP" = (
/obj/structure/mirror/directional/east,
/obj/structure/chair/stool/bar/directional/east,
@@ -59118,7 +59126,7 @@
/obj/structure/flora/bush/flowers_yw/style_random,
/obj/machinery/light/small/directional/east,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"utD" = (
/obj/machinery/light_switch/directional/west,
/obj/effect/turf_decal/stripes/corner{
@@ -60506,7 +60514,7 @@
/obj/structure/flora/tree/jungle/small/style_random,
/obj/structure/flora/bush/flowers_pp/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"uSi" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -60535,8 +60543,13 @@
/turf/open/floor/iron,
/area/station/science/lower)
"uSC" = (
-/turf/closed/wall/mineral/wood/nonmetal,
-/area/station/service/hydroponics/garden/monastery)
+/obj/effect/landmark/start/assistant,
+/obj/effect/landmark/start/assistant,
+/obj/structure/chair/sofa/bamboo/left{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"uSG" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -60864,11 +60877,9 @@
/turf/closed/wall,
/area/station/science/lower)
"uXN" = (
-/obj/effect/turf_decal/siding/wood{
- dir = 1
- },
+/obj/structure/altar_of_gods,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"uXU" = (
/obj/effect/spawner/random/structure/closet_maintenance,
/obj/effect/spawner/random/maintenance,
@@ -61622,15 +61633,14 @@
/area/station/engineering/atmos)
"vkz" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/effect/turf_decal/siding/wood,
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vkG" = (
/obj/effect/turf_decal/siding/wood/corner{
dir = 1
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vkJ" = (
/obj/item/book/manual/wiki/security_space_law{
pixel_x = 9;
@@ -62681,7 +62691,7 @@
dir = 8
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vzV" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -62692,8 +62702,12 @@
/area/station/security/tram)
"vzW" = (
/obj/structure/disposalpipe/segment,
-/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/chair/sofa/bamboo/left{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"vzX" = (
/obj/machinery/door/airlock/command{
name = "Centcom Dock"
@@ -62753,8 +62767,12 @@
/area/station/security/tram)
"vAA" = (
/obj/effect/landmark/start/hangover,
-/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/obj/effect/turf_decal/siding/wood,
+/obj/structure/chair/sofa/bamboo/left{
+ dir = 1
+ },
+/turf/open/floor/wood/large,
+/area/station/service/chapel)
"vAC" = (
/obj/structure/flora/bush/large/style_random{
pixel_y = -3
@@ -62780,8 +62798,11 @@
"vAR" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/effect/turf_decal/siding/wood{
+ dir = 8
+ },
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vAT" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -63800,7 +63821,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/flora/bush/flowers_yw/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vSL" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/turf_decal/tile/neutral{
@@ -63824,7 +63845,7 @@
"vSX" = (
/obj/structure/flora/bush/sunny/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"vSY" = (
/obj/structure/table,
/obj/item/chisel{
@@ -64912,7 +64933,7 @@
},
/obj/structure/flora/bush/sunny/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"wjM" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/disposalpipe/segment{
@@ -65004,7 +65025,7 @@
/obj/structure/disposalpipe/segment,
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"wlJ" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -65023,7 +65044,7 @@
/obj/effect/turf_decal/siding/wood,
/obj/structure/flora/bush/flowers_pp/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"wme" = (
/obj/effect/spawner/random/structure/crate,
/turf/open/floor/plating,
@@ -65194,7 +65215,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"woD" = (
/obj/effect/turf_decal/siding/wood{
dir = 4
@@ -67372,7 +67393,7 @@
/obj/structure/flora/bush/flowers_pp/style_random,
/obj/effect/landmark/event_spawn,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"wWc" = (
/obj/effect/spawner/structure/window,
/turf/open/floor/plating,
@@ -68894,7 +68915,7 @@
},
/obj/structure/flora/bush/flowers_br/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"xpU" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -70777,7 +70798,7 @@
"xPR" = (
/obj/structure/flora/tree/jungle/small/style_random,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"xPW" = (
/obj/item/kirbyplants/random/fullysynthetic,
/turf/open/floor/wood/parquet,
@@ -71005,7 +71026,7 @@
"xRZ" = (
/obj/effect/turf_decal/siding/wood,
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"xSe" = (
/obj/structure/table/glass,
/obj/structure/microscope,
@@ -71525,7 +71546,7 @@
/area/station/maintenance/starboard/greater)
"xYD" = (
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"xYE" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -71666,8 +71687,11 @@
/turf/open/floor/stone,
/area/station/command/heads_quarters/hos)
"yaG" = (
+/obj/effect/turf_decal/siding/wood{
+ dir = 1
+ },
/turf/open/floor/wood/large,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"yaI" = (
/obj/structure/cable,
/obj/structure/disposalpipe/segment,
@@ -72366,7 +72390,7 @@
dir = 1
},
/turf/open/floor/grass,
-/area/station/service/hydroponics/garden/monastery)
+/area/station/service/chapel)
"yjE" = (
/turf/closed/wall/r_wall,
/area/station/maintenance/department/engine)
@@ -84976,12 +85000,12 @@ mhk
mhk
mhk
csp
-xYD
+qZB
uaa
-yaG
+qCR
ram
ryp
-xYD
+qZB
xYD
xRZ
wBm
@@ -85490,12 +85514,12 @@ rYD
mhk
jrZ
xYD
-xYD
+jEU
uXN
-uSC
-uSC
+qCR
+raX
vkz
-xYD
+agF
syG
pHN
wAW
@@ -85747,9 +85771,9 @@ pbu
mhk
mYS
xYD
-xPR
-uXN
-uSC
+yaG
+qOp
+qCR
uSC
vkz
vAA
@@ -86004,12 +86028,12 @@ xLO
mhk
ptZ
sYF
-tzJ
+yaG
qkw
qCR
raX
rzu
-xYD
+agF
xYD
wlQ
wBm
@@ -86263,7 +86287,7 @@ mhk
oqE
qbr
hNT
-yaG
+qCR
rba
rAb
vAR
diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm
index ed91e1bd69733..e83a6941c8855 100644
--- a/_maps/map_files/NorthStar/north_star.dmm
+++ b/_maps/map_files/NorthStar/north_star.dmm
@@ -947,6 +947,12 @@
/obj/effect/turf_decal/tile/purple/opposingcorners,
/turf/open/floor/iron/white,
/area/station/command/heads_quarters/rd)
+"alL" = (
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark/side{
+ dir = 8
+ },
+/area/station/hallway/floor2/fore)
"amg" = (
/obj/structure/cable,
/obj/machinery/power/apc/auto_name/directional/east,
@@ -1289,6 +1295,15 @@
/obj/item/clothing/mask/facehugger/toy,
/turf/open/floor/pod/light,
/area/station/maintenance/floor1/starboard)
+"aqm" = (
+/obj/machinery/door/firedoor/border_only,
+/obj/structure/railing,
+/obj/effect/turf_decal/box/red,
+/obj/machinery/atmospherics/components/unary/portables_connector/visible/layer4{
+ dir = 8
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"aqu" = (
/obj/effect/turf_decal/siding/wood,
/obj/structure/disposalpipe/segment{
@@ -4573,10 +4588,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/iron/white,
/area/station/medical/psychology)
-"bgq" = (
-/obj/machinery/bluespace_vendor/directional/west,
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor2/fore)
"bgr" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark/textured_corner,
@@ -6525,15 +6536,6 @@
/obj/structure/chair/plastic,
/turf/open/floor/pod/light,
/area/station/maintenance/floor3/port/aft)
-"bBT" = (
-/obj/effect/turf_decal/trimline/blue/line{
- dir = 4
- },
-/obj/effect/turf_decal/trimline/purple/line{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor2/fore)
"bBV" = (
/obj/effect/turf_decal/trimline/green/arrow_cw{
dir = 8
@@ -6978,6 +6980,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/station/medical/abandoned)
+"bJA" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
+ dir = 8
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"bJQ" = (
/obj/structure/railing/corner{
dir = 1
@@ -7450,12 +7459,6 @@
},
/turf/open/floor/iron/dark,
/area/station/security/checkpoint/third)
-"bQo" = (
-/obj/machinery/bluespace_vendor/directional/north,
-/turf/open/floor/iron/dark/side{
- dir = 4
- },
-/area/station/hallway/floor4/aft)
"bQv" = (
/obj/machinery/power/terminal{
dir = 4
@@ -8055,13 +8058,6 @@
dir = 1
},
/area/station/hallway/floor2/aft)
-"bYl" = (
-/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/layer2{
- dir = 4
- },
-/obj/machinery/atmospherics/components/unary/vent_scrubber,
-/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance/freezerchamber)
"bYp" = (
/obj/structure/rack,
/obj/effect/spawner/random/engineering/material,
@@ -10367,12 +10363,6 @@
/obj/machinery/duct,
/turf/open/floor/iron/white,
/area/station/medical/morgue)
-"cBP" = (
-/obj/effect/spawner/structure/window/hollow/plasma/middle{
- dir = 4
- },
-/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance/freezerchamber)
"cBU" = (
/obj/structure/window/reinforced/spawner/directional/west,
/obj/structure/flora/bush/sunny/style_random,
@@ -11170,6 +11160,14 @@
},
/turf/open/floor/iron/smooth_large,
/area/station/hallway/secondary/entry)
+"cMz" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/obj/machinery/camera/autoname/directional/south,
+/obj/machinery/bluespace_vendor/directional/south,
+/turf/open/floor/iron/dark/side,
+/area/station/hallway/floor2/aft)
"cMA" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -16510,21 +16508,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/iron/dark/side,
/area/station/command/teleporter)
-"ehZ" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/structure/cable,
-/obj/structure/table/reinforced,
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/obj/effect/turf_decal/trimline/dark_blue/end{
- dir = 8
- },
-/obj/item/storage/toolbox/emergency,
-/obj/machinery/bluespace_vendor/directional/south,
-/turf/open/floor/iron/dark,
-/area/station/commons/storage/tools)
"eir" = (
/obj/machinery/door/airlock/hatch{
name = "Maintenance Access"
@@ -17588,11 +17571,6 @@
dir = 8
},
/area/station/security/office)
-"exv" = (
-/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible/layer2,
-/obj/machinery/atmospherics/pipe/smart/simple/purple,
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"exw" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -18770,6 +18748,10 @@
/obj/structure/cable,
/turf/open/floor/iron,
/area/station/cargo/storage)
+"eOC" = (
+/obj/machinery/bluespace_vendor/directional/north,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor3/fore)
"eOP" = (
/turf/closed/wall/r_wall,
/area/station/hallway/floor4/aft)
@@ -18970,6 +18952,14 @@
/obj/machinery/duct,
/turf/open/floor/iron/kitchen,
/area/station/service/kitchen)
+"eSq" = (
+/obj/structure/railing/corner,
+/obj/machinery/atmospherics/pipe/smart/simple/purple,
+/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
+ dir = 8
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"eSw" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/chair/stool/directional/south,
@@ -20756,6 +20746,17 @@
"fsJ" = (
/turf/closed/wall/r_wall,
/area/station/ai_monitored/turret_protected/ai_upload)
+"fsK" = (
+/obj/effect/turf_decal/trimline/red/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/red/line{
+ dir = 8
+ },
+/obj/effect/landmark/start/hangover,
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor4/aft)
"fsR" = (
/obj/item/kirbyplants/random,
/obj/machinery/light/directional/east,
@@ -22112,14 +22113,6 @@
},
/turf/open/floor/pod/dark,
/area/station/maintenance/floor3/starboard)
-"fLX" = (
-/obj/structure/railing/corner,
-/obj/machinery/atmospherics/pipe/smart/simple/purple,
-/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"fMc" = (
/obj/machinery/airalarm/directional/west,
/obj/effect/turf_decal/stripes{
@@ -22365,12 +22358,6 @@
/obj/structure/flora/bush/lavendergrass/style_random,
/turf/open/floor/grass,
/area/station/security/courtroom)
-"fPd" = (
-/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"fPf" = (
/obj/effect/turf_decal/tile/blue/half,
/turf/open/floor/iron/textured_edge,
@@ -24915,13 +24902,6 @@
/obj/structure/sign/poster/official/random/directional/south,
/turf/open/floor/iron/dark/side,
/area/station/hallway/floor2/fore)
-"gxE" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/structure/cable,
-/obj/machinery/bluespace_vendor/directional/north,
-/turf/open/floor/iron,
-/area/station/hallway/floor1/aft)
"gxH" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -25549,16 +25529,6 @@
/obj/structure/cable,
/turf/open/floor/wood,
/area/station/commons/dorms/apartment1)
-"gGr" = (
-/obj/effect/turf_decal/trimline/red/line{
- dir = 4
- },
-/obj/effect/turf_decal/trimline/red/line{
- dir = 8
- },
-/obj/effect/landmark/start/hangover,
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor4/aft)
"gGt" = (
/obj/machinery/atmospherics/pipe/heat_exchanging/simple/layer2{
dir = 4
@@ -26472,15 +26442,6 @@
/obj/effect/spawner/structure/electrified_grille,
/turf/open/floor/plating,
/area/station/maintenance/floor2/port/aft)
-"gSv" = (
-/obj/effect/turf_decal/trimline/yellow/line{
- dir = 4
- },
-/obj/effect/turf_decal/trimline/yellow/line{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor1/fore)
"gSw" = (
/obj/structure/cable,
/obj/effect/turf_decal/stripes/white/line,
@@ -27388,6 +27349,12 @@
/obj/machinery/hydroponics/constructable,
/turf/open/floor/iron,
/area/station/service/hydroponics)
+"heI" = (
+/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/visible{
+ dir = 4
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"heR" = (
/obj/structure/cable,
/obj/effect/spawner/structure/window/reinforced,
@@ -27622,11 +27589,6 @@
/obj/effect/spawner/random/medical/surgery_tool,
/turf/open/floor/pod/light,
/area/station/maintenance/department/engine/atmos)
-"hid" = (
-/turf/open/floor/iron/dark/side{
- dir = 8
- },
-/area/station/hallway/floor4/aft)
"hio" = (
/obj/machinery/atmospherics/pipe/smart/manifold/scrubbers/visible{
dir = 4
@@ -27797,15 +27759,6 @@
dir = 1
},
/area/station/hallway/floor1/aft)
-"hko" = (
-/obj/effect/turf_decal/trimline/green/line{
- dir = 4
- },
-/obj/effect/turf_decal/trimline/green/line{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor3/fore)
"hkq" = (
/turf/closed/wall/r_wall,
/area/station/engineering/atmos)
@@ -29001,6 +28954,13 @@
/obj/structure/flora/bush/style_random,
/turf/open/floor/grass,
/area/station/security/courtroom)
+"hAH" = (
+/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
+ dir = 4
+ },
+/obj/machinery/atmospherics/pipe/smart/simple/purple,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"hAI" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/cable,
@@ -29434,6 +29394,14 @@
/obj/effect/landmark/blobstart,
/turf/open/floor/pod/light,
/area/station/maintenance/floor4/starboard)
+"hGC" = (
+/obj/machinery/atmospherics/pipe/heat_exchanging/junction/layer2{
+ dir = 1
+ },
+/obj/effect/spawner/structure/window/hollow/plasma/middle,
+/obj/machinery/atmospherics/pipe/smart/simple/purple,
+/turf/open/floor/engine/vacuum,
+/area/station/science/ordnance/freezerchamber)
"hGL" = (
/obj/machinery/light/small/directional/north,
/obj/effect/decal/cleanable/dirt,
@@ -32635,18 +32603,6 @@
dir = 1
},
/area/station/hallway/secondary/exit/escape_pod)
-"ixd" = (
-/obj/machinery/door/firedoor/border_only{
- dir = 4
- },
-/obj/structure/railing{
- dir = 4
- },
-/obj/machinery/atmospherics/components/unary/portables_connector/visible{
- dir = 1
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"ixf" = (
/obj/structure/chair/sofa/bench/right{
dir = 1
@@ -35938,6 +35894,16 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/pod/light,
/area/station/maintenance/floor4/starboard/aft)
+"jqq" = (
+/obj/effect/turf_decal/trimline/green/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/green/line{
+ dir = 8
+ },
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor3/fore)
"jqy" = (
/obj/structure/lattice/catwalk,
/turf/open/openspace,
@@ -37468,6 +37434,11 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/plating,
/area/station/maintenance/floor4/starboard)
+"jJM" = (
+/obj/machinery/atmospherics/pipe/smart/manifold/purple/visible/layer2,
+/obj/machinery/atmospherics/pipe/smart/simple/purple,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"jJP" = (
/obj/effect/decal/cleanable/glass,
/turf/open/floor/engine,
@@ -39362,14 +39333,6 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/wood/parquet,
/area/station/medical/psychology)
-"kiw" = (
-/obj/machinery/atmospherics/pipe/heat_exchanging/junction/layer2{
- dir = 1
- },
-/obj/effect/spawner/structure/window/hollow/plasma/middle,
-/obj/machinery/atmospherics/pipe/smart/simple/purple,
-/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance/freezerchamber)
"kiA" = (
/obj/effect/turf_decal/tile/green/opposingcorners,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -43498,6 +43461,10 @@
/obj/effect/mapping_helpers/broken_floor,
/turf/open/floor/plating,
/area/station/service/abandoned_gambling_den)
+"liu" = (
+/obj/machinery/atmospherics/components/unary/bluespace_sender,
+/turf/open/floor/iron/dark,
+/area/station/engineering/atmos/project)
"liL" = (
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron,
@@ -45325,6 +45292,12 @@
/obj/effect/mapping_helpers/airlock/access/any/service/theatre,
/turf/open/floor/pod/dark,
/area/station/maintenance/floor3/starboard/aft)
+"lIC" = (
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark/side{
+ dir = 4
+ },
+/area/station/hallway/floor2/fore)
"lIJ" = (
/obj/structure/table/reinforced,
/obj/item/flashlight/lamp{
@@ -46100,13 +46073,6 @@
/obj/structure/flora/bush/flowers_yw/style_random,
/turf/open/floor/grass,
/area/station/science/genetics)
-"lRw" = (
-/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
- dir = 4
- },
-/obj/machinery/atmospherics/pipe/smart/simple/purple,
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"lRF" = (
/obj/effect/turf_decal/trimline/brown/filled/line{
dir = 1
@@ -47648,10 +47614,6 @@
dir = 4
},
/area/station/hallway/floor3/fore)
-"mlc" = (
-/obj/machinery/atmospherics/components/unary/bluespace_sender,
-/turf/open/floor/iron/dark,
-/area/station/engineering/atmos/project)
"mlg" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -49021,6 +48983,13 @@
},
/turf/open/floor/wood/tile,
/area/station/service/library/lounge)
+"mCU" = (
+/obj/machinery/atmospherics/pipe/heat_exchanging/manifold/layer2{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/vent_scrubber,
+/turf/open/floor/engine/vacuum,
+/area/station/science/ordnance/freezerchamber)
"mDe" = (
/obj/structure/lattice,
/turf/open/openspace,
@@ -53514,6 +53483,16 @@
},
/turf/open/floor/engine/airless,
/area/station/engineering/supermatter/waste)
+"nIN" = (
+/obj/effect/turf_decal/trimline/blue/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/purple/line{
+ dir = 8
+ },
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor2/fore)
"nIO" = (
/obj/structure/cable,
/turf/open/floor/iron/smooth,
@@ -54302,13 +54281,6 @@
},
/turf/open/floor/iron/dark,
/area/station/hallway/floor1/fore)
-"nTF" = (
-/obj/structure/chair/sofa/bench/left{
- dir = 4
- },
-/obj/machinery/bluespace_vendor/directional/west,
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor1/fore)
"nTI" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -54905,13 +54877,6 @@
dir = 1
},
/area/station/engineering/lobby)
-"obC" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"obH" = (
/obj/structure/disposalpipe/segment{
dir = 4
@@ -56703,6 +56668,13 @@
/obj/effect/landmark/start/medical_doctor,
/turf/open/floor/iron/white,
/area/station/medical/office)
+"ozM" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
+/obj/machinery/bluespace_vendor/directional/north,
+/turf/open/floor/iron,
+/area/station/hallway/floor1/aft)
"ozO" = (
/turf/closed/wall,
/area/station/security/prison)
@@ -58267,6 +58239,12 @@
/obj/machinery/light_switch/directional/east,
/turf/open/floor/iron,
/area/station/cargo/storage)
+"oUW" = (
+/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
+ dir = 8
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"oVa" = (
/obj/effect/turf_decal/trimline/blue/filled/line{
dir = 8
@@ -59716,6 +59694,12 @@
dir = 4
},
/area/station/hallway/secondary/exit/departure_lounge)
+"pqB" = (
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark/side{
+ dir = 8
+ },
+/area/station/hallway/floor3/fore)
"pqH" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
@@ -60567,6 +60551,16 @@
},
/turf/open/floor/iron,
/area/station/hallway/floor1/fore)
+"pBQ" = (
+/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
+ dir = 1
+ },
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/structure/sign/poster/official/random/directional/south,
+/turf/open/floor/iron/dark/side,
+/area/station/hallway/floor1/fore)
"pBS" = (
/obj/machinery/deepfryer,
/turf/open/floor/iron/kitchen,
@@ -62694,6 +62688,10 @@
},
/turf/open/floor/iron,
/area/station/hallway/floor1/aft)
+"qdF" = (
+/obj/machinery/bluespace_vendor/directional/west,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor2/fore)
"qdS" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/cable,
@@ -62939,6 +62937,16 @@
/obj/machinery/atmospherics/pipe/heat_exchanging/manifold,
/turf/open/space/basic,
/area/space/nearstation)
+"qgU" = (
+/obj/effect/turf_decal/trimline/yellow/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/yellow/line{
+ dir = 8
+ },
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor1/fore)
"qgV" = (
/obj/structure/railing{
dir = 1
@@ -64041,10 +64049,6 @@
/obj/structure/cable,
/turf/open/floor/carpet/royalblue,
/area/station/commons/dorms/room4)
-"qwd" = (
-/obj/machinery/bluespace_vendor/directional/north,
-/turf/open/floor/iron/dark,
-/area/station/hallway/floor3/fore)
"qwg" = (
/obj/structure/chair/comfy/brown{
dir = 1
@@ -65390,6 +65394,13 @@
/obj/item/radio/intercom/directional/north,
/turf/open/floor/iron,
/area/station/science/genetics)
+"qNI" = (
+/obj/machinery/light/floor,
+/obj/machinery/bluespace_vendor/directional/north,
+/turf/open/floor/iron/dark/side{
+ dir = 4
+ },
+/area/station/hallway/floor4/aft)
"qNK" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -68910,6 +68921,10 @@
/obj/structure/cable,
/turf/open/floor/catwalk_floor,
/area/station/maintenance/floor3/starboard/aft)
+"rKV" = (
+/obj/machinery/bluespace_vendor/directional/north,
+/turf/open/floor/engine,
+/area/station/engineering/supermatter/room)
"rKX" = (
/obj/structure/cable,
/obj/effect/spawner/structure/window/reinforced,
@@ -73225,6 +73240,16 @@
/obj/structure/cable,
/turf/open/floor/iron,
/area/station/engineering/atmos/hfr_room)
+"sTE" = (
+/obj/effect/turf_decal/trimline/red/line{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/red/line{
+ dir = 8
+ },
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor4/aft)
"sTG" = (
/obj/machinery/chem_dispenser/drinks,
/obj/structure/table/glass,
@@ -74586,14 +74611,6 @@
/obj/machinery/light/floor,
/turf/open/floor/iron/dark,
/area/station/hallway/floor2/fore)
-"tjS" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/structure/cable,
-/obj/machinery/camera/autoname/directional/south,
-/obj/machinery/bluespace_vendor/directional/south,
-/turf/open/floor/iron/dark/side,
-/area/station/hallway/floor2/aft)
"tjV" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/structure/cable,
@@ -76347,6 +76364,18 @@
},
/turf/open/floor/pod,
/area/station/maintenance/floor4/starboard/aft)
+"tHk" = (
+/obj/machinery/door/firedoor/border_only{
+ dir = 4
+ },
+/obj/structure/railing{
+ dir = 4
+ },
+/obj/machinery/atmospherics/components/unary/portables_connector/visible{
+ dir = 1
+ },
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"tHn" = (
/obj/machinery/atmospherics/components/binary/pump/layer4{
dir = 1
@@ -78197,6 +78226,21 @@
},
/turf/open/floor/catwalk_floor,
/area/station/maintenance/floor1/port)
+"uhj" = (
+/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
+/obj/structure/table/reinforced,
+/obj/structure/disposalpipe/segment{
+ dir = 4
+ },
+/obj/effect/turf_decal/trimline/dark_blue/end{
+ dir = 8
+ },
+/obj/item/storage/toolbox/emergency,
+/obj/machinery/bluespace_vendor/directional/south,
+/turf/open/floor/iron/dark,
+/area/station/commons/storage/tools)
"uhl" = (
/obj/effect/decal/cleanable/cobweb/cobweb2,
/obj/effect/spawner/random/structure/crate,
@@ -79993,6 +80037,13 @@
/obj/machinery/vending/coffee,
/turf/open/floor/iron/dark,
/area/station/science/breakroom)
+"uGS" = (
+/obj/structure/chair/sofa/bench/left{
+ dir = 4
+ },
+/obj/machinery/bluespace_vendor/directional/west,
+/turf/open/floor/iron/dark,
+/area/station/hallway/floor1/fore)
"uHa" = (
/obj/effect/turf_decal/tile/red,
/turf/open/floor/iron/dark/side,
@@ -81868,10 +81919,6 @@
/obj/machinery/duct,
/turf/open/floor/pod/dark,
/area/station/maintenance/floor2/port)
-"vdT" = (
-/obj/machinery/bluespace_vendor/directional/north,
-/turf/open/floor/engine,
-/area/station/engineering/supermatter/room)
"vdU" = (
/obj/effect/decal/cleanable/dirt,
/obj/effect/landmark/generic_maintenance_landmark,
@@ -88719,12 +88766,6 @@
dir = 5
},
/area/station/security/prison)
-"wLQ" = (
-/obj/machinery/atmospherics/pipe/layer_manifold/scrubbers/visible{
- dir = 4
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"wLV" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 4
@@ -89526,12 +89567,24 @@
/obj/item/storage/briefcase/secure,
/turf/open/floor/iron/dark,
/area/station/command/teleporter)
+"wWY" = (
+/obj/effect/spawner/structure/window/hollow/plasma/middle{
+ dir = 4
+ },
+/turf/open/floor/engine/vacuum,
+/area/station/science/ordnance/freezerchamber)
"wXc" = (
/obj/structure/disposalpipe/segment{
dir = 10
},
/turf/open/floor/plating,
/area/station/maintenance/floor2/starboard/fore)
+"wXg" = (
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark/side{
+ dir = 8
+ },
+/area/station/hallway/floor4/aft)
"wXi" = (
/obj/structure/cable/multilayer/multiz,
/turf/open/floor/plating,
@@ -90172,15 +90225,6 @@
icon_state = "textured_dark"
},
/area/station/medical/office)
-"xgo" = (
-/obj/machinery/door/firedoor/border_only,
-/obj/structure/railing,
-/obj/effect/turf_decal/box/red,
-/obj/machinery/atmospherics/components/unary/portables_connector/visible/layer4{
- dir = 8
- },
-/turf/open/floor/iron/dark,
-/area/station/science/ordnance/testlab)
"xgC" = (
/obj/structure/railing/corner{
dir = 8
@@ -93022,11 +93066,6 @@
/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/hallway/secondary/service)
-"xSd" = (
-/obj/structure/transport/linear/public,
-/obj/machinery/light/directional/south,
-/turf/open/floor/plating/elevatorshaft,
-/area/station/hallway/floor1/fore)
"xSi" = (
/obj/effect/turf_decal/tile/dark/half/contrasted,
/obj/effect/turf_decal/tile/dark/half/contrasted,
@@ -93165,6 +93204,12 @@
},
/turf/open/space/openspace,
/area/space)
+"xUB" = (
+/obj/machinery/light/floor,
+/turf/open/floor/iron/dark/side{
+ dir = 4
+ },
+/area/station/hallway/floor3/fore)
"xUI" = (
/obj/structure/cable,
/obj/structure/chair/sofa/bench/left,
@@ -112550,7 +112595,7 @@ aYd
nBn
rUH
rUH
-nTF
+uGS
rNO
tSK
hJy
@@ -121797,7 +121842,7 @@ xHA
xHA
uKC
gqU
-kRg
+pBQ
wdL
wdL
wdL
@@ -122054,7 +122099,7 @@ pye
xHA
bzw
gqU
-gjy
+imJ
cQm
nCi
svW
@@ -124368,12 +124413,12 @@ qIz
jYY
ptd
cbT
-gSv
+qgU
okN
-gSv
+qgU
mXx
nRe
-xSd
+mXx
kyR
eVk
twx
@@ -136699,7 +136744,7 @@ bJU
pYs
uyu
kbu
-gxE
+ozM
eeQ
mdR
gpf
@@ -141321,7 +141366,7 @@ qEw
qEw
qEw
sAH
-vdT
+rKV
kfo
iZP
kcB
@@ -143100,7 +143145,7 @@ owI
owI
css
lwc
-mlc
+liu
vEN
tGq
vmr
@@ -178074,7 +178119,7 @@ kEI
wwu
sbI
jtJ
-bgq
+qdF
hat
qfv
lXq
@@ -189387,7 +189432,7 @@ dpL
dpL
dpL
fNT
-skU
+alL
tjP
jVt
fNT
@@ -189904,9 +189949,9 @@ uPQ
mge
loK
umC
-bBT
+nIN
gYX
-bBT
+nIN
feX
feX
feX
@@ -190415,7 +190460,7 @@ qun
qun
qun
fNT
-veG
+lIC
uKW
gEa
fNT
@@ -203783,7 +203828,7 @@ wzS
nyE
aOp
oqv
-tjS
+cMz
igE
aWR
aZn
@@ -243098,7 +243143,7 @@ nVq
nVq
cyX
wRJ
-qwd
+eOC
mUs
oJo
oJo
@@ -254923,7 +254968,7 @@ liQ
liQ
liQ
eDe
-bks
+pqB
bdR
cKS
eDe
@@ -255440,9 +255485,9 @@ cXK
kZH
uNx
hkV
-hko
+jqq
viX
-hko
+jqq
oZx
oZx
oZx
@@ -255951,7 +255996,7 @@ qrd
qrd
qrd
eDe
-drk
+xUB
bdR
mZI
eDe
@@ -269059,7 +269104,7 @@ faS
fXB
quO
cgm
-ehZ
+uhj
frW
frW
chn
@@ -315042,7 +315087,7 @@ xpL
qRI
mKO
rDL
-wLQ
+heI
jha
nPE
xVV
@@ -315299,7 +315344,7 @@ wFa
eIs
wFa
tYV
-fPd
+oUW
xwL
nPE
nPE
@@ -315556,7 +315601,7 @@ mSG
aSX
aSX
pqH
-obC
+bJA
mKu
hHi
fMc
@@ -315813,7 +315858,7 @@ dWz
lYx
unQ
wMU
-fPd
+oUW
rDL
jjj
dIJ
@@ -316066,12 +316111,12 @@ ucA
vyc
vPP
rrs
-bYl
-kiw
-exv
-lRw
-fLX
-ixd
+mCU
+hGC
+jJM
+hAH
+eSq
+tHk
bDn
gwe
eoI
@@ -316323,11 +316368,11 @@ ucA
lYx
oRh
lYx
-cBP
+wWY
lYx
ngD
wMU
-xgo
+aqm
kFy
xTG
xxA
@@ -320459,7 +320504,7 @@ liQ
liQ
liQ
nWW
-hid
+wXg
nQX
bgI
eOP
@@ -320976,9 +321021,9 @@ jgd
kpl
tFp
gQh
-gGr
+fsK
weB
-gQh
+sTE
vRO
vRO
vRO
@@ -321487,7 +321532,7 @@ txa
txa
txa
nWW
-bQo
+qNI
nQX
kQk
eOP
diff --git a/code/__DEFINES/atom_hud.dm b/code/__DEFINES/atom_hud.dm
index df837c86d9a31..b175acd65a615 100644
--- a/code/__DEFINES/atom_hud.dm
+++ b/code/__DEFINES/atom_hud.dm
@@ -112,6 +112,7 @@
#define SECHUD_SCIENTIST "hudscientist"
#define SECHUD_SHAFT_MINER "hudshaftminer"
#define SECHUD_STATION_ENGINEER "hudstationengineer"
+#define SECHUD_VETERAN_ADVISOR "hudveteranadvisor"
#define SECHUD_VIROLOGIST "hudvirologist"
#define SECHUD_WARDEN "hudwarden"
diff --git a/code/__DEFINES/jobs.dm b/code/__DEFINES/jobs.dm
index 1d69d48e9d59f..fca771489558f 100644
--- a/code/__DEFINES/jobs.dm
+++ b/code/__DEFINES/jobs.dm
@@ -49,6 +49,7 @@
#define JOB_CHIEF_ENGINEER "Chief Engineer"
#define JOB_CHIEF_MEDICAL_OFFICER "Chief Medical Officer"
#define JOB_BRIDGE_ASSISTANT "Bridge Assistant"
+#define JOB_VETERAN_ADVISOR "Veteran Security Advisor"
//Silicon
#define JOB_AI "AI"
#define JOB_CYBORG "Cyborg"
@@ -156,10 +157,11 @@
#define JOB_DISPLAY_ORDER_ROBOTICIST 33
#define JOB_DISPLAY_ORDER_GENETICIST 34
#define JOB_DISPLAY_ORDER_HEAD_OF_SECURITY 35
-#define JOB_DISPLAY_ORDER_WARDEN 36
-#define JOB_DISPLAY_ORDER_DETECTIVE 37
-#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 38
-#define JOB_DISPLAY_ORDER_PRISONER 39
+#define JOB_DISPLAY_ORDER_VETERAN_ADVISOR 36
+#define JOB_DISPLAY_ORDER_WARDEN 37
+#define JOB_DISPLAY_ORDER_DETECTIVE 38
+#define JOB_DISPLAY_ORDER_SECURITY_OFFICER 39
+#define JOB_DISPLAY_ORDER_PRISONER 40
#define DEPARTMENT_UNASSIGNED "No Department"
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index fdfec5e8ca086..a4fb6d40be73e 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,6 +1,6 @@
// tgstation-server DMAPI
-#define TGS_DMAPI_VERSION "7.0.2"
+#define TGS_DMAPI_VERSION "7.1.1"
// All functions and datums outside this document are subject to change with any version and should not be relied on.
@@ -50,6 +50,13 @@
#endif
+#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
+#endif
+#define TGS_FILE2TEXT_NATIVE file2text
+#endif
+
// EVENT CODES
/// Before a reboot mode change, extras parameters are the current and new reboot mode enums.
@@ -490,6 +497,16 @@
/world/proc/TgsChatChannelInfo()
return
+/**
+ * Trigger an event in TGS. Requires TGS version >= 6.3.0. Returns [TRUE] if the event was triggered successfully, [FALSE] otherwise. This function may sleep!
+ *
+ * event_name - The name of the event to trigger
+ * parameters - Optional list of string parameters to pass as arguments to the event script. The first parameter passed to a script will always be the running game's directory followed by these parameters.
+ * wait_for_completion - If set, this function will not return until the event has run to completion.
+ */
+/world/proc/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
+ return
+
/*
The MIT License
diff --git a/code/controllers/subsystem/materials.dm b/code/controllers/subsystem/materials.dm
index 4ae9272e97010..25efd8695dca0 100644
--- a/code/controllers/subsystem/materials.dm
+++ b/code/controllers/subsystem/materials.dm
@@ -33,6 +33,9 @@ SUBSYSTEM_DEF(materials)
new /datum/stack_recipe("Carving block", /obj/structure/carving_block, 5, time = 3 SECONDS, one_per_turf = TRUE, on_solid_ground = TRUE, applies_mats = TRUE, category = CAT_STRUCTURE),
)
+ ///A list of dimensional themes used by the dimensional anomaly and other things, most of which require materials to function.
+ var/list/datum/dimension_theme/dimensional_themes
+
///Ran on initialize, populated the materials and materials_by_category dictionaries with their appropiate vars (See these variables for more info)
/datum/controller/subsystem/materials/proc/InitializeMaterials()
materials = list()
@@ -47,6 +50,8 @@ SUBSYSTEM_DEF(materials)
continue // Do not initialize at mapload
InitializeMaterial(list(mat_type))
+ dimensional_themes = init_subtypes_w_path_keys(/datum/dimension_theme)
+
/** Creates and caches a material datum.
*
* Arugments:
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index c4c3b85b4c939..410db36988dd8 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -302,6 +302,7 @@ SUBSYSTEM_DEF(vote)
"question" = current_vote.override_question,
"timeRemaining" = current_vote.time_remaining,
"countMethod" = current_vote.count_method,
+ "displayStatistics" = current_vote.display_statistics,
"choices" = choices,
"vote" = vote_data,
)
diff --git a/code/datums/ai_laws/laws_neutral.dm b/code/datums/ai_laws/laws_neutral.dm
index 2fe19dafbc517..7adef14d95b89 100644
--- a/code/datums/ai_laws/laws_neutral.dm
+++ b/code/datums/ai_laws/laws_neutral.dm
@@ -60,6 +60,7 @@
"You are a universally renowned artist.",
"The station is your canvas.",
"Make something beautiful out of your canvas. It will be admired as an artistic wonder of this sector.",
+ "Art requires appreciation. Cultivate an audience aboard the station to ensure as many as possible see your works.",
)
/datum/ai_laws/tyrant
diff --git a/code/datums/brain_damage/special.dm b/code/datums/brain_damage/special.dm
index e24ecd99c6177..31f316221301e 100644
--- a/code/datums/brain_damage/special.dm
+++ b/code/datums/brain_damage/special.dm
@@ -426,3 +426,49 @@
to_chat(victim, "[span_name("[name]")] exclaims, \"[span_robot("[beepskys_cry]")]")
if(victim.client?.prefs.read_preference(/datum/preference/toggle/enable_runechat))
victim.create_chat_message(src, raw_message = beepskys_cry, spans = list("robotic"))
+
+// Used by Veteran Security Advisor job.
+/datum/brain_trauma/special/ptsd
+ name = "Combat PTSD"
+ desc = "The patient is experiencing PTSD stemming from past combat exposure, resulting in a lack of emotions. Additionally, they are experiencing mild hallucinations."
+ scan_desc = "PTSD"
+ gain_text = span_warning("You're thrust back into the chaos of past! Explosions! Gunfire! Emotions, gone AWOL!")
+ lose_text = span_notice("You feel flashbacks of past fade, as your emotions return and mind clear.")
+ resilience = TRAUMA_RESILIENCE_ABSOLUTE
+ can_gain = TRUE
+ random_gain = FALSE
+ /// Our cooldown declare for causing hallucinations
+ COOLDOWN_DECLARE(ptsd_hallucinations)
+ var/list/ptsd_hallucinations_list = list(
+ /datum/hallucination/fake_sound/normal/boom,
+ /datum/hallucination/fake_sound/normal/distant_boom,
+ /datum/hallucination/stray_bullet,
+ /datum/hallucination/battle/gun/disabler,
+ /datum/hallucination/battle/gun/laser,
+ /datum/hallucination/battle/bomb,
+ /datum/hallucination/battle/e_sword,
+ /datum/hallucination/battle/harm_baton,
+ /datum/hallucination/battle/stun_prod,
+ )
+
+/datum/brain_trauma/special/ptsd/on_life(seconds_per_tick, times_fired)
+ if(owner.stat != CONSCIOUS)
+ return
+
+ if(!COOLDOWN_FINISHED(src, ptsd_hallucinations))
+ return
+
+ owner.cause_hallucination(pick(ptsd_hallucinations_list), "Caused by The Combat PTSD brain trauma")
+ COOLDOWN_START(src, ptsd_hallucinations, rand(10 SECONDS, 10 MINUTES))
+
+/datum/brain_trauma/special/ptsd/on_gain()
+ owner.add_mood_event("combat_ptsd", /datum/mood_event/desentized)
+ owner.mob_mood?.mood_modifier -= 1 //Basically nothing can change your mood
+ owner.mob_mood?.sanity_level = SANITY_DISTURBED //Makes sanity on a unstable level unless cured
+ ..()
+
+/datum/brain_trauma/special/ptsd/on_lose()
+ owner.clear_mood_event("combat_ptsd")
+ owner.mob_mood?.mood_modifier += 1
+ owner.mob_mood?.sanity_level = SANITY_GREAT
+ return ..()
diff --git a/code/datums/elements/window_smash.dm b/code/datums/elements/window_smash.dm
index fbe2674b86c72..32896d096bf6e 100644
--- a/code/datums/elements/window_smash.dm
+++ b/code/datums/elements/window_smash.dm
@@ -24,6 +24,9 @@
for(var/obj/structure/window/window in target_turf)
window.smash_and_injure(flying_mob, old_loc, direction)
+ for(var/obj/structure/grille/grille in target_turf)
+ grille.smash_and_injure(flying_mob, old_loc, direction)
+
/datum/element/window_smashing/Detach(datum/source)
UnregisterSignal(source, COMSIG_MOVABLE_MOVED)
passwindow_off(source, TRAM_PASSENGER_TRAIT)
diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm
index ea46cc91319fa..46f691564bb4b 100644
--- a/code/datums/id_trim/jobs.dm
+++ b/code/datums/id_trim/jobs.dm
@@ -1183,6 +1183,36 @@
)
job = /datum/job/station_engineer
+/datum/id_trim/job/veteran_advisor
+ assignment = "Veteran Security Advisor"
+ trim_state = "trim_veteranadvisor"
+ department_color = COLOR_SECURITY_RED
+ subdepartment_color = COLOR_COMMAND_BLUE
+ sechud_icon_state = SECHUD_VETERAN_ADVISOR
+ minimal_access = list(
+ ACCESS_COMMAND,
+ ACCESS_BRIG,
+ ACCESS_BRIG_ENTRANCE,
+ ACCESS_COURT,
+ ACCESS_MECH_SECURITY,
+ ACCESS_MINERAL_STOREROOM,
+ ACCESS_SECURITY,
+ ACCESS_WEAPONS,
+ )
+ extra_access = list()
+ template_access = list()
+ job = /datum/job/veteran_advisor
+
+/datum/id_trim/job/veteran_advisor/refresh_trim_access()
+ . = ..()
+
+ if(!.)
+ return
+
+ // Config check for if sec has maint access.
+ if(CONFIG_GET(flag/security_has_maint_access))
+ access |= list(ACCESS_MAINT_TUNNELS)
+
/datum/id_trim/job/virologist
assignment = "Virologist"
trim_state = "trim_virologist"
diff --git a/code/datums/mood_events/generic_negative_events.dm b/code/datums/mood_events/generic_negative_events.dm
index 32b9772dc0709..0cfb48f7a9823 100644
--- a/code/datums/mood_events/generic_negative_events.dm
+++ b/code/datums/mood_events/generic_negative_events.dm
@@ -483,3 +483,9 @@
/datum/mood_event/all_nighter
description = "I didn't sleep at all last night. I'm exhausted."
mood_change = -5
+
+//Used by the Veteran Advisor trait job
+/datum/mood_event/desentized
+ description = "Nothing will ever rival with what I seen in the past..."
+ mood_change = -3
+ special_screen_obj = "mood_desentized"
diff --git a/code/datums/records/manifest.dm b/code/datums/records/manifest.dm
index 7d3b7978af904..789b8787fe6e1 100644
--- a/code/datums/records/manifest.dm
+++ b/code/datums/records/manifest.dm
@@ -38,6 +38,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
misc_list[++misc_list.len] = list(
"name" = name,
"rank" = rank,
+ "trim" = trim,
)
continue
for(var/department_type as anything in job.departments_list)
@@ -51,6 +52,7 @@ GLOBAL_DATUM_INIT(manifest, /datum/manifest, new)
var/list/entry = list(
"name" = name,
"rank" = rank,
+ "trim" = trim,
)
var/list/department_list = manifest_out[department.department_name]
if(istype(job, department.department_head))
diff --git a/code/datums/station_traits/job_traits.dm b/code/datums/station_traits/job_traits.dm
index 8dea2f96bbf09..041f846424094 100644
--- a/code/datums/station_traits/job_traits.dm
+++ b/code/datums/station_traits/job_traits.dm
@@ -164,6 +164,19 @@
new /obj/item/reagent_containers/cup/coffeepot(picked_turf)
new /obj/item/storage/box/coffeepack(picked_turf)
+/datum/station_trait/job/veteran_advisor
+ name = "Veteran Advisor"
+ button_desc = "Sign up to become a DISABLED but hard boiled Veteran Advisor of Nanotrasen Security Force. Advise HoS and Captain, train Officers, all while fighting your PTSD."
+ weight = 2
+ report_message = "Veteran Security Advisor has been assigned to your station to help with Security matters."
+ show_in_report = TRUE
+ can_roll_antag = CAN_ROLL_PROTECTED
+ job_to_add = /datum/job/veteran_advisor
+
+/datum/station_trait/job/veteran_advisor/on_lobby_button_update_overlays(atom/movable/screen/lobby/button/sign_up/lobby_button, list/overlays)
+ . = ..()
+ overlays += "veteran_advisor"
+
#undef CAN_ROLL_ALWAYS
#undef CAN_ROLL_PROTECTED
#undef CAN_ROLL_NEVER
diff --git a/code/datums/votes/_vote_datum.dm b/code/datums/votes/_vote_datum.dm
index a882511b51130..3f821a7129ada 100644
--- a/code/datums/votes/_vote_datum.dm
+++ b/code/datums/votes/_vote_datum.dm
@@ -32,6 +32,8 @@
var/count_method = VOTE_COUNT_METHOD_SINGLE
/// The method for selecting a winner.
var/winner_method = VOTE_WINNER_METHOD_SIMPLE
+ /// Should we show details about the number of votes submitted for each option?
+ var/display_statistics = TRUE
/**
* Used to determine if this vote is a possible
@@ -193,21 +195,22 @@
if(total_votes <= 0)
return span_bold("Vote Result: Inconclusive - No Votes!")
- returned_text += "\nResults:"
- for(var/option in choices)
- returned_text += "\n"
- var/votes = choices[option]
- var/percentage_text = ""
- if(votes > 0)
- var/actual_percentage = round((votes / total_votes) * 100, 0.1)
- var/text = "[actual_percentage]"
- var/spaces_needed = 5 - length(text)
- for(var/_ in 1 to spaces_needed)
- returned_text += " "
- percentage_text += "[text]%"
- else
- percentage_text = " 0%"
- returned_text += "[percentage_text] | [span_bold(option)]: [choices[option]]"
+ if (display_statistics)
+ returned_text += "\nResults:"
+ for(var/option in choices)
+ returned_text += "\n"
+ var/votes = choices[option]
+ var/percentage_text = ""
+ if(votes > 0)
+ var/actual_percentage = round((votes / total_votes) * 100, 0.1)
+ var/text = "[actual_percentage]"
+ var/spaces_needed = 5 - length(text)
+ for(var/_ in 1 to spaces_needed)
+ returned_text += " "
+ percentage_text += "[text]%"
+ else
+ percentage_text = " 0%"
+ returned_text += "[percentage_text] | [span_bold(option)]: [choices[option]]"
if(!real_winner) // vote has no winner or cannot be won, but still had votes
return returned_text
diff --git a/code/datums/votes/custom_vote.dm b/code/datums/votes/custom_vote.dm
index 5960e7dff0ed9..d67eb0281c6c6 100644
--- a/code/datums/votes/custom_vote.dm
+++ b/code/datums/votes/custom_vote.dm
@@ -47,6 +47,17 @@
to_chat(vote_creator, span_boldwarning("Unknown winner method. Contact a coder."))
return FALSE
+ var/display_stats = tgui_alert(
+ vote_creator,
+ "Should voting statistics be public?",
+ "Show voting stats?",
+ list("Yes", "No"),
+ )
+
+ if(display_stats == null)
+ return FALSE
+ display_statistics = display_stats == "Yes"
+
override_question = tgui_input_text(vote_creator, "What is the vote for?", "Custom Vote")
if(!override_question)
return FALSE
diff --git a/code/datums/votes/map_vote.dm b/code/datums/votes/map_vote.dm
index be156866f667f..a07d87846f050 100644
--- a/code/datums/votes/map_vote.dm
+++ b/code/datums/votes/map_vote.dm
@@ -3,6 +3,7 @@
message = "Vote for next round's map!"
count_method = VOTE_COUNT_METHOD_SINGLE
winner_method = VOTE_WINNER_METHOD_WEIGHTED_RANDOM
+ display_statistics = FALSE
/datum/vote/map_vote/New()
. = ..()
diff --git a/code/game/machinery/computer/arena.dm b/code/game/machinery/computer/arena.dm
deleted file mode 100644
index 97d89c2414076..0000000000000
--- a/code/game/machinery/computer/arena.dm
+++ /dev/null
@@ -1,411 +0,0 @@
-#define ARENA_RED_TEAM "red"
-#define ARENA_GREEN_TEAM "green"
-#define ARENA_DEFAULT_ID "arena_default"
-#define ARENA_CORNER_A "cornerA"
-#define ARENA_CORNER_B "cornerB"
-
-/// Arena related landmarks
-/obj/effect/landmark/arena
- name = "arena landmark"
- var/landmark_tag
- var/arena_id = ARENA_DEFAULT_ID
-
-/obj/effect/landmark/arena/start
- name = "arena corner A"
- landmark_tag = ARENA_CORNER_A
-
-/obj/effect/landmark/arena/end
- name = "arena corner B"
- landmark_tag = ARENA_CORNER_B
-
-/// Controller for admin event arenas
-/obj/machinery/computer/arena
- name = "arena controller"
-
- interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE|INTERACT_MACHINE_REQUIRES_LITERACY
-
- /// Arena ID
- var/arena_id = ARENA_DEFAULT_ID
- /// Enables/disables spawning
- var/ready_to_spawn = FALSE
- /// Assoc list of map templates indexed by user friendly names
- var/static/list/arena_templates = list()
- /// Were the config directory arenas loaded
- var/static/default_arenas_loaded = FALSE
- /// Name of currently loaded template
- var/current_arena_template = "None"
- // What turf arena clears to
- var/empty_turf_type = /turf/open/indestructible
- // List of team ids
- var/list/teams = list(ARENA_RED_TEAM,ARENA_GREEN_TEAM)
- /// List of hud instances indedxed by team id
- var/static/list/team_huds = list()
- /// List of hud colors indexed by team id
- var/static/list/team_colors = list(ARENA_RED_TEAM = "red", ARENA_GREEN_TEAM = "green")
- // Team hud index in GLOB.huds indexed by team id
- var/static/list/team_hud_index = list()
-
- /// List of ckeys indexed by team id
- var/list/team_keys = list()
- /// List of outfit datums/types indexed by team id, can be empty
- var/list/outfits = list()
- /// Default team outfit if `outfits[team]` is empty
- var/default_outfit = /datum/outfit/job/assistant
-
- /// Is the arena template loading in
- var/loading = FALSE
-
- //How long between admin pressing start and doors opening
- var/start_delay = 30 SECONDS
- //Value for the countdown
- var/start_time
- var/list/countdowns = list() //List of countdown effects ticking down to start
-
- //Sound played when the fight starts.
- var/start_sound = 'sound/items/airhorn2.ogg'
- var/start_sound_volume = 50
-
-/obj/machinery/computer/arena/Initialize(mapload, obj/item/circuitboard/C)
- . = ..()
- LoadDefaultArenas()
-
-/**
- * Loads the arenas from config directory.
- * THESE ARE FULLY CACHED FOR QUICK SWITCHING SO KEEP TRACK OF THE AMOUNT
- */
-/obj/machinery/computer/arena/proc/LoadDefaultArenas()
- if(default_arenas_loaded)
- return
- var/arena_dir = "[global.config.directory]/arenas/"
- var/list/default_arenas = flist(arena_dir)
- for(var/arena_file in default_arenas)
- var/simple_name = replacetext(replacetext(arena_file,arena_dir,""),".dmm","")
- INVOKE_ASYNC(src, PROC_REF(add_new_arena_template), null, arena_dir + arena_file, simple_name)
-
-/obj/machinery/computer/arena/proc/get_landmark_turf(landmark_tag)
- for(var/obj/effect/landmark/arena/L in GLOB.landmarks_list)
- if(L.arena_id == arena_id && L.landmark_tag == landmark_tag && isturf(L.loc))
- return L.loc
-
-/obj/machinery/computer/arena/proc/get_load_point()
- var/turf/A = get_landmark_turf(ARENA_CORNER_A)
- var/turf/B = get_landmark_turf(ARENA_CORNER_B)
- return locate(min(A.x,B.x),min(A.y,B.y),A.z)
-
-/obj/machinery/computer/arena/proc/get_arena_turfs()
- var/lp = get_load_point()
- var/turf/A = get_landmark_turf(ARENA_CORNER_A)
- var/turf/B = get_landmark_turf(ARENA_CORNER_B)
- var/turf/hp = locate(max(A.x,B.x),max(A.y,B.y),A.z)
- return block(lp,hp)
-
-/obj/machinery/computer/arena/proc/clear_arena()
- for(var/turf/T in get_arena_turfs())
- T.empty(turf_type = /turf/open/indestructible)
- current_arena_template = "None"
-
-/obj/machinery/computer/arena/proc/load_arena(arena_template,mob/user)
- if(loading)
- return
- var/datum/map_template/M = arena_templates[arena_template]
- if(!M)
- to_chat(user,span_warning("No such arena"))
- return
- clear_arena() //Clear current arena
- var/turf/A = get_landmark_turf(ARENA_CORNER_A)
- var/turf/B = get_landmark_turf(ARENA_CORNER_B)
- var/wh = abs(A.x - B.x) + 1
- var/hz = abs(A.y - B.y) + 1
- if(M.width > wh || M.height > hz)
- to_chat(user,span_warning("Arena template is too big for the current arena!"))
- return
- loading = TRUE
- var/bd = M.load(get_load_point())
- if(bd)
- current_arena_template = arena_template
- loading = FALSE
-
- message_admins("[key_name_admin(user)] loaded [arena_template] event arena for [arena_id] arena.")
- log_admin("[key_name(user)] loaded [arena_template] event arena for [arena_id] arena.")
-
-
-
-/obj/machinery/computer/arena/proc/add_new_arena_template(user,fname,friendly_name)
- if(!fname)
- fname = input(user, "Upload dmm file to use as arena template","Upload Map Template") as null|file
- if(!fname)
- return
- if(!friendly_name)
- friendly_name = "[fname]" //Could ask the user for friendly name here
-
- var/datum/map_template/T = new(fname,friendly_name,TRUE)
- if(!T.cached_map || T.cached_map.check_for_errors())
- to_chat(user,"Map failed to parse check for errors.")
- return
-
- arena_templates[T.name] = T
- message_admins("[key_name_admin(user)] uploaded new event arena: [friendly_name].")
- log_admin("[key_name(user)] uploaded new event arena: [friendly_name].")
-
-/obj/machinery/computer/arena/proc/load_team(user,team)
- var/rawteam = tgui_input_text(user, "Enter team member list (ckeys separated by comma)", "Team List", multiline = TRUE)
- if(isnull(rawteam))
- return
- for(var/i in splittext(rawteam, ","))
- var/key = ckey(i)
- if(!i)
- continue
- add_team_member(user,team,key)
-
-/obj/machinery/computer/arena/proc/add_team_member(mob/user,team,key)
- if(!key)
- var/list/keys = list()
- for(var/mob/M in GLOB.player_list)
- keys += M.client
- var/client/selection = tgui_input_list(user, "Select a player", "Team member", sort_key(keys))
- //Could be freeform if you want to add disconnected i guess
- if(isnull(selection))
- return
- key = selection.ckey
- if(!team_keys[team])
- team_keys[team] = list(key)
- else
- team_keys[team] |= key
- to_chat(user,"[key] added to [team] team.")
-
-/obj/machinery/computer/arena/proc/remove_member(mob/user,ckey,team)
- team_keys[team] -= ckey
- to_chat(user,"[ckey] removed from [team] team.")
-
-/obj/machinery/computer/arena/proc/spawn_member(obj/machinery/arena_spawn/spawnpoint,ckey,team)
- var/mob/oldbody = get_mob_by_key(ckey)
- if(!isobserver(oldbody))
- return
- var/mob/living/carbon/human/M = new/mob/living/carbon/human(get_turf(spawnpoint))
- oldbody.client.prefs.safe_transfer_prefs_to(M, is_antag = TRUE)
- M.set_species(/datum/species/human) // Could use setting per team
- M.equipOutfit(outfits[team] ? outfits[team] : default_outfit)
- M.faction += team //In case anyone wants to add team based stuff to arena special effects
- M.key = ckey
-
-/obj/machinery/computer/arena/proc/change_outfit(mob/user,team)
- outfits[team] = user.client.robust_dress_shop()
-
-/obj/machinery/computer/arena/proc/toggle_spawn(mob/user)
- ready_to_spawn = !ready_to_spawn
- to_chat(user,"You [ready_to_spawn ? "enable" : "disable"] the spawners.")
- log_admin("[key_name(user)] toggled event arena spawning for [arena_id] arena.")
- // Could use update_appearance on spawnpoints here to show they're on
- if(ready_to_spawn)
- for(var/mob/M in all_contestants())
- to_chat(M,span_userdanger("Arena you're signed up for is ready!"))
-
-/obj/machinery/computer/arena/proc/all_contestants()
- . = list()
- for(var/team in team_keys)
- for(var/key in team_keys[team])
- var/mob/M = get_mob_by_key(key)
- if(M)
- . += M
-
-/obj/machinery/computer/arena/proc/reset_arena()
- clear_arena()
- set_doors(closed = TRUE)
-
-/obj/machinery/computer/arena/proc/get_spawn(team)
- for(var/obj/machinery/arena_spawn/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/arena_spawn))
- if(A.arena_id == arena_id && A.team == team)
- return A
-
-/obj/machinery/computer/arena/proc/start_match(mob/user)
- //TODO: Check if everyone is spawned in, if not ask for confirmation.
- var/timetext = DisplayTimeText(start_delay)
- to_chat(user,span_notice("The match will start in [timetext]."))
- for(var/mob/M in all_contestants())
- to_chat(M,span_userdanger("The gates will open in [timetext]!"))
- start_time = world.time + start_delay
- addtimer(CALLBACK(src, PROC_REF(begin)),start_delay)
- for(var/team in teams)
- var/obj/machinery/arena_spawn/team_spawn = get_spawn(team)
- var/obj/effect/countdown/arena/A = new(team_spawn)
- A.start()
- countdowns += A
-
-/obj/machinery/computer/arena/proc/begin()
- ready_to_spawn = FALSE
- set_doors(closed = FALSE)
- if(start_sound)
- for(var/team in teams)
- var/obj/machinery/arena_spawn/A = get_spawn(team)
- playsound(A,start_sound, start_sound_volume)
- for(var/mob/M in all_contestants())
- to_chat(M,span_userdanger("START!"))
- //Clean up the countdowns
- QDEL_LIST(countdowns)
- start_time = null
- updateUsrDialog()
-
-
-/obj/machinery/computer/arena/proc/set_doors(closed = FALSE)
- for(var/obj/machinery/door/poddoor/D as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/door/poddoor))
- if(D.id != arena_id)
- continue
- if(closed)
- INVOKE_ASYNC(D, TYPE_PROC_REF(/obj/machinery/door/poddoor, close))
- else
- INVOKE_ASYNC(D, TYPE_PROC_REF(/obj/machinery/door/poddoor, open))
-
-/obj/machinery/computer/arena/Topic(href, href_list)
- if(..())
- return
- var/mob/user = usr
-
- if(!user.client.holder) // Should it require specific perm ?
- return
-
- if(href_list["upload"])
- add_new_arena_template(user)
- if(href_list["change_arena"])
- load_arena(href_list["change_arena"],user)
- if(href_list["toggle_spawn"])
- toggle_spawn(user)
- if(href_list["start"])
- start_match(user)
- if(href_list["follow"])
- var/mob/observed_team_member = locate(href_list["follow"]) in GLOB.mob_list
- if(observed_team_member)
- user.client?.admin_follow(observed_team_member)
- if(href_list["team_action"])
- var/team = href_list["team"]
- switch(href_list["team_action"])
- if("addmember")
- add_team_member(user,team)
- if("loadteam")
- load_team(user,team)
- if("outfit")
- change_outfit(user,team)
- if(href_list["special"])
- switch(href_list["special"])
- if("reset")
- reset_arena()
- //Just example in case you want to add more
- if("randomarena")
- load_random_arena(user)
- if("spawntrophy")
- trophy_for_last_man_standing(user)
- if(href_list["member_action"])
- var/ckey = href_list["ckey"]
- var/team = href_list["team"]
- switch(href_list["member_action"])
- if("remove")
- remove_member(user,ckey,team)
- updateUsrDialog()
-
-// Special functions
-
-/obj/machinery/computer/arena/proc/load_random_arena(mob/user)
- if(!length(arena_templates))
- to_chat(user,span_warning("No arenas present"))
- return
- var/picked = pick(arena_templates)
- load_arena(picked,user)
-
-/obj/machinery/computer/arena/proc/trophy_for_last_man_standing()
- var/arena_turfs = get_arena_turfs()
- for(var/mob/living/L in GLOB.mob_living_list)
- if(L.stat != DEAD && (get_turf(L) in arena_turfs))
- var/obj/item/reagent_containers/cup/glass/trophy/gold_cup/G = new(get_turf(L))
- G.name = "[L.real_name]'s Trophy"
-
-/obj/machinery/computer/arena/ui_interact(mob/user)
- . = ..()
- var/list/dat = list()
- dat += "
Spawning is currently [ready_to_spawn ? "
enabled " : "
disabled "]
Toggle "
- dat += ""
- for(var/team in teams)
- dat += "[capitalize(team)] team: "
- dat += ""
- for(var/ckey in team_keys[team])
- var/player_status = "Not Present"
- var/mob/M = get_mob_by_key(ckey)
- if(M)
- //Should define waiting room upper/lower corner and check if they're there instead of generic live/dead check
- if(isobserver(M))
- player_status = "Ghosted"
- else
- player_status = M.stat == DEAD ? "Dead" : "Alive"
- dat += "[ckey] - [player_status] - "
- dat += "FLW "
- dat += "Remove "
- //Add more per player features here
- dat += " "
- dat += " "
- dat += " Team Outfit : [outfits[team] ? outfits[team] : default_outfit]
"
- dat += "Load team "
- dat += "Add member "
- dat += "Change Outfit "
- //Add more per team features here
-
- dat += "Current arena: [current_arena_template]"
- dat += "Arena List: "
- for(var/A in arena_templates)
- dat += "[A] "
- dat += " "
- dat += "Upload new arena "
- dat += " "
- //Special actions
- dat += "Reset Arena. "
- dat += "Load random arena. "
- dat += "Spawn trophies for survivors. "
-
- var/datum/browser/popup = new(user, "arena controller", "Arena Controller", 500, 600)
- popup.set_content(dat.Join())
- popup.open()
-
-/// Arena spawnpoint
-/obj/machinery/arena_spawn
- name = "Arena Spawnpoint"
- icon = 'icons/obj/machines/beacon.dmi'
- icon_state = "syndbeacon"
- resistance_flags = INDESTRUCTIBLE
- /// In case we have multiple arena controllers at once.
- var/arena_id = ARENA_DEFAULT_ID
- /// Team ID
- var/team = "default"
- /// only exist to cut down on glob.machines lookups, do not modify
- var/obj/machinery/computer/arena/_controller
-
-/obj/machinery/arena_spawn/red
- name = "Red Team Spawnpoint"
- color = "red"
- team = ARENA_RED_TEAM
-
-/obj/machinery/arena_spawn/green
- name = "Green Team Spawnpoint"
- color = "green"
- team = ARENA_GREEN_TEAM
-
-/obj/machinery/arena_spawn/proc/get_controller()
- if(_controller && !QDELETED(_controller) && _controller.arena_id == arena_id)
- return _controller
- for(var/obj/machinery/computer/arena/A as anything in SSmachines.get_machines_by_type_and_subtypes(/obj/machinery/computer/arena))
- if(A.arena_id == arena_id)
- _controller = A
- return _controller
-
-/obj/machinery/arena_spawn/attack_ghost(mob/user)
- var/obj/machinery/computer/arena/C = get_controller()
- if(!C) //Unlinked spawn
- return
- if(C.ready_to_spawn)
- var/list/allowed_keys = C.team_keys[team]
- if(!(user.ckey in allowed_keys))
- to_chat(user,span_warning("You're not on the team list."))
- return
- C.spawn_member(src,user.ckey,team)
-
-#undef ARENA_GREEN_TEAM
-#undef ARENA_RED_TEAM
-#undef ARENA_DEFAULT_ID
-#undef ARENA_CORNER_A
-#undef ARENA_CORNER_B
diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm
index 8a5efc193ca9f..e624e3f33d705 100644
--- a/code/game/machinery/constructable_frame.dm
+++ b/code/game/machinery/constructable_frame.dm
@@ -172,7 +172,12 @@
else
var/option = tgui_input_list(user, "Select Circuitboard To Install"," Available Boards", circuit_boards)
target_board = circuit_boards[option]
- if(QDELETED(target_board) || QDELETED(src) || QDELETED(user) || !(target_board in replacer) || !user.is_holding(replacer) || !user.Adjacent(src))
+ // Everything still where it should be after the UI closed?
+ if(QDELETED(target_board) || QDELETED(src) || QDELETED(user) || !(target_board in replacer) || !user.is_holding(replacer))
+ return FALSE
+ // User still within range?
+ var/close_enough = replacer.works_from_distance || user.Adjacent(src)
+ if(!close_enough)
return FALSE
if(install_board(user, target_board, by_hand = FALSE))
diff --git a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
index 092a4c7889a28..4e84870ec9c30 100644
--- a/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
+++ b/code/game/machinery/dna_infuser/organ_sets/rat_organs.dm
@@ -65,26 +65,22 @@
/obj/item/organ/internal/heart/rat/on_mob_insert(mob/living/carbon/receiver)
. = ..()
- if(!. || !ishuman(receiver))
+ if(!ishuman(receiver))
return
var/mob/living/carbon/human/human_receiver = receiver
- if(!human_receiver.can_mutate())
- return
- human_receiver.dna.add_mutation(/datum/mutation/human/dwarfism)
+ if(human_receiver.can_mutate())
+ human_receiver.dna.add_mutation(/datum/mutation/human/dwarfism)
//but 1.5 damage
- if(human_receiver.physiology)
- human_receiver.physiology.damage_resistance -= 50
+ human_receiver.physiology?.damage_resistance -= 50
/obj/item/organ/internal/heart/rat/on_mob_remove(mob/living/carbon/heartless, special)
. = ..()
if(!ishuman(heartless))
return
var/mob/living/carbon/human/human_heartless = heartless
- if(!human_heartless.can_mutate())
- return
- human_heartless.dna.remove_mutation(/datum/mutation/human/dwarfism)
- if(human_heartless.physiology)
- human_heartless.physiology.damage_resistance += 50
+ if(human_heartless.can_mutate())
+ human_heartless.dna.remove_mutation(/datum/mutation/human/dwarfism)
+ human_heartless.physiology?.damage_resistance += 50
/// you occasionally squeak, and have some rat related verbal tics
/obj/item/organ/internal/tongue/rat
diff --git a/code/game/machinery/slotmachine.dm b/code/game/machinery/slotmachine.dm
index ddfe76f56af1d..b7eec3994b8d1 100644
--- a/code/game/machinery/slotmachine.dm
+++ b/code/game/machinery/slotmachine.dm
@@ -10,7 +10,7 @@
#define JACKPOT 10000
#define SPIN_TIME 65 //As always, deciseconds.
#define REEL_DEACTIVATE_DELAY 7
-#define SEVEN "7 "
+#define JACKPOT_SEVENS FA_ICON_7
#define HOLOCHIP 1
#define COIN 2
@@ -24,7 +24,7 @@
density = TRUE
circuit = /obj/item/circuitboard/computer/slot_machine
light_color = LIGHT_COLOR_BROWN
- interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON|INTERACT_MACHINE_SET_MACHINE // don't need to be literate to play slots
+ interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON // don't need to be literate to play slots
var/money = 3000 //How much money it has CONSUMED
var/plays = 0
var/working = FALSE
@@ -32,9 +32,19 @@
var/jackpots = 0
var/paymode = HOLOCHIP //toggles between HOLOCHIP/COIN, defined above
var/cointype = /obj/item/coin/iron //default cointype
+ /// Icons that can be displayed by the slot machine.
+ var/static/list/icons = list(
+ FA_ICON_LEMON = list("value" = 2, "colour" = "yellow"),
+ FA_ICON_STAR = list("value" = 2, "colour" = "yellow"),
+ FA_ICON_BOMB = list("value" = 2, "colour" = "red"),
+ FA_ICON_BIOHAZARD = list("value" = 2, "colour" = "green"),
+ FA_ICON_APPLE_WHOLE = list("value" = 2, "colour" = "red"),
+ FA_ICON_7 = list("value" = 1, "colour" = "yellow"),
+ FA_ICON_DOLLAR_SIGN = list("value" = 2, "colour" = "green"),
+ )
+
var/static/list/coinvalues
var/list/reels = list(list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0, list("", "", "") = 0)
- var/list/symbols = list(SEVEN = 1, "& " = 2, "@ " = 2, "$ " = 2, "? " = 2, "# " = 2, "! " = 2, "% " = 2) //if people are winning too much, multiply every number in this list by 2 and see if they are still winning too much.
var/static/list/ray_filter = list(type = "rays", y = 16, size = 40, density = 4, color = COLOR_RED_LIGHT, factor = 15, flags = FILTER_OVERLAY)
/obj/machinery/computer/slot_machine/Initialize(mapload)
@@ -42,13 +52,13 @@
jackpots = rand(1, 4) //false hope
plays = rand(75, 200)
- INVOKE_ASYNC(src, PROC_REF(toggle_reel_spin), TRUE)//The reels won't spin unless we activate them
+ toggle_reel_spin_sync(1) //The reels won't spin unless we activate them
var/list/reel = reels[1]
for(var/i in 1 to reel.len) //Populate the reels.
randomize_reels()
- INVOKE_ASYNC(src, PROC_REF(toggle_reel_spin), FALSE)
+ toggle_reel_spin_sync(0)
if (isnull(coinvalues))
coinvalues = list()
@@ -84,46 +94,49 @@
icon_screen = "slots_screen"
return ..()
-/obj/machinery/computer/slot_machine/attackby(obj/item/I, mob/living/user, params)
- if(istype(I, /obj/item/coin))
- var/obj/item/coin/C = I
+
+/obj/machinery/computer/slot_machine/item_interaction(mob/living/user, obj/item/inserted, list/modifiers, is_right_clicking)
+ if(istype(inserted, /obj/item/coin))
+ var/obj/item/coin/inserted_coin = inserted
if(paymode == COIN)
if(prob(2))
- if(!user.transferItemToLoc(C, drop_location(), silent = FALSE))
+ if(!user.transferItemToLoc(inserted_coin, drop_location(), silent = FALSE))
return
- C.throw_at(user, 3, 10)
+ inserted_coin.throw_at(user, 3, 10)
if(prob(10))
balance = max(balance - SPIN_PRICE, 0)
to_chat(user, span_warning("[src] spits your coin back out!"))
else
- if(!user.temporarilyRemoveItemFromInventory(C))
+ if(!user.temporarilyRemoveItemFromInventory(inserted_coin))
return
- to_chat(user, span_notice("You insert [C] into [src]'s slot!"))
- balance += C.value
- qdel(C)
+ balloon_alert(user, "coin insterted")
+ balance += inserted_coin.value
+ qdel(inserted_coin)
else
- to_chat(user, span_warning("This machine is only accepting holochips!"))
- else if(istype(I, /obj/item/holochip))
+ balloon_alert(user, "holochips only!")
+
+ else if(istype(inserted, /obj/item/holochip))
if(paymode == HOLOCHIP)
- var/obj/item/holochip/H = I
- if(!user.temporarilyRemoveItemFromInventory(H))
+ var/obj/item/holochip/inserted_chip = inserted
+ if(!user.temporarilyRemoveItemFromInventory(inserted_chip))
return
- to_chat(user, span_notice("You insert [H.credits] holocredits into [src]'s slot!"))
- balance += H.credits
- qdel(H)
+ balloon_alert(user, "[inserted_chip.credits] credit[inserted_chip.credits == 1 ? "" : "s"] inserted")
+ balance += inserted_chip.credits
+ qdel(inserted_chip)
else
- to_chat(user, span_warning("This machine is only accepting coins!"))
- else if(I.tool_behaviour == TOOL_MULTITOOL)
+ balloon_alert(user, "coins only!")
+
+ else if(inserted.tool_behaviour == TOOL_MULTITOOL)
if(balance > 0)
visible_message("[src] says, 'ERROR! Please empty the machine balance before altering paymode'") //Prevents converting coins into holocredits and vice versa
else
if(paymode == HOLOCHIP)
paymode = COIN
- visible_message("[src] says, 'This machine now works with COINS!'")
+ balloon_alert(user, "now using coins")
else
paymode = HOLOCHIP
- visible_message("[src] says, 'This machine now works with HOLOCHIPS!'")
+ balloon_alert(user, "now using holochips")
else
return ..()
@@ -138,49 +151,54 @@
balloon_alert(user, "machine rigged")
return TRUE
-/obj/machinery/computer/slot_machine/ui_interact(mob/living/user)
+/obj/machinery/computer/slot_machine/ui_interact(mob/living/user, datum/tgui/ui)
+ . = ..()
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "SlotMachine", name)
+ ui.open()
+
+/obj/machinery/computer/slot_machine/ui_static_data(mob/user)
+ var/list/data = list()
+ data["icons"] = list()
+ for(var/icon_name in icons)
+ var/list/icon = icons[icon_name]
+ icon += list("icon" = icon_name)
+ data["icons"] += list(icon)
+ data["cost"] = SPIN_PRICE
+ data["jackpot"] = JACKPOT
+
+ return data
+
+/obj/machinery/computer/slot_machine/ui_data(mob/user)
+ var/list/data = list()
+ var/list/reel_states = list()
+ for(var/reel_state in reels)
+ reel_states += list(reel_state)
+ data["state"] = reel_states
+ data["balance"] = balance
+ data["working"] = working
+ data["money"] = money
+ data["plays"] = plays
+ data["jackpots"] = jackpots
+ data["paymode"] = paymode
+ return data
+
+
+/obj/machinery/computer/slot_machine/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
- var/reeltext = {"
- /*****^*****^*****^*****^*****\\
- | \[[reels[1][1]]\] | \[[reels[2][1]]\] | \[[reels[3][1]]\] | \[[reels[4][1]]\] | \[[reels[5][1]]\] |
- | \[[reels[1][2]]\] | \[[reels[2][2]]\] | \[[reels[3][2]]\] | \[[reels[4][2]]\] | \[[reels[5][2]]\] |
- | \[[reels[1][3]]\] | \[[reels[2][3]]\] | \[[reels[3][3]]\] | \[[reels[4][3]]\] | \[[reels[5][3]]\] |
- \\*****v*****v*****v*****v*****/
- "}
-
- var/dat
- if(working)
- dat = reeltext
-
- else
- dat = {"Five credits to play!
- Prize Money Available: [money] (jackpot payout is ALWAYS 100%!)
- Credit Remaining: [balance]
- [plays] players have tried their luck today, and [jackpots] have won a jackpot!
-
- Play!
-
- [reeltext]
- "}
- if(balance > 0)
- dat+="Refund balance "
-
- var/datum/browser/popup = new(user, "slotmachine", "Slot Machine")
- popup.set_content(dat)
- popup.open()
-
-/obj/machinery/computer/slot_machine/Topic(href, href_list)
- . = ..() //Sanity checks.
if(.)
- return .
-
- if(href_list["spin"])
- spin(usr)
+ return
- else if(href_list["refund"])
- if(balance > 0)
- give_payout(balance)
- balance = 0
+ switch(action)
+ if("spin")
+ spin(ui.user)
+ return TRUE
+ if("payout")
+ if(balance > 0)
+ give_payout(balance)
+ balance = 0
+ return TRUE
/obj/machinery/computer/slot_machine/emp_act(severity)
. = ..()
@@ -214,8 +232,6 @@
toggle_reel_spin(1)
update_appearance()
- updateDialog()
-
var/spin_loop = addtimer(CALLBACK(src, PROC_REF(do_spin)), 2, TIMER_LOOP|TIMER_STOPPABLE)
addtimer(CALLBACK(src, PROC_REF(finish_spinning), spin_loop, user, the_name), SPIN_TIME - (REEL_DEACTIVATE_DELAY * reels.len))
@@ -223,7 +239,6 @@
/obj/machinery/computer/slot_machine/proc/do_spin()
randomize_reels()
- updateDialog()
use_power(active_power_usage)
/obj/machinery/computer/slot_machine/proc/finish_spinning(spin_loop, mob/user, the_name)
@@ -232,50 +247,64 @@
deltimer(spin_loop)
give_prizes(the_name, user)
update_appearance()
- updateDialog()
+/// Check if the machine can be spun
/obj/machinery/computer/slot_machine/proc/can_spin(mob/user)
if(machine_stat & NOPOWER)
- to_chat(user, span_warning("The slot machine has no power!"))
+ balloon_alert(user, "no power!")
return FALSE
if(machine_stat & BROKEN)
- to_chat(user, span_warning("The slot machine is broken!"))
+ balloon_alert(user, "machine broken!")
return FALSE
if(working)
- to_chat(user, span_warning("You need to wait until the machine stops spinning before you can play again!"))
+ balloon_alert(user, "already spinning!")
return FALSE
if(balance < SPIN_PRICE)
- to_chat(user, span_warning("Insufficient money to play!"))
+ balloon_alert(user, "insufficient balance!")
return FALSE
return TRUE
+/// Sets the spinning states of all reels to value, with a delay between them
/obj/machinery/computer/slot_machine/proc/toggle_reel_spin(value, delay = 0) //value is 1 or 0 aka on or off
for(var/list/reel in reels)
if(!value)
playsound(src, 'sound/machines/ding_short.ogg', 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
reels[reel] = value
- sleep(delay)
+ if(delay)
+ sleep(delay)
+/// Same as toggle_reel_spin, but without the delay and runs synchronously
+/obj/machinery/computer/slot_machine/proc/toggle_reel_spin_sync(value)
+ for(var/list/reel in reels)
+ reels[reel] = value
+
+/// Randomize the states of all reels
/obj/machinery/computer/slot_machine/proc/randomize_reels()
for(var/reel in reels)
if(reels[reel])
reel[3] = reel[2]
reel[2] = reel[1]
- reel[1] = pick(symbols)
+ var/chosen = pick(icons)
+ reel[1] = icons[chosen] + list("icon_name" = chosen)
+/// Checks if any prizes have been won, and pays them out
/obj/machinery/computer/slot_machine/proc/give_prizes(usrname, mob/user)
var/linelength = get_lines()
var/did_player_win = TRUE
- if(reels[1][2] + reels[2][2] + reels[3][2] + reels[4][2] + reels[5][2] == "[SEVEN][SEVEN][SEVEN][SEVEN][SEVEN]")
- visible_message("[src] says, 'JACKPOT! You win [money] credits!'")
+ if(check_jackpot(FA_ICON_BOMB))
+ var/obj/item/grenade/flashbang/bang = new(get_turf(src))
+ bang.arm_grenade(null, 1 SECONDS)
+
+ else if(check_jackpot(JACKPOT_SEVENS))
+ var/prize = money + JACKPOT
+ visible_message("[src] says, 'JACKPOT! You win [prize] credits!'")
priority_announce("Congratulations to [user ? user.real_name : usrname] for winning the jackpot at the slot machine in [get_area(src)]!")
jackpots += 1
- balance += money - give_payout(JACKPOT)
money = 0
if(paymode == HOLOCHIP)
- new /obj/item/holochip(loc, JACKPOT)
+ new /obj/item/holochip(loc, prize)
else
for(var/i in 1 to 5)
cointype = pick(subtypesof(/obj/item/coin))
@@ -298,7 +327,8 @@
money = max(money - SPIN_PRICE * 4, money)
else
- to_chat(user, span_warning("No luck!"))
+ balloon_alert(user, "no luck!")
+ playsound(src, 'sound/machines/buzz-sigh.ogg', 50)
did_player_win = FALSE
if(did_player_win)
@@ -307,31 +337,38 @@
addtimer(CALLBACK(src, TYPE_PROC_REF(/datum, remove_filter), "jackpot_rays"), 3 SECONDS)
playsound(src, 'sound/machines/roulettejackpot.ogg', 50, TRUE)
+/// Checks for a jackpot (5 matching icons in the middle row) with the given icon name
+/obj/machinery/computer/slot_machine/proc/check_jackpot(name)
+ return reels[1][2]["icon_name"] + reels[2][2]["icon_name"] + reels[3][2]["icon_name"] + reels[4][2]["icon_name"] + reels[5][2]["icon_name"] == "[name][name][name][name][name]"
+
+/// Finds the largest number of consecutive matching icons in a row
/obj/machinery/computer/slot_machine/proc/get_lines()
var/amountthesame
for(var/i in 1 to 3)
- var/inputtext = reels[1][i] + reels[2][i] + reels[3][i] + reels[4][i] + reels[5][i]
- for(var/symbol in symbols)
+ var/inputtext = reels[1][i]["icon_name"] + reels[2][i]["icon_name"] + reels[3][i]["icon_name"] + reels[4][i]["icon_name"] + reels[5][i]["icon_name"]
+ for(var/icon in icons)
var/j = 3 //The lowest value we have to check for.
- var/symboltext = symbol + symbol + symbol
+ var/symboltext = icon + icon + icon
while(j <= 5)
if(findtext(inputtext, symboltext))
amountthesame = max(j, amountthesame)
j++
- symboltext += symbol
+ symboltext += icon
if(amountthesame)
break
return amountthesame
+/// Give the specified amount of money. If the amount is greater than the amount of prize money available, add the difference as balance
/obj/machinery/computer/slot_machine/proc/give_money(amount)
- var/amount_to_give = money >= amount ? amount : money
- var/surplus = amount_to_give - give_payout(amount_to_give)
- money = max(0, money - amount)
+ var/amount_to_give = min(amount, money)
+ var/surplus = amount - give_payout(amount_to_give)
+ money -= amount_to_give
balance += surplus
+/// Pay out the specified amount in either coins or holochips
/obj/machinery/computer/slot_machine/proc/give_payout(amount)
if(paymode == HOLOCHIP)
cointype = /obj/item/holochip
@@ -348,23 +385,25 @@
return amount
-/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, mob/living/target, throwit = 0)
+/// Dispense the given amount. If machine is set to use coins, will use the specified coin type.
+/// If throwit and target are set, will launch the payment at the target
+/obj/machinery/computer/slot_machine/proc/dispense(amount = 0, cointype = /obj/item/coin/silver, throwit = FALSE, mob/living/target)
if(paymode == HOLOCHIP)
- var/obj/item/holochip/H = new /obj/item/holochip(loc,amount)
+ var/obj/item/holochip/chip = new /obj/item/holochip(loc,amount)
if(throwit && target)
- H.throw_at(target, 3, 10)
+ chip.throw_at(target, 3, 10)
else
var/value = coinvalues["[cointype]"]
if(value <= 0)
CRASH("Coin value of zero, refusing to payout in dispenser")
while(amount >= value)
- var/obj/item/coin/C = new cointype(loc) //DOUBLE THE PAIN
+ var/obj/item/coin/thrown_coin = new cointype(loc) //DOUBLE THE PAIN
amount -= value
if(throwit && target)
- C.throw_at(target, 3, 10)
+ thrown_coin.throw_at(target, 3, 10)
else
- random_step(C, 2, 40)
+ random_step(thrown_coin, 2, 40)
playsound(src, pick(list('sound/machines/coindrop.ogg', 'sound/machines/coindrop2.ogg')), 50, TRUE)
return amount
@@ -374,7 +413,7 @@
#undef HOLOCHIP
#undef JACKPOT
#undef REEL_DEACTIVATE_DELAY
-#undef SEVEN
+#undef JACKPOT_SEVENS
#undef SMALL_PRIZE
#undef SPIN_PRICE
#undef SPIN_TIME
diff --git a/code/game/machinery/syndicatebomb.dm b/code/game/machinery/syndicatebomb.dm
index bc1523bde0ea0..ab381b14fad25 100644
--- a/code/game/machinery/syndicatebomb.dm
+++ b/code/game/machinery/syndicatebomb.dm
@@ -584,6 +584,68 @@
qdel(src)
+#define DIMENSION_CHOICE_RANDOM "None/Randomized"
+
+/obj/item/bombcore/dimensional
+ name = "multi-dimensional payload"
+ desc = "A wicked payload meant to wildly transmutate terrain over a wide area, a power no mere human should wield."
+ range_heavy = 17
+ var/datum/dimension_theme/chosen_theme
+
+/obj/item/bombcore/dimensional/Destroy()
+ chosen_theme = null
+ return ..()
+
+/obj/item/bombcore/dimensional/examine(mob/user)
+ . = ..()
+ . += span_notice("Use in hand to change the linked dimension. Current dimension: [chosen_theme?.name || "None, output will be random"].")
+
+/obj/item/bombcore/dimensional/attack_self(mob/user)
+ . = ..()
+ var/list/choosable_dimensions = list()
+ var/datum/radial_menu_choice/null_choice = new
+ null_choice.name = DIMENSION_CHOICE_RANDOM
+ choosable_dimensions += null_choice
+ for(var/datum/dimension_theme/theme as anything in SSmaterials.dimensional_themes)
+ var/datum/radial_menu_choice/theme_choice = new
+ theme_choice.image = image(initial(theme.icon), initial(theme.icon_state))
+ theme_choice.name = initial(theme.name)
+ choosable_dimensions[theme] = theme_choice
+
+ var/datum/dimension_theme/picked = show_radial_menu(user, src, choosable_dimensions, custom_check = CALLBACK(src, PROC_REF(check_menu), user), radius = 38, require_near = TRUE)
+ if(isnull(picked))
+ return
+ if(picked == DIMENSION_CHOICE_RANDOM)
+ chosen_theme = null
+ else
+ chosen_theme = picked
+ balloon_alert(user, "set to [chosen_theme?.name || DIMENSION_CHOICE_RANDOM]")
+
+/obj/item/bombcore/dimensional/proc/check_menu(mob/user)
+ if(!user.is_holding(src) || user.incapacitated())
+ return FALSE
+ return TRUE
+
+/obj/item/bombcore/dimensional/detonate()
+ var/list/affected_turfs = circle_range_turfs(src, range_heavy)
+ var/theme_count = length(SSmaterials.dimensional_themes)
+ var/num_affected = 0
+ for(var/turf/affected as anything in affected_turfs)
+ var/datum/dimension_theme/theme_to_use = chosen_theme
+ if(isnull(chosen_theme))
+ theme_to_use = SSmaterials.dimensional_themes[SSmaterials.dimensional_themes[rand(1, theme_count)]]
+ if(!theme_to_use.can_convert(affected))
+ continue
+ num_affected++
+ var/skip_sound = TRUE
+ if(num_affected % 5) //makes it play the sound more sparingly
+ skip_sound = FALSE
+ var/time_mult = round(get_dist_euclidian(get_turf(src), affected)) + 1
+ addtimer(CALLBACK(theme_to_use, TYPE_PROC_REF(/datum/dimension_theme, apply_theme), affected, skip_sound, TRUE), 0.1 SECONDS * time_mult)
+ qdel(src)
+
+#undef DIMENSION_CHOICE_RANDOM
+
///Syndicate Detonator (aka the big red button)///
/obj/item/syndicatedetonator
diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional.dm b/code/game/objects/effects/anomalies/anomalies_dimensional.dm
index 9aea9dfea6a0c..16dd5bafcfaea 100644
--- a/code/game/objects/effects/anomalies/anomalies_dimensional.dm
+++ b/code/game/objects/effects/anomalies/anomalies_dimensional.dm
@@ -21,6 +21,11 @@
animate(src, transform = matrix()*0.85, time = 3, loop = -1)
animate(transform = matrix(), time = 3, loop = -1)
+/obj/effect/anomaly/dimensional/Destroy()
+ theme = null
+ target_turfs = null
+ return ..()
+
/obj/effect/anomaly/dimensional/anomalyEffect(seconds_per_tick)
. = ..()
transmute_area()
@@ -36,8 +41,7 @@
return
var/turf/affected_turf = target_turfs[1]
- new /obj/effect/temp_visual/transmute_tile_flash(affected_turf)
- theme.apply_theme(affected_turf)
+ theme.apply_theme(affected_turf, show_effect = TRUE)
target_turfs -= affected_turf
/**
@@ -47,7 +51,7 @@
/obj/effect/anomaly/dimensional/proc/prepare_area(new_theme_path)
if (!new_theme_path)
new_theme_path = pick(subtypesof(/datum/dimension_theme))
- theme = new new_theme_path()
+ theme = SSmaterials.dimensional_themes[new_theme_path]
apply_theme_icon()
target_turfs = list()
diff --git a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm
index 16408ea9ce6e0..c6190a0d84a21 100644
--- a/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm
+++ b/code/game/objects/effects/anomalies/anomalies_dimensional_themes.dm
@@ -1,4 +1,3 @@
-
/**
* Datum which describes a theme and replaces turfs and objects in specified locations to match that theme
*/
@@ -44,12 +43,16 @@
*
* Arguments
* * affected_turf - Turf to transform.
+ * * skip_sound - If the sound shouldn't be played.
+ * * show_effect - if the temp visual effect should be shown.
*/
-/datum/dimension_theme/proc/apply_theme(turf/affected_turf, skip_sound = FALSE)
+/datum/dimension_theme/proc/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE)
if (!replace_turf(affected_turf))
return
if (!skip_sound)
playsound(affected_turf, sound, 100, TRUE)
+ if(show_effect)
+ new /obj/effect/temp_visual/transmute_tile_flash(affected_turf)
for (var/obj/object in affected_turf)
replace_object(object)
if (length(random_spawns) && prob(random_spawn_chance) && !affected_turf.is_blocked_turf(exclude_mobs = TRUE))
@@ -250,7 +253,7 @@
/datum/dimension_theme/radioactive
name = "Radioactive"
icon = 'icons/obj/ore.dmi'
- icon_state = "Uranium ore"
+ icon_state = "uranium"
material = /datum/material/uranium
sound = 'sound/items/welder.ogg'
@@ -353,7 +356,14 @@
name = "Fancy"
icon = 'icons/obj/clothing/head/costume.dmi'
icon_state = "fancycrown"
+ replace_floors = null
replace_walls = /turf/closed/wall/mineral/wood/nonmetal
+ replace_objs = list(
+ /obj/structure/chair = list(/obj/structure/chair/comfy = 1),
+ /obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1),
+ )
+ ///cooldown for changing carpets, It's kinda dull to always use the same one, but we also can't make it too random.
+ COOLDOWN_DECLARE(carpet_switch_cd)
#define FANCY_CARPETS list(\
/turf/open/floor/eighties, \
@@ -369,14 +379,12 @@
/turf/open/floor/carpet/royalblack, \
/turf/open/floor/carpet/royalblue,)
-/datum/dimension_theme/fancy/New()
- . = ..()
- replace_floors = list(pick(FANCY_CARPETS) = 1)
- replace_objs = list(
- /obj/structure/chair = list(/obj/structure/chair/comfy = 1),
- /obj/machinery/door/airlock = list(/obj/machinery/door/airlock/wood = 1, /obj/machinery/door/airlock/wood/glass = 1),
- /obj/structure/table/wood = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1),
- )
+/datum/dimension_theme/fancy/apply_theme(turf/affected_turf, skip_sound = FALSE, show_effect = FALSE)
+ if(COOLDOWN_FINISHED(src, carpet_switch_cd))
+ replace_floors = list(pick(FANCY_CARPETS) = 1)
+ replace_objs[/obj/structure/table/wood] = list(pick(subtypesof(/obj/structure/table/wood/fancy)) = 1)
+ COOLDOWN_START(src, carpet_switch_cd, 90 SECONDS)
+ return ..()
#undef FANCY_CARPETS
diff --git a/code/game/objects/effects/countdown.dm b/code/game/objects/effects/countdown.dm
index ab422dda3d156..d83440ee9bd36 100644
--- a/code/game/objects/effects/countdown.dm
+++ b/code/game/objects/effects/countdown.dm
@@ -162,19 +162,6 @@
var/time_left = max(0, (H.finish_time - world.time) / 10)
return round(time_left)
-/obj/effect/countdown/arena
- invisibility = INVISIBILITY_NONE
- name = "arena countdown"
-
-/obj/effect/countdown/arena/get_value()
- var/obj/machinery/arena_spawn/A = attached_to
- if(!istype(A))
- return
- else
- var/obj/machinery/computer/arena/C = A.get_controller()
- var/time_left = max(0, (C.start_time - world.time) / 10)
- return round(time_left)
-
/obj/effect/countdown/flower_bud
name = "flower bud countdown"
diff --git a/code/game/objects/effects/spawners/random/maintenance.dm b/code/game/objects/effects/spawners/random/maintenance.dm
index 234b69e85716d..38f8af6a90269 100644
--- a/code/game/objects/effects/spawners/random/maintenance.dm
+++ b/code/game/objects/effects/spawners/random/maintenance.dm
@@ -9,7 +9,7 @@
/obj/effect/spawner/random/maintenance/no_decals
/obj/effect/spawner/random/maintenance/no_decals/can_spawn(atom/loot)
- return !istype(loot, /obj/effect/decal)
+ return !ispath(loot, /obj/effect/decal)
/obj/effect/spawner/random/maintenance/examine(mob/user)
. = ..()
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 6c96f24e33697..06b4a8e4b0721 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -683,11 +683,11 @@
duration = 0.4 SECONDS
/// Plays a dispersing animation on hivelord and legion minions so they don't just vanish
-/obj/effect/temp_visual/hive_spawn_wither
+/obj/effect/temp_visual/despawn_effect
name = "withering spawn"
duration = 1 SECONDS
-/obj/effect/temp_visual/hive_spawn_wither/Initialize(mapload, atom/copy_from)
+/obj/effect/temp_visual/despawn_effect/Initialize(mapload, atom/copy_from)
if (isnull(copy_from))
. = ..()
return INITIALIZE_HINT_QDEL
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 45daf00db1ae3..1f06113158cef 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -244,6 +244,14 @@ GLOBAL_LIST_INIT(channel_tokens, list(
worn_icon_state = "com_headset"
keyslot = /obj/item/encryptionkey/heads/hos
+/obj/item/radio/headset/heads/hos/advisor
+ name = "\proper the veteran security advisor headset"
+ desc = "The headset of the man who was in charge of keeping order and protecting the station..."
+ icon_state = "com_headset"
+ worn_icon_state = "com_headset"
+ keyslot = /obj/item/encryptionkey/heads/hos
+ command = FALSE
+
/obj/item/radio/headset/heads/hos/alt
name = "\proper the head of security's bowman headset"
desc = "The headset of the man in charge of keeping order and protecting the station. Protects ears from flashbangs."
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index de996015e592c..f110cd8b43eab 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -325,6 +325,7 @@
door.update_appearance()
qdel(src)
+ return door
/obj/structure/door_assembly/update_overlays()
. = ..()
diff --git a/code/game/objects/structures/door_assembly_types.dm b/code/game/objects/structures/door_assembly_types.dm
index 36b41fbc32632..589cad42bcabc 100644
--- a/code/game/objects/structures/door_assembly_types.dm
+++ b/code/game/objects/structures/door_assembly_types.dm
@@ -293,4 +293,5 @@
/obj/structure/door_assembly/door_assembly_material/finish_door()
var/obj/machinery/door/airlock/door = ..()
door.set_custom_materials(custom_materials)
+ door.update_appearance()
return door
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index fba9d5cecc454..da02394251810 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -339,19 +339,19 @@
var/turf/T = get_turf(src)
if(T.overfloor_placed)//cant be a floor in the way!
return FALSE
- // Shocking hurts the grille (to weaken monkey powersinks)
- if(prob(50))
+
+ var/obj/structure/cable/cable_node = T.get_cable_node()
+ if(isnull(cable_node))
+ return FALSE
+ if(!electrocute_mob(user, cable_node, src, 1, TRUE))
+ return FALSE
+ if(prob(50)) // Shocking hurts the grille (to weaken monkey powersinks)
take_damage(1, BURN, FIRE, sound_effect = FALSE)
- var/obj/structure/cable/C = T.get_cable_node()
- if(C)
- if(electrocute_mob(user, C, src, 1, TRUE))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(3, 1, src)
- s.start()
- return TRUE
- else
- return FALSE
- return FALSE
+ var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
+ sparks.set_up(3, 1, src)
+ sparks.start()
+
+ return TRUE
/obj/structure/grille/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return exposed_temperature > T0C + 1500 && !broken
diff --git a/code/game/turfs/open/floor.dm b/code/game/turfs/open/floor.dm
index a88e7f6b85e18..2dbd065849ec1 100644
--- a/code/game/turfs/open/floor.dm
+++ b/code/game/turfs/open/floor.dm
@@ -201,7 +201,6 @@
/turf/open/floor/acid_melt()
ScrapeAway(flags = CHANGETURF_INHERIT_AIR)
-/// if you are updating this make to to update /turf/open/misc/rcd_vals() too
/turf/open/floor/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
switch(the_rcd.mode)
if(RCD_TURF)
diff --git a/code/game/turfs/open/misc.dm b/code/game/turfs/open/misc.dm
index a704c7f12b168..02de7489786f9 100644
--- a/code/game/turfs/open/misc.dm
+++ b/code/game/turfs/open/misc.dm
@@ -76,153 +76,18 @@
return
/turf/open/misc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
- switch(the_rcd.mode)
- if(RCD_TURF)
- if(the_rcd.rcd_design_path != /turf/open/floor/plating/rcd)
- return FALSE
-
- var/obj/structure/girder/girder = locate() in src
- if(girder)
- return girder.rcd_vals(user, the_rcd)
-
- return rcd_result_with_memory(
- list("delay" = 2 SECONDS, "cost" = 16),
- src, RCD_MEMORY_WALL,
- )
- if(RCD_WINDOWGRILLE)
- //default cost for building a grill for fulltile windows
- var/cost = 4
- var/delay = 1 SECONDS
- if(the_rcd.rcd_design_path == /obj/structure/window)
- cost = 4
- delay = 2 SECONDS
- else if(the_rcd.rcd_design_path == /obj/structure/window/reinforced)
- cost = 6
- delay = 2.5 SECONDS
- return rcd_result_with_memory(
- list("delay" = delay, "cost" = cost),
- src, RCD_MEMORY_WINDOWGRILLE,
- )
- if(RCD_AIRLOCK)
- if(ispath(the_rcd.rcd_design_path, /obj/machinery/door/airlock/glass))
- return list("delay" = 5 SECONDS, "cost" = 20)
- else
- return list("delay" = 5 SECONDS, "cost" = 16)
- if(RCD_STRUCTURE)
- var/static/list/structure_costs = list(
- /obj/structure/reflector = list("delay" = 2 SECONDS, "cost" = 20),
- /obj/structure/girder = list("delay" = 1.3 SECONDS, "cost" = 8),
- /obj/structure/frame/machine/secured = list("delay" = 2 SECONDS, "cost" = 20),
- /obj/structure/frame/computer/rcd = list("delay" = 2 SECONDS, "cost" = 20),
- /obj/structure/floodlight_frame = list("delay" = 3 SECONDS, "cost" = 20),
- /obj/structure/chair = list("delay" = 1 SECONDS, "cost" = 4),
- /obj/structure/chair/stool/bar = list("delay" = 0.5 SECONDS, "cost" = 4),
- /obj/structure/table = list("delay" = 2 SECONDS, "cost" = 8),
- /obj/structure/bed = list("delay" = 2.5 SECONDS, "cost" = 8),
- /obj/structure/rack = list("delay" = 2.5 SECONDS, "cost" = 4),
- )
-
- var/list/design_data = structure_costs[the_rcd.rcd_design_path]
- if(!isnull(design_data))
- return design_data
-
- for(var/structure in structure_costs)
- if(ispath(the_rcd.rcd_design_path, structure))
- return structure_costs[structure]
-
+ if(the_rcd.mode == RCD_TURF)
+ if(the_rcd.rcd_design_path != /turf/open/floor/plating/rcd)
return FALSE
+ return list("delay" = 0, "cost" = 3)
return FALSE
/turf/open/misc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, list/rcd_data)
- switch(rcd_data["[RCD_DESIGN_MODE]"])
- if(RCD_TURF)
- if(rcd_data["[RCD_DESIGN_PATH]"] != /turf/open/floor/plating/rcd)
- return FALSE
-
- var/obj/structure/girder/girder = locate() in src
- if(girder)
- return girder.rcd_act(user, the_rcd, rcd_data)
-
- place_on_top(/turf/closed/wall)
- return TRUE
- if(RCD_WINDOWGRILLE)
- //check if we are building a window
- var/obj/structure/window/window_path = rcd_data["[RCD_DESIGN_PATH]"]
- if(!ispath(window_path))
- CRASH("Invalid window path type in RCD: [window_path]")
-
- //allow directional windows to be built without grills
- if(!initial(window_path.fulltile))
- if(!valid_build_direction(src, user.dir, is_fulltile = FALSE))
- balloon_alert(user, "window already here!")
- return FALSE
- var/obj/structure/window/WD = new window_path(src, user.dir)
- WD.set_anchored(TRUE)
- return TRUE
-
- //build grills to deal with full tile windows
- if(locate(/obj/structure/grille) in src)
- return FALSE
- var/obj/structure/grille/new_grille = new(src)
- new_grille.set_anchored(TRUE)
- return TRUE
- if(RCD_AIRLOCK)
- var/obj/machinery/door/airlock_type = rcd_data["[RCD_DESIGN_PATH]"]
-
- if(ispath(airlock_type, /obj/machinery/door/window))
- if(!valid_build_direction(src, user.dir, is_fulltile = FALSE))
- balloon_alert(user, "there's already a windoor!")
- return FALSE
- for(var/obj/machinery/door/door in src)
- if(istype(door, /obj/machinery/door/window))
- continue
- balloon_alert(user, "there's already a door!")
- return FALSE
- //create the assembly and let it finish itself
- var/obj/structure/windoor_assembly/assembly = new (src, user.dir)
- assembly.secure = ispath(airlock_type, /obj/machinery/door/window/brigdoor)
- assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly)
- assembly.finish_door()
- return TRUE
-
- for(var/obj/machinery/door/door in src)
- if(door.sub_door)
- continue
- balloon_alert(user, "there's already a door!")
- return FALSE
- //create the assembly and let it finish itself
- var/obj/structure/door_assembly/assembly = new (src)
- if(initial(airlock_type.glass))
- assembly.glass = TRUE
- assembly.glass_type = airlock_type
- else
- assembly.airlock_type = airlock_type
- assembly.electronics = the_rcd.airlock_electronics.create_copy(assembly)
- assembly.finish_door()
- return TRUE
- if(RCD_STRUCTURE)
- var/atom/movable/design_type = rcd_data["[RCD_DESIGN_PATH]"]
-
- //map absolute types to basic subtypes
- var/atom/movable/locate_type = design_type
- if(ispath(locate_type, /obj/structure/frame/machine/secured))
- locate_type = /obj/structure/frame/machine
- if(ispath(locate_type, /obj/structure/frame/computer/rcd))
- locate_type = /obj/structure/frame/computer
- if(ispath(locate_type, /obj/structure/floodlight_frame/completed))
- locate_type = /obj/structure/floodlight_frame
- if(locate(locate_type) in src)
- return FALSE
-
- var/atom/movable/design = new design_type(src)
- var/static/list/dir_types = list(
- /obj/structure/chair,
- /obj/structure/table,
- /obj/structure/rack,
- /obj/structure/bed,
- )
- if(is_path_in_list(locate_type, dir_types))
- design.setDir(user.dir)
- return TRUE
+ if(rcd_data["[RCD_DESIGN_MODE]"] == RCD_TURF)
+ if(rcd_data["[RCD_DESIGN_PATH]"] != /turf/open/floor/plating/rcd)
+ return FALSE
+
+ place_on_top(/turf/open/floor/plating, flags = CHANGETURF_INHERIT_AIR)
+ return TRUE
return FALSE
diff --git a/code/modules/antagonists/changeling/powers/mutations.dm b/code/modules/antagonists/changeling/powers/mutations.dm
index 7ad2b14448c2e..af7348f7bf139 100644
--- a/code/modules/antagonists/changeling/powers/mutations.dm
+++ b/code/modules/antagonists/changeling/powers/mutations.dm
@@ -90,8 +90,8 @@
chemical_cost = 1000
dna_cost = CHANGELING_POWER_UNOBTAINABLE
- var/helmet_type = /obj/item
- var/suit_type = /obj/item
+ var/helmet_type = null
+ var/suit_type = null
var/suit_name_simple = " "
var/helmet_name_simple = " "
var/recharge_slowdown = 0
@@ -125,10 +125,14 @@
if(!ishuman(user) || !changeling)
return 1
var/mob/living/carbon/human/H = user
+
if(istype(H.wear_suit, suit_type) || istype(H.head, helmet_type))
- H.visible_message(span_warning("[H] casts off [H.p_their()] [suit_name_simple]!"), span_warning("We cast off our [suit_name_simple]."), span_hear("You hear the organic matter ripping and tearing!"))
- H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it
- H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE)
+ var/name_to_use = (isnull(suit_type) ? helmet_name_simple : suit_name_simple)
+ H.visible_message(span_warning("[H] casts off [H.p_their()] [name_to_use]!"), span_warning("We cast off our [name_to_use]."), span_hear("You hear the organic matter ripping and tearing!"))
+ if(!isnull(helmet_type))
+ H.temporarilyRemoveItemFromInventory(H.head, TRUE) //The qdel on dropped() takes care of it
+ if(!isnull(suit_type))
+ H.temporarilyRemoveItemFromInventory(H.wear_suit, TRUE)
H.update_worn_oversuit()
H.update_worn_head()
H.update_body_parts()
@@ -141,18 +145,19 @@
return 1
/datum/action/changeling/suit/sting_action(mob/living/carbon/human/user)
- if(!user.canUnEquip(user.wear_suit))
+ if(!user.canUnEquip(user.wear_suit) && !isnull(suit_type))
user.balloon_alert(user, "body occupied!")
return
- if(!user.canUnEquip(user.head))
+ if(!user.canUnEquip(user.head) && !isnull(helmet_type))
user.balloon_alert(user, "head occupied!")
return
..()
- user.dropItemToGround(user.head)
- user.dropItemToGround(user.wear_suit)
-
- user.equip_to_slot_if_possible(new suit_type(user), ITEM_SLOT_OCLOTHING, 1, 1, 1)
- user.equip_to_slot_if_possible(new helmet_type(user), ITEM_SLOT_HEAD, 1, 1, 1)
+ if(!isnull(suit_type))
+ user.dropItemToGround(user.wear_suit)
+ user.equip_to_slot_if_possible(new suit_type(user), ITEM_SLOT_OCLOTHING, 1, 1, 1)
+ if(!isnull(helmet_type))
+ user.dropItemToGround(user.head)
+ user.equip_to_slot_if_possible(new helmet_type(user), ITEM_SLOT_HEAD, 1, 1, 1)
var/datum/antagonist/changeling/changeling = IS_CHANGELING(user)
changeling.chem_recharge_slowdown += recharge_slowdown
@@ -582,3 +587,124 @@
/obj/item/clothing/head/helmet/changeling/Initialize(mapload)
. = ..()
ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
+
+/datum/action/changeling/suit/hive_head
+ name = "Hive Head"
+ desc = "We coat our head in a waxy outing coating similar to a bee hive which can be used to manufacture bees to attack our enemies. Costs 15 chemicals."
+ helptext = "While the hive head does not provide much in the ways of armor, it does allow the user to send bees out to attack targets. Reagents can poured inside the hive to cause all bees released to inject said reagents."
+ button_icon_state = "hive_head"
+ chemical_cost = 15
+ dna_cost = 2
+ req_human = FALSE
+ blood_on_castoff = TRUE
+
+ helmet_type = /obj/item/clothing/head/helmet/changeling_hivehead
+ helmet_name_simple = "hive head"
+
+/obj/item/clothing/head/helmet/changeling_hivehead
+ name = "hive head"
+ desc = "A strange, waxy outer coating covering your head. Gives you tinnitus."
+ icon_state = "hivehead"
+ inhand_icon_state = null
+ flash_protect = FLASH_PROTECTION_FLASH
+ item_flags = DROPDEL
+ armor_type = /datum/armor/changeling_hivehead
+ flags_inv = HIDEEARS|HIDEHAIR|HIDEEYES|HIDEFACIALHAIR|HIDEFACE|HIDESNOUT
+ actions_types = list(/datum/action/cooldown/hivehead_spawn_minions)
+ ///Does this hive head hold reagents?
+ var/holds_reagents = TRUE
+
+/obj/item/clothing/head/helmet/changeling_hivehead/Initialize(mapload)
+ . = ..()
+ if(holds_reagents)
+ create_reagents(50, REFILLABLE)
+
+/datum/armor/changeling_hivehead
+ melee = 10
+ bullet = 10
+ laser = 10
+ energy = 10
+ bio = 50
+
+/obj/item/clothing/head/helmet/changeling_hivehead/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_NODROP, CHANGELING_TRAIT)
+
+/obj/item/clothing/head/helmet/changeling_hivehead/attackby(obj/item/attacking_item, mob/user, params)
+ . = ..()
+ if(!istype(attacking_item, /obj/item/organ/internal/monster_core/regenerative_core/legion) || !holds_reagents)
+ return
+ visible_message(span_boldwarning("As [user] shoves [attacking_item] into [src], [src] begins to mutate."))
+ var/mob/living/carbon/wearer = loc
+ playsound(wearer, 'sound/effects/attackblob.ogg', 60, TRUE)
+ wearer.temporarilyRemoveItemFromInventory(wearer.head, TRUE)
+ wearer.equip_to_slot_if_possible(new /obj/item/clothing/head/helmet/changeling_hivehead/legion(wearer), ITEM_SLOT_HEAD, 1, 1, 1)
+ qdel(attacking_item)
+
+
+/datum/action/cooldown/hivehead_spawn_minions
+ name = "Release Bees"
+ desc = "Release a group of bees to attack all other lifeforms."
+ background_icon_state = "bg_demon"
+ overlay_icon_state = "bg_demon_border"
+ button_icon = 'icons/mob/simple/bees.dmi'
+ button_icon_state = "queen_item"
+ cooldown_time = 30 SECONDS
+ ///The mob we're going to spawn
+ var/spawn_type = /mob/living/basic/bee/timed/short
+ ///How many are we going to spawn
+ var/spawn_count = 6
+
+/datum/action/cooldown/hivehead_spawn_minions/PreActivate(atom/target)
+ if(owner.movement_type & VENTCRAWLING)
+ owner.balloon_alert(owner, "unavailable here")
+ return
+ return ..()
+
+/datum/action/cooldown/hivehead_spawn_minions/Activate(atom/target)
+ . = ..()
+ do_tell()
+ var/spawns = spawn_count
+ if(owner.stat >= HARD_CRIT)
+ spawns = 1
+ for(var/i in 1 to spawns)
+ var/mob/living/basic/summoned_minion = new spawn_type(get_turf(owner))
+ summoned_minion.faction = list("[REF(owner)]")
+ minion_additional_changes(summoned_minion)
+
+///Our tell that we're using this ability. Usually a sound and a visible message.area
+/datum/action/cooldown/hivehead_spawn_minions/proc/do_tell()
+ owner.visible_message(span_warning("[owner]'s head begins to buzz as bees begin to pour out!"), span_warning("We release the bees."), span_hear("You hear a loud buzzing sound!"))
+ playsound(owner, 'sound/creatures/bee_swarm.ogg', 60, TRUE)
+
+///Stuff we want to do to our minions. This is in its own proc so subtypes can override this behaviour.
+/datum/action/cooldown/hivehead_spawn_minions/proc/minion_additional_changes(mob/living/basic/minion)
+ var/mob/living/basic/bee/summoned_bee = minion
+ var/mob/living/carbon/wearer = owner
+ if(istype(summoned_bee) && length(wearer.head.reagents.reagent_list))
+ summoned_bee.assign_reagent(pick(wearer.head.reagents.reagent_list))
+
+/obj/item/clothing/head/helmet/changeling_hivehead/legion
+ name = "legion hive head"
+ desc = "A strange, boney coating covering your head with a fleshy inside. Surprisingly comfortable."
+ icon_state = "hivehead_legion"
+ actions_types = list(/datum/action/cooldown/hivehead_spawn_minions/legion)
+ holds_reagents = FALSE
+
+/datum/action/cooldown/hivehead_spawn_minions/legion
+ name = "Release Legion"
+ desc = "Release a group of legion to attack all other lifeforms."
+ button_icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
+ button_icon_state = "legion_head"
+ cooldown_time = 15 SECONDS
+ spawn_type = /mob/living/basic/legion_brood
+ spawn_count = 4
+
+/datum/action/cooldown/hivehead_spawn_minions/legion/do_tell()
+ owner.visible_message(span_warning("[owner]'s head begins to shake as legion begin to pour out!"), span_warning("We release the legion."), span_hear("You hear a loud squishing sound!"))
+ playsound(owner, 'sound/effects/attackblob.ogg', 60, TRUE)
+
+/datum/action/cooldown/hivehead_spawn_minions/legion/minion_additional_changes(mob/living/basic/minion)
+ var/mob/living/basic/legion_brood/brood = minion
+ if (istype(brood))
+ brood.assign_creator(owner, FALSE)
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index caacb2bb6036f..02357d22e8b41 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -451,42 +451,42 @@
switch(construct_class)
if(CONSTRUCT_JUGGERNAUT)
if(IS_CULTIST(creator))
- makeNewConstruct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc
+ make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc
return
switch(theme)
if(THEME_WIZARD)
- makeNewConstruct(/mob/living/basic/construct/juggernaut/mystic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/juggernaut/mystic, target, creator, cultoverride, loc_override)
if(THEME_HOLY)
- makeNewConstruct(/mob/living/basic/construct/juggernaut/angelic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/juggernaut/angelic, target, creator, cultoverride, loc_override)
if(THEME_CULT)
- makeNewConstruct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/juggernaut, target, creator, cultoverride, loc_override)
if(CONSTRUCT_WRAITH)
if(IS_CULTIST(creator))
- makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc
+ make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc
return
switch(theme)
if(THEME_WIZARD)
- makeNewConstruct(/mob/living/basic/construct/wraith/mystic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/wraith/mystic, target, creator, cultoverride, loc_override)
if(THEME_HOLY)
- makeNewConstruct(/mob/living/basic/construct/wraith/angelic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/wraith/angelic, target, creator, cultoverride, loc_override)
if(THEME_CULT)
- makeNewConstruct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/wraith, target, creator, cultoverride, loc_override)
if(CONSTRUCT_ARTIFICER)
if(IS_CULTIST(creator))
- makeNewConstruct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the makeNewConstruct proc
+ make_new_construct(/mob/living/basic/construct/artificer, target, creator, cultoverride, loc_override) // ignore themes, the actual giving of cult info is in the make_new_construct proc
return
switch(theme)
if(THEME_WIZARD)
- makeNewConstruct(/mob/living/basic/construct/artificer/mystic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/artificer/mystic, target, creator, cultoverride, loc_override)
if(THEME_HOLY)
- makeNewConstruct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override)
if(THEME_CULT)
- makeNewConstruct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override)
+ make_new_construct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override)
-/proc/makeNewConstruct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null)
+/proc/make_new_construct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null)
if(QDELETED(target))
return
- var/mob/living/basic/construct/newstruct = new ctype((loc_override) ? (loc_override) : (get_turf(target)))
+ var/mob/living/basic/construct/newstruct = new ctype(loc_override || get_turf(target))
var/makeicon = newstruct.icon_state
var/theme = newstruct.theme
flick("make_[makeicon][theme]", newstruct)
@@ -494,20 +494,20 @@
if(stoner)
newstruct.faction |= "[REF(stoner)]"
newstruct.master = stoner
- var/datum/action/innate/seek_master/SM = new()
- SM.Grant(newstruct)
- newstruct.key = target.key
- var/atom/movable/screen/alert/bloodsense/BS
- if(newstruct.mind && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted())
+ var/datum/action/innate/seek_master/seek_master = new
+ seek_master.Grant(newstruct)
+ target.mind?.transfer_to(newstruct, force_key_move = TRUE)
+ var/atom/movable/screen/alert/bloodsense/sense_alert
+ if(newstruct.mind && !IS_CULTIST(newstruct) && ((stoner && IS_CULTIST(stoner)) || cultoverride) && SSticker.HasRoundStarted())
newstruct.mind.add_antag_datum(/datum/antagonist/cult/construct)
if(IS_CULTIST(stoner) || cultoverride)
- to_chat(newstruct, "You are still bound to serve the cult[stoner ? " and [stoner]":""], follow [stoner ? stoner.p_their() : "their"] orders and help [stoner ? stoner.p_them() : "them"] complete [stoner ? stoner.p_their() : "their"] goals at all costs. ")
+ to_chat(newstruct, span_cultbold("You are still bound to serve the cult[stoner ? " and [stoner]" : ""], follow [stoner?.p_their() || "their"] orders and help [stoner?.p_them() || "them"] complete [stoner?.p_their() || "their"] goals at all costs."))
else if(stoner)
- to_chat(newstruct, "You are still bound to serve your creator, [stoner], follow [stoner.p_their()] orders and help [stoner.p_them()] complete [stoner.p_their()] goals at all costs. ")
+ to_chat(newstruct, span_boldwarning("You are still bound to serve your creator, [stoner], follow [stoner.p_their()] orders and help [stoner.p_them()] complete [stoner.p_their()] goals at all costs."))
newstruct.clear_alert("bloodsense")
- BS = newstruct.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
- if(BS)
- BS.Cviewer = newstruct
+ sense_alert = newstruct.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
+ if(sense_alert)
+ sense_alert.Cviewer = newstruct
newstruct.cancel_camera()
/obj/item/soulstone/anybody
diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm
index 337dca218ead7..fd30973d24107 100644
--- a/code/modules/cargo/goodies.dm
+++ b/code/modules/cargo/goodies.dm
@@ -249,6 +249,12 @@
cost = PAYCHECK_CREW
contains = list(/obj/item/bait_can/worm/premium)
+/datum/supply_pack/goody/naturalbait
+ name = "Freshness Jars full of Natural Bait"
+ desc = "Homemade in the Spinward Sector."
+ cost = PAYCHECK_CREW * 4 //rock on
+ contains = list(/obj/item/storage/pill_bottle/naturalbait)
+
/datum/supply_pack/goody/telescopic_fishing_rod
name = "Telescopic Fishing Rod"
desc = "A collapsible fishing rod that can fit within a backpack."
diff --git a/code/modules/cargo/markets/market_items/weapons.dm b/code/modules/cargo/markets/market_items/weapons.dm
index ee16daae7d502..052074a30b38d 100644
--- a/code/modules/cargo/markets/market_items/weapons.dm
+++ b/code/modules/cargo/markets/market_items/weapons.dm
@@ -73,3 +73,12 @@
price_max = CARGO_CRATE_VALUE * 4
stock_max = 1
availability_prob = 75
+
+/datum/market_item/weapon/dimensional_bomb
+ name = "Multi-Dimensional Bomb Core"
+ desc = "A special bomb core, one of a kind, for all your 'terraforming gone wrong' purposes."
+ item = /obj/item/bombcore/dimensional
+ price_min = CARGO_CRATE_VALUE * 40
+ price_max = CARGO_CRATE_VALUE * 50
+ stock_max = 1
+ availability_prob = 15
diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm
index 7edfe9e2a9cf8..fae1e405d3fb2 100644
--- a/code/modules/cargo/packs/imports.dm
+++ b/code/modules/cargo/packs/imports.dm
@@ -71,13 +71,6 @@
crate_name = "bananium sheet crate"
discountable = SUPPLY_PACK_RARE_DISCOUNTABLE
-/datum/supply_pack/imports/naturalbait
- name = "Freshness Jars full of Natural Bait"
- desc = "Homemade in the Spinward Sector."
- cost = 2000 //rock on
- contains = list(/obj/item/storage/pill_bottle/naturalbait)
- crate_name = "fishing bait crate"
-
/datum/supply_pack/imports/dumpstercorpse
name = "A....Dumpster?"
desc = "Why does it smell so bad...."
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index e8338f4c95b19..0b0a6fb4d50cb 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -135,6 +135,15 @@
strip_delay = 60
dog_fashion = null
+/obj/item/clothing/head/soft/veteran
+ name = "veteran cap"
+ desc = "It's a robust baseball hat in tasteful black colour with a golden connotation to \"REMEMBER\"."
+ icon_state = "veteransoft"
+ soft_type = "veteran"
+ armor_type = /datum/armor/cosmetic_sec
+ strip_delay = 60
+ dog_fashion = null
+
/obj/item/clothing/head/soft/paramedic
name = "paramedic cap"
desc = "It's a baseball hat with a dark turquoise color and a reflective cross on the top."
diff --git a/code/modules/events/ghost_role/fugitive_event.dm b/code/modules/events/ghost_role/fugitive_event.dm
index 1556eb045589d..4b86e751c0b98 100644
--- a/code/modules/events/ghost_role/fugitive_event.dm
+++ b/code/modules/events/ghost_role/fugitive_event.dm
@@ -62,7 +62,7 @@
HUNTER_PACK_BOUNTY,
HUNTER_PACK_PSYKER,
)
- addtimer(CALLBACK(src, PROC_REF(spawn_hunters), hunter_backstory), 10 MINUTES)
+ addtimer(CALLBACK(src, PROC_REF(check_spawn_hunters), hunter_backstory, 10 MINUTES), 1 MINUTES)
role_name = "fugitive hunter"
return SUCCESSFUL_SPAWN
@@ -103,7 +103,13 @@
S.put_in_hands(A)
new /obj/item/autosurgeon(landing_turf)
-//security team gets called in after 10 minutes of prep to find the refugees
+/datum/round_event/ghost_role/fugitives/proc/check_spawn_hunters(backstory, remaining_time)
+ //if the emergency shuttle has been called, spawn hunters now to give them a chance
+ if(remaining_time == 0 || SSshuttle.emergency.mode != EMERGENCY_IDLE_OR_RECALLED)
+ spawn_hunters(backstory)
+ return
+ addtimer(CALLBACK(src, PROC_REF(check_spawn_hunters), backstory, remaining_time - 1 MINUTES), 1 MINUTES)
+
/datum/round_event/ghost_role/fugitives/proc/spawn_hunters(backstory)
var/list/candidates = SSpolling.poll_ghost_candidates("Do you wish to be considered for a group of [backstory]?", check_jobban = ROLE_FUGITIVE_HUNTER, pic_source = /obj/machinery/sleeper, role_name_text = backstory)
shuffle_inplace(candidates)
diff --git a/code/modules/jobs/job_types/station_trait/veteran_advisor.dm b/code/modules/jobs/job_types/station_trait/veteran_advisor.dm
new file mode 100644
index 0000000000000..87ad65c2c7a71
--- /dev/null
+++ b/code/modules/jobs/job_types/station_trait/veteran_advisor.dm
@@ -0,0 +1,76 @@
+/datum/job/veteran_advisor
+ title = JOB_VETERAN_ADVISOR
+ description = "Advise HoS, and Captain on matters of Security. Train green Officers. \
+ Lay back in your wheelchair and say \"I told you\" to the HoS when all of the station collapses."
+ auto_deadmin_role_flags = DEADMIN_POSITION_SECURITY
+ department_head = list(JOB_HEAD_OF_SECURITY)
+ faction = FACTION_STATION
+ total_positions = 0
+ spawn_positions = 0
+ supervisors = SUPERVISOR_HOS
+ minimal_player_age = 7
+ exp_requirements = 6000 //100 HOURS! We want really hard boiled people
+ exp_required_type = EXP_TYPE_CREW
+ exp_required_type_department = EXP_TYPE_SECURITY
+ exp_granted_type = EXP_TYPE_CREW
+ config_tag = "VETERAN_ADVISOR"
+
+ outfit = /datum/outfit/job/veteran_advisor
+ plasmaman_outfit = /datum/outfit/plasmaman/security
+
+ paycheck = PAYCHECK_CREW
+ paycheck_department = ACCOUNT_SEC
+
+ liver_traits = list(TRAIT_LAW_ENFORCEMENT_METABOLISM)
+
+ display_order = JOB_DISPLAY_ORDER_VETERAN_ADVISOR
+ departments_list = list(/datum/job_department/security)
+
+ family_heirlooms = list(/obj/item/plaque)
+
+ mail_goodies = list(
+ /obj/item/clothing/accessory/medal/conduct = 1,
+ /obj/item/instrument/trumpet = 5,
+ /obj/item/storage/fancy/cigarettes/cigars = 10,
+ )
+ rpg_title = "Royal Advisor"
+ allow_bureaucratic_error = FALSE
+ job_flags = STATION_JOB_FLAGS | STATION_TRAIT_JOB_FLAGS
+
+/datum/job/veteran_advisor/get_roundstart_spawn_point() //Spawning at Brig where Officers spawn
+ if (length(GLOB.start_landmarks_list["Security Officer"]))
+ return pick(GLOB.start_landmarks_list["Security Officer"])
+ return ..()
+
+/datum/job/veteran_advisor/after_spawn(mob/living/spawned, client/player_client)
+ . = ..()
+ var/mob/living/carbon/veteran = spawned
+ spawned.add_quirk(/datum/quirk/paraplegic) //Even in 2300s veterans are getting it bad
+ if(veteran)
+ veteran.gain_trauma(/datum/brain_trauma/special/ptsd) //War, war never changes...
+
+/datum/outfit/job/veteran_advisor
+ name = "Veteran Security Advisor"
+ jobtype = /datum/job/veteran_advisor
+
+ id_trim = /datum/id_trim/job/veteran_advisor
+ backpack_contents = list(
+ /obj/item/modular_computer/pda/veteran_advisor = 1,
+ /obj/item/storage/fancy/cigarettes/cigars = 1,
+ /obj/item/lighter = 1,
+ /obj/item/clothing/accessory/medal/bronze_heart = 1,
+ )
+
+ uniform = /obj/item/clothing/under/rank/security/officer/formal
+ head = /obj/item/clothing/head/soft/veteran
+ mask = /obj/item/clothing/mask/cigarette/cigar
+ suit = /obj/item/clothing/suit/jacket/trenchcoat
+ belt = /obj/item/storage/belt/holster/detective/full/ert //M1911 pistol
+ ears = /obj/item/radio/headset/heads/hos/advisor
+ glasses = /obj/item/clothing/glasses/eyepatch
+ shoes = /obj/item/clothing/shoes/jackboots
+ l_pocket = /obj/item/coin/antagtoken
+ r_pocket = /obj/item/melee/baton/telescopic
+ r_hand = /obj/item/cane
+
+ implants = list(/obj/item/implant/mindshield)
diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm
index 66c0d12996299..89eedd7cb5593 100644
--- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm
+++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm
@@ -25,10 +25,6 @@
response_harm_continuous = "squashes"
response_harm_simple = "squash"
- mob_size = MOB_SIZE_LARGE
- pixel_x = -16
- base_pixel_x = -16
-
speed = 1
maxHealth = 10
health = 10
@@ -110,9 +106,13 @@
beegent = null
if(flags_1 & HOLOGRAM_1 || gibbed)
return ..()
- new /obj/item/trash/bee(loc, src)
+ spawn_corpse()
return ..()
+/// Leave something to remember us by
+/mob/living/basic/bee/proc/spawn_corpse()
+ new /obj/item/trash/bee(loc, src)
+
/mob/living/basic/bee/proc/pre_attack(mob/living/puncher, atom/target)
SIGNAL_HANDLER
@@ -217,12 +217,20 @@
var/datum/reagent/toxin = pick(typesof(/datum/reagent/toxin))
assign_reagent(GLOB.chemical_reagents_list[toxin])
-/mob/living/basic/bee/short
- desc = "These bees seem unstable and won't survive for long."
+/// A bee which despawns after a short amount of time (beespawns?)
+/mob/living/basic/bee/timed
+ /// How long do we live?
+ var/lifespan = 50 SECONDS
+
+/mob/living/basic/bee/timed/short
+ lifespan = 25 SECONDS
-/mob/living/basic/bee/short/Initialize(mapload, timetolive=50 SECONDS)
+/mob/living/basic/bee/timed/Initialize(mapload)
. = ..()
- addtimer(CALLBACK(src, PROC_REF(death)), timetolive)
+ addtimer(CALLBACK(src, PROC_REF(death)), lifespan)
+
+/mob/living/basic/bee/timed/spawn_corpse()
+ new /obj/effect/temp_visual/despawn_effect(get_turf(src), /* copy_from = */ src)
/obj/item/queen_bee
name = "queen bee"
diff --git a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm
index 7b1e461991ce7..f0de6c3272e55 100644
--- a/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm
+++ b/code/modules/mob/living/basic/lavaland/hivelord/hivelord.dm
@@ -110,5 +110,5 @@
/mob/living/basic/hivelord_brood/death(gibbed)
if (!gibbed)
- new /obj/effect/temp_visual/hive_spawn_wither(get_turf(src), /* copy_from = */ src)
+ new /obj/effect/temp_visual/despawn_effect(get_turf(src), /* copy_from = */ src)
return ..()
diff --git a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm
index 7cc5ea06ad8b6..96c7319380a2e 100644
--- a/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm
+++ b/code/modules/mob/living/basic/lavaland/legion/legion_brood.dm
@@ -42,7 +42,7 @@
/mob/living/basic/legion_brood/death(gibbed)
if (!gibbed)
- new /obj/effect/temp_visual/hive_spawn_wither(get_turf(src), /* copy_from = */ src)
+ new /obj/effect/temp_visual/despawn_effect(get_turf(src), /* copy_from = */ src)
return ..()
/mob/living/basic/legion_brood/melee_attack(mob/living/target, list/modifiers, ignore_cooldown)
diff --git a/code/modules/mob/living/carbon/alien/organs.dm b/code/modules/mob/living/carbon/alien/organs.dm
index 66f555b639a88..9303cd2347413 100644
--- a/code/modules/mob/living/carbon/alien/organs.dm
+++ b/code/modules/mob/living/carbon/alien/organs.dm
@@ -197,23 +197,13 @@
for(var/atom/movable/thing as anything in stomach_contents)
if(!digestable_cache[thing.type])
continue
- thing.reagents.trans_to(src, 4)
-
- if(isliving(thing))
- var/mob/living/lad = thing
- lad.adjustBruteLoss(6)
- else if(!thing.reagents.total_volume) // Mobs can't get dusted like this, too important
- qdel(thing)
+ thing.acid_act(75, 10)
/obj/item/organ/internal/stomach/alien/proc/consume_thing(atom/movable/thing)
RegisterSignal(thing, COMSIG_MOVABLE_MOVED, PROC_REF(content_moved))
RegisterSignal(thing, COMSIG_QDELETING, PROC_REF(content_deleted))
if(isliving(thing))
- var/mob/living/lad = thing
RegisterSignal(thing, COMSIG_LIVING_DEATH, PROC_REF(content_died))
- if(lad.stat == DEAD)
- qdel(lad)
- return
stomach_contents += thing
thing.forceMove(owner || src) // We assert that if we have no owner, we will not be nullspaced
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 84fe6dd5edf41..ec03414abfcd2 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -85,7 +85,7 @@
span_userdanger("You violently crash into [victim][extra_speed ? " extra hard" : ""], but [victim] managed to block the worst of it!"))
log_combat(src, victim, "crashed into and was blocked by")
return
- else if(HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED))
+ else if(HAS_TRAIT(victim, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED))
victim.take_bodypart_damage(10 + 5 * extra_speed, check_armor = TRUE, wound_bonus = extra_speed * 5)
victim.apply_damage(10 + 10 * extra_speed, STAMINA)
victim.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH * 2, 10 SECONDS)
diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
index 4de716fe953d0..1f371d575ac1e 100644
--- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm
+++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm
@@ -42,9 +42,7 @@
ai_controlled_species = TRUE
/datum/species/monkey/random_name(gender,unique,lastname)
- var/randname = "monkey ([rand(1,999)])"
-
- return randname
+ return "monkey ([rand(1, 999)])"
/datum/species/monkey/on_species_gain(mob/living/carbon/human/H, datum/species/old_species)
. = ..()
@@ -170,7 +168,7 @@
/obj/item/organ/internal/brain/primate/on_mob_insert(mob/living/carbon/primate)
. = ..()
- RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed), TRUE)
+ RegisterSignal(primate, COMSIG_MOVABLE_CROSS, PROC_REF(on_crossed))
/obj/item/organ/internal/brain/primate/on_mob_remove(mob/living/carbon/primate)
. = ..()
@@ -185,11 +183,13 @@
var/mob/living/in_the_way_mob = crossed
if(iscarbon(in_the_way_mob) && !in_the_way_mob.combat_mode)
return
- if(in_the_way_mob.pass_flags & PASSTABLE)
+ if(in_the_way_mob.pass_flags & PASSMOB)
return
in_the_way_mob.knockOver(owner)
/obj/item/organ/internal/brain/primate/get_attacking_limb(mob/living/carbon/human/target)
- return owner.get_bodypart(BODY_ZONE_HEAD)
+ if(!HAS_TRAIT(owner, TRAIT_ADVANCEDTOOLUSER))
+ return owner.get_bodypart(BODY_ZONE_HEAD)
+ return ..()
#undef MONKEY_SPEC_ATTACK_BITE_MISS_CHANCE
diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm
index f0f3516ae7e0e..562c54ae0b758 100644
--- a/code/modules/mob/living/living_defense.dm
+++ b/code/modules/mob/living/living_defense.dm
@@ -547,7 +547,7 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(cult_ending_helper), CULT_VICTORY_MASS_CONVERSION), 120)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(ending_helper)), 270)
if(client)
- makeNewConstruct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE)
+ make_new_construct(/mob/living/basic/construct/harvester, src, cultoverride = TRUE)
else
switch(rand(1, 4))
if(1)
diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm
index 041d964f5dc50..a7d5b08579930 100644
--- a/code/modules/mob/living/silicon/ai/ai.dm
+++ b/code/modules/mob/living/silicon/ai/ai.dm
@@ -699,7 +699,7 @@
if("Station Member")
var/list/personnel_list = list()
- for(var/datum/record/crew/record in GLOB.manifest.locked)//Look in data core locked.
+ for(var/datum/record/locked/record in GLOB.manifest.locked)//Look in data core locked.
personnel_list["[record.name]: [record.rank]"] = record.character_appearance//Pull names, rank, and image.
if(!length(personnel_list))
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 9253448563b2d..ac9031f59c33f 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -356,8 +356,7 @@
/obj/machinery/anomalous_crystal/theme_warp/Initialize(mapload)
. = ..()
- var/terrain_type = pick(subtypesof(/datum/dimension_theme))
- terrain_theme = new terrain_type()
+ terrain_theme = SSmaterials.dimensional_themes[pick(subtypesof(/datum/dimension_theme))]
observer_desc = "This crystal changes the area around it to match the theme of \"[terrain_theme.name]\"."
/obj/machinery/anomalous_crystal/theme_warp/ActivationReaction(mob/user, method)
@@ -372,7 +371,7 @@
return TRUE
/obj/machinery/anomalous_crystal/theme_warp/Destroy()
- QDEL_NULL(terrain_theme)
+ terrain_theme = null
converted_areas.Cut()
return ..()
diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm
index 8c6ebe114965b..d2b8ce0f3c380 100644
--- a/code/modules/mob/mob_helpers.dm
+++ b/code/modules/mob/mob_helpers.dm
@@ -391,7 +391,7 @@
///Can the mob hear
/mob/proc/can_hear()
- . = TRUE
+ return !HAS_TRAIT(src, TRAIT_DEAF)
/**
* Examine text for traits shared by multiple types.
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 2403ca2da53c3..acf943b540ee3 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -537,7 +537,9 @@
else
to_chat(src, span_warning("You are not Superman."))
return
-
+ balloon_alert(src, "moving up...")
+ if(!do_after(src, 1 SECONDS))
+ return
if(zMove(UP, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag))
to_chat(src, span_notice("You move upwards."))
@@ -561,7 +563,9 @@
return loc_atom.relaymove(src, DOWN)
var/ventcrawling_flag = HAS_TRAIT(src, TRAIT_MOVE_VENTCRAWLING) ? ZMOVE_VENTCRAWLING : 0
-
+ balloon_alert(src, "moving down...")
+ if(!do_after(src, 1 SECONDS))
+ return
if(zMove(DOWN, z_move_flags = ZMOVE_FLIGHT_FLAGS|ZMOVE_FEEDBACK|ventcrawling_flag))
to_chat(src, span_notice("You move down."))
return FALSE
diff --git a/code/modules/modular_computers/computers/item/role_tablet_presets.dm b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
index 904b9fc9837cd..205c6a0c422e5 100644
--- a/code/modules/modular_computers/computers/item/role_tablet_presets.dm
+++ b/code/modules/modular_computers/computers/item/role_tablet_presets.dm
@@ -429,6 +429,17 @@
/datum/computer_file/program/status,
)
+/obj/item/modular_computer/pda/veteran_advisor
+ name = "security advisor PDA"
+ greyscale_colors = "#EA3232#FFD700"
+ inserted_item = /obj/item/pen/fountain
+ starting_programs = list(
+ /datum/computer_file/program/records/security,
+ /datum/computer_file/program/crew_manifest,
+ /datum/computer_file/program/coupon, //veteran discount
+ /datum/computer_file/program/skill_tracker,
+ )
+
/**
* Non-roles
*/
diff --git a/code/modules/power/singularity/narsie.dm b/code/modules/power/singularity/narsie.dm
index 2de87210798d4..caba755eb81a7 100644
--- a/code/modules/power/singularity/narsie.dm
+++ b/code/modules/power/singularity/narsie.dm
@@ -147,7 +147,7 @@
start_ending_the_round()
/obj/narsie/attack_ghost(mob/user)
- makeNewConstruct(/mob/living/basic/construct/harvester, user, cultoverride = TRUE, loc_override = loc)
+ make_new_construct(/mob/living/basic/construct/harvester, user, cultoverride = TRUE, loc_override = loc)
/obj/narsie/process()
var/datum/component/singularity/singularity_component = singularity.resolve()
diff --git a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
index 8e74b0ad6f869..bc41e25090bf1 100644
--- a/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
+++ b/code/modules/reagents/chemistry/recipes/pyrotechnics.dm
@@ -194,7 +194,7 @@
beeagents += R
var/bee_amount = round(created_volume * 0.2)
for(var/i in 1 to bee_amount)
- var/mob/living/basic/bee/short/new_bee = new(location)
+ var/mob/living/basic/bee/timed/new_bee = new(location)
if(LAZYLEN(beeagents))
new_bee.assign_reagent(pick(beeagents))
@@ -419,7 +419,7 @@
determin_ph_range = 6
temp_exponent_factor = 0.5
ph_exponent_factor = 1
- thermic_constant = -7.5
+ thermic_constant = -1.5
H_ion_release = 0
rate_up_lim = 10
purity_min = 0.2
diff --git a/code/modules/surgery/bodyparts/parts.dm b/code/modules/surgery/bodyparts/parts.dm
index 776207a2ccee9..ead03aa0f707c 100644
--- a/code/modules/surgery/bodyparts/parts.dm
+++ b/code/modules/surgery/bodyparts/parts.dm
@@ -253,9 +253,9 @@
px_x = -5
px_y = -3
dmg_overlay_type = SPECIES_MONKEY
- unarmed_damage_low = 1 /// monkey punches must be really weak, considering they bite people instead and their bites are weak as hell.
- unarmed_damage_high = 2
- unarmed_effectiveness = 0
+ unarmed_damage_low = 3
+ unarmed_damage_high = 8
+ unarmed_effectiveness = 5
appendage_noun = "paw"
/obj/item/bodypart/arm/left/alien
@@ -351,8 +351,8 @@
px_x = 5
px_y = -3
dmg_overlay_type = SPECIES_MONKEY
- unarmed_damage_low = 1
- unarmed_damage_high = 2
+ unarmed_damage_low = 3
+ unarmed_damage_high = 8
unarmed_effectiveness = 0
appendage_noun = "paw"
@@ -468,8 +468,8 @@
dmg_overlay_type = SPECIES_MONKEY
unarmed_damage_low = 2
unarmed_damage_high = 3
- unarmed_effectiveness = 0
- footprint_sprite = FOOTPRINT_SPRITE_PAWS
+ unarmed_effectiveness = 5
+ footprint_sprite = FOOTPRINT_SPRITE_PAWS
/obj/item/bodypart/leg/left/alien
icon = 'icons/mob/human/species/alien/bodyparts.dmi'
@@ -559,8 +559,8 @@
dmg_overlay_type = SPECIES_MONKEY
unarmed_damage_low = 2
unarmed_damage_high = 3
- unarmed_effectiveness = 0
- footprint_sprite = FOOTPRINT_SPRITE_PAWS
+ unarmed_effectiveness = 5
+ footprint_sprite = FOOTPRINT_SPRITE_PAWS
/obj/item/bodypart/leg/right/alien
icon = 'icons/mob/human/species/alien/bodyparts.dmi'
diff --git a/code/modules/tgs/core/core.dm b/code/modules/tgs/core/core.dm
index 8be96f27404a4..15622228e91fe 100644
--- a/code/modules/tgs/core/core.dm
+++ b/code/modules/tgs/core/core.dm
@@ -166,3 +166,11 @@
var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
if(api)
return api.Visibility()
+
+/world/TgsTriggerEvent(event_name, list/parameters, wait_for_completion = FALSE)
+ var/datum/tgs_api/api = TGS_READ_GLOBAL(tgs)
+ if(api)
+ if(!istype(parameters, /list))
+ parameters = list()
+
+ return api.TriggerEvent(event_name, parameters, wait_for_completion)
diff --git a/code/modules/tgs/core/datum.dm b/code/modules/tgs/core/datum.dm
index 07ce3b684584e..898516f12486f 100644
--- a/code/modules/tgs/core/datum.dm
+++ b/code/modules/tgs/core/datum.dm
@@ -17,7 +17,7 @@ TGS_DEFINE_AND_SET_GLOBAL(tgs, null)
world.sleep_offline = FALSE // https://www.byond.com/forum/post/2894866
del(world)
world.sleep_offline = FALSE // just in case, this is BYOND after all...
- sleep(1)
+ sleep(world.tick_lag)
TGS_DEBUG_LOG("BYOND DIDN'T TERMINATE THE WORLD!!! TICK IS: [world.time], sleep_offline: [world.sleep_offline]")
/datum/tgs_api/latest
@@ -69,3 +69,6 @@ TGS_PROTECT_DATUM(/datum/tgs_api)
/datum/tgs_api/proc/Visibility()
return TGS_UNIMPLEMENTED
+
+/datum/tgs_api/proc/TriggerEvent(event_name, list/parameters, wait_for_completion)
+ return FALSE
diff --git a/code/modules/tgs/v4/api.dm b/code/modules/tgs/v4/api.dm
index 945e2e4117671..7c87922750b9b 100644
--- a/code/modules/tgs/v4/api.dm
+++ b/code/modules/tgs/v4/api.dm
@@ -181,7 +181,7 @@
var/json = json_encode(data)
while(requesting_new_port && !override_requesting_new_port)
- sleep(1)
+ sleep(world.tick_lag)
//we need some port open at this point to facilitate return communication
if(!world.port)
@@ -209,7 +209,7 @@
requesting_new_port = FALSE
while(export_lock)
- sleep(1)
+ sleep(world.tick_lag)
export_lock = TRUE
last_interop_response = null
@@ -217,7 +217,7 @@
text2file(json, server_commands_json_path)
for(var/I = 0; I < EXPORT_TIMEOUT_DS && !last_interop_response; ++I)
- sleep(1)
+ sleep(world.tick_lag)
if(!last_interop_response)
TGS_ERROR_LOG("Failed to get export result for: [json]")
diff --git a/code/modules/tgs/v5/__interop_version.dm b/code/modules/tgs/v5/__interop_version.dm
index 616263098fd3e..f4806f7adb97c 100644
--- a/code/modules/tgs/v5/__interop_version.dm
+++ b/code/modules/tgs/v5/__interop_version.dm
@@ -1 +1 @@
-"5.8.0"
+"5.9.0"
diff --git a/code/modules/tgs/v5/_defines.dm b/code/modules/tgs/v5/_defines.dm
index 1c7d67d20cdf6..92c7a8388a711 100644
--- a/code/modules/tgs/v5/_defines.dm
+++ b/code/modules/tgs/v5/_defines.dm
@@ -14,6 +14,7 @@
#define DMAPI5_BRIDGE_COMMAND_KILL 4
#define DMAPI5_BRIDGE_COMMAND_CHAT_SEND 5
#define DMAPI5_BRIDGE_COMMAND_CHUNK 6
+#define DMAPI5_BRIDGE_COMMAND_EVENT 7
#define DMAPI5_PARAMETER_ACCESS_IDENTIFIER "accessIdentifier"
#define DMAPI5_PARAMETER_CUSTOM_COMMANDS "customCommands"
@@ -34,6 +35,7 @@
#define DMAPI5_BRIDGE_PARAMETER_VERSION "version"
#define DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE "chatMessage"
#define DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL "minimumSecurityLevel"
+#define DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION "eventInvocation"
#define DMAPI5_BRIDGE_RESPONSE_NEW_PORT "newPort"
#define DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION "runtimeInformation"
@@ -81,6 +83,7 @@
#define DMAPI5_TOPIC_COMMAND_SEND_CHUNK 9
#define DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK 10
#define DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST 11
+#define DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT 12
#define DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE "commandType"
#define DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND "chatCommand"
@@ -116,3 +119,9 @@
#define DMAPI5_CUSTOM_CHAT_COMMAND_NAME "name"
#define DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT "helpText"
#define DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY "adminOnly"
+
+#define DMAPI5_EVENT_ID "eventId"
+
+#define DMAPI5_EVENT_INVOCATION_NAME "eventName"
+#define DMAPI5_EVENT_INVOCATION_PARAMETERS "parameters"
+#define DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION "notifyCompletion"
diff --git a/code/modules/tgs/v5/api.dm b/code/modules/tgs/v5/api.dm
index a5c064a8eaf1e..95b8edd3ee5c2 100644
--- a/code/modules/tgs/v5/api.dm
+++ b/code/modules/tgs/v5/api.dm
@@ -27,6 +27,8 @@
var/chunked_requests = 0
var/list/chunked_topics = list()
+ var/list/pending_events = list()
+
var/detached = FALSE
/datum/tgs_api/v5/New()
@@ -46,6 +48,10 @@
var/datum/tgs_version/api_version = ApiVersion()
version = null // we want this to be the TGS version, not the interop version
+
+ // sleep once to prevent an issue where world.Export on the first tick can hang indefinitely
+ sleep(world.tick_lag)
+
var/list/bridge_response = Bridge(DMAPI5_BRIDGE_COMMAND_STARTUP, list(DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL = minimum_required_security_level, DMAPI5_BRIDGE_PARAMETER_VERSION = api_version.raw_parameter, DMAPI5_PARAMETER_CUSTOM_COMMANDS = ListCustomCommands(), DMAPI5_PARAMETER_TOPIC_PORT = GetTopicPort()))
if(!istype(bridge_response))
TGS_ERROR_LOG("Failed initial bridge request!")
@@ -125,7 +131,7 @@
TGS_DEBUG_LOG("RequireInitialBridgeResponse: Starting sleep")
logged = TRUE
- sleep(1)
+ sleep(world.tick_lag)
TGS_DEBUG_LOG("RequireInitialBridgeResponse: Passed")
@@ -249,6 +255,40 @@
WaitForReattach(TRUE)
return chat_channels.Copy()
+/datum/tgs_api/v5/TriggerEvent(event_name, list/parameters, wait_for_completion)
+ RequireInitialBridgeResponse()
+ WaitForReattach(TRUE)
+
+ if(interop_version.minor < 9)
+ TGS_WARNING_LOG("Interop version too low for custom events!")
+ return FALSE
+
+ var/str_parameters = list()
+ for(var/i in parameters)
+ str_parameters += "[i]"
+
+ var/list/response = Bridge(DMAPI5_BRIDGE_COMMAND_EVENT, list(DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION = list(DMAPI5_EVENT_INVOCATION_NAME = event_name, DMAPI5_EVENT_INVOCATION_PARAMETERS = str_parameters, DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION = wait_for_completion)))
+ if(!response)
+ return FALSE
+
+ var/event_id = response[DMAPI5_EVENT_ID]
+ if(!event_id)
+ return FALSE
+
+ TGS_DEBUG_LOG("Created event ID: [event_id]")
+ if(!wait_for_completion)
+ return TRUE
+
+ TGS_DEBUG_LOG("Waiting for completion of event ID: [event_id]")
+
+ while(!pending_events[event_id])
+ sleep(world.tick_lag)
+
+ TGS_DEBUG_LOG("Completed wait on event ID: [event_id]")
+ pending_events -= event_id
+
+ return TRUE
+
/datum/tgs_api/v5/proc/DecodeChannels(chat_update_json)
TGS_DEBUG_LOG("DecodeChannels()")
var/list/chat_channels_json = chat_update_json[DMAPI5_CHAT_UPDATE_CHANNELS]
diff --git a/code/modules/tgs/v5/bridge.dm b/code/modules/tgs/v5/bridge.dm
index a0ab359876704..0c5e701a32b60 100644
--- a/code/modules/tgs/v5/bridge.dm
+++ b/code/modules/tgs/v5/bridge.dm
@@ -65,7 +65,7 @@
if(detached)
// Wait up to one minute
for(var/i in 1 to 600)
- sleep(1)
+ sleep(world.tick_lag)
if(!detached && (!require_channels || length(chat_channels)))
break
@@ -77,8 +77,11 @@
/datum/tgs_api/v5/proc/PerformBridgeRequest(bridge_request)
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)
+ TGS_DEBUG_LOG("Bridge request complete")
+
if(!export_response)
TGS_ERROR_LOG("Failed bridge request: [bridge_request]")
return
@@ -88,7 +91,7 @@
TGS_ERROR_LOG("Failed bridge request, missing content!")
return
- var/response_json = file2text(content)
+ var/response_json = TGS_FILE2TEXT_NATIVE(content)
if(!response_json)
TGS_ERROR_LOG("Failed bridge request, failed to load content!")
return
diff --git a/code/modules/tgs/v5/topic.dm b/code/modules/tgs/v5/topic.dm
index 05e6c4e1b2146..e1f2cb6385789 100644
--- a/code/modules/tgs/v5/topic.dm
+++ b/code/modules/tgs/v5/topic.dm
@@ -176,6 +176,10 @@
var/list/reattach_response = TopicResponse(error_message)
reattach_response[DMAPI5_PARAMETER_CUSTOM_COMMANDS] = ListCustomCommands()
reattach_response[DMAPI5_PARAMETER_TOPIC_PORT] = GetTopicPort()
+
+ for(var/eventId in pending_events)
+ pending_events[eventId] = TRUE
+
return reattach_response
if(DMAPI5_TOPIC_COMMAND_SEND_CHUNK)
@@ -276,6 +280,15 @@
TGS_WORLD_ANNOUNCE(message)
return TopicResponse()
+ if(DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT)
+ var/event_id = topic_parameters[DMAPI5_EVENT_ID]
+ if (!istext(event_id))
+ return TopicResponse("Invalid or missing [DMAPI5_EVENT_ID]")
+
+ TGS_DEBUG_LOG("Completing event ID [event_id]...")
+ pending_events[event_id] = TRUE
+ return TopicResponse()
+
return TopicResponse("Unknown command: [command]")
/datum/tgs_api/v5/proc/WorldBroadcast(message)
diff --git a/code/modules/tgs/v5/undefs.dm b/code/modules/tgs/v5/undefs.dm
index d531d4b7b9dd1..237207fdfd056 100644
--- a/code/modules/tgs/v5/undefs.dm
+++ b/code/modules/tgs/v5/undefs.dm
@@ -14,6 +14,7 @@
#undef DMAPI5_BRIDGE_COMMAND_KILL
#undef DMAPI5_BRIDGE_COMMAND_CHAT_SEND
#undef DMAPI5_BRIDGE_COMMAND_CHUNK
+#undef DMAPI5_BRIDGE_COMMAND_EVENT
#undef DMAPI5_PARAMETER_ACCESS_IDENTIFIER
#undef DMAPI5_PARAMETER_CUSTOM_COMMANDS
@@ -34,6 +35,7 @@
#undef DMAPI5_BRIDGE_PARAMETER_VERSION
#undef DMAPI5_BRIDGE_PARAMETER_CHAT_MESSAGE
#undef DMAPI5_BRIDGE_PARAMETER_MINIMUM_SECURITY_LEVEL
+#undef DMAPI5_BRIDGE_PARAMETER_EVENT_INVOCATION
#undef DMAPI5_BRIDGE_RESPONSE_NEW_PORT
#undef DMAPI5_BRIDGE_RESPONSE_RUNTIME_INFORMATION
@@ -81,6 +83,7 @@
#undef DMAPI5_TOPIC_COMMAND_SEND_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_CHUNK
#undef DMAPI5_TOPIC_COMMAND_RECEIVE_BROADCAST
+#undef DMAPI5_TOPIC_COMMAND_COMPLETE_EVENT
#undef DMAPI5_TOPIC_PARAMETER_COMMAND_TYPE
#undef DMAPI5_TOPIC_PARAMETER_CHAT_COMMAND
@@ -116,3 +119,9 @@
#undef DMAPI5_CUSTOM_CHAT_COMMAND_NAME
#undef DMAPI5_CUSTOM_CHAT_COMMAND_HELP_TEXT
#undef DMAPI5_CUSTOM_CHAT_COMMAND_ADMIN_ONLY
+
+#undef DMAPI5_EVENT_ID
+
+#undef DMAPI5_EVENT_INVOCATION_NAME
+#undef DMAPI5_EVENT_INVOCATION_PARAMETERS
+#undef DMAPI5_EVENT_INVOCATION_NOTIFY_COMPLETION
diff --git a/code/modules/transport/linear_controller.dm b/code/modules/transport/linear_controller.dm
index dd90562deb643..80c161c32918d 100644
--- a/code/modules/transport/linear_controller.dm
+++ b/code/modules/transport/linear_controller.dm
@@ -35,6 +35,9 @@
///if true, the platform cannot be manually moved.
var/controls_locked = FALSE
+ /// probability of being thrown hard during an emergency stop
+ var/throw_chance = 17.5
+
/datum/transport_controller/linear/New(obj/structure/transport/linear/transport_module)
transport_id = transport_module.transport_id
create_modular_set = transport_module.create_modular_set
diff --git a/code/modules/transport/tram/tram_controller.dm b/code/modules/transport/tram/tram_controller.dm
index c7fc895184fe8..4dceecbfc4c26 100644
--- a/code/modules/transport/tram/tram_controller.dm
+++ b/code/modules/transport/tram/tram_controller.dm
@@ -17,17 +17,15 @@
var/travel_remaining = 0
///how far in total we'll be travelling
var/travel_trip_length = 0
-
///multiplier on how much damage/force the tram imparts on things it hits
var/collision_lethality = 1
- var/obj/effect/landmark/transport/nav_beacon/tram/nav/nav_beacon
- /// reference to the destination landmarks we consider ourselves "at" or travelling towards. since we potentially span multiple z levels we dont actually
+ /// reference to the navigation landmark associated with this tram. since we potentially span multiple z levels we dont actually
/// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this
/// and the destination landmark.
+ var/obj/effect/landmark/transport/nav_beacon/tram/nav/nav_beacon
+ /// reference to the landmark we consider ourself stationary at.
var/obj/effect/landmark/transport/nav_beacon/tram/platform/idle_platform
- /// reference to the destination landmarks we consider ourselves travelling towards. since we potentially span multiple z levels we dont actually
- /// know where on us this platform is. as long as we know THAT its on us we can just move the distance and direction between this
- /// and the destination landmark.
+ /// reference to the destination landmark we consider ourselves travelling towards.
var/obj/effect/landmark/transport/nav_beacon/tram/platform/destination_platform
var/current_speed = 0
@@ -284,7 +282,11 @@
degraded_stop()
return PROCESS_KILL
- normal_stop()
+ if((controller_status & COMM_ERROR) && prob(5)) // malfunctioning tram has a small chance to e-stop
+ degraded_stop()
+ else
+ normal_stop()
+
return PROCESS_KILL
else if(world.time >= scheduled_move)
@@ -538,7 +540,8 @@
set_status_code(COMM_ERROR, TRUE)
SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, FALSE)
paired_cabinet.generate_repair_signals()
- collision_lethality = 1.25
+ collision_lethality *= 1.25
+ throw_chance *= 1.25
log_transport("TC: [specific_transport_id] starting Tram Malfunction event.")
/**
@@ -553,6 +556,7 @@
set_status_code(COMM_ERROR, FALSE)
paired_cabinet.clear_repair_signals()
collision_lethality = initial(collision_lethality)
+ throw_chance = initial(throw_chance)
SEND_TRANSPORT_SIGNAL(COMSIG_COMMS_STATUS, src, TRUE)
log_transport("TC: [specific_transport_id] ending Tram Malfunction event.")
diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm
index c33d729e75c0d..9fdfefc835cae 100644
--- a/code/modules/transport/transport_module.dm
+++ b/code/modules/transport/transport_module.dm
@@ -934,7 +934,8 @@
/obj/structure/transport/linear/tram/proc/estop_throw(throw_direction)
for(var/mob/living/passenger in transport_contents)
to_chat(passenger, span_userdanger("The tram comes to a sudden, grinding stop!"))
- if(prob(17.5)) // sometimes you go through a window
+ var/mob_throw_chance = transport_controller_datum.throw_chance
+ if(prob(mob_throw_chance || 17.5) || HAS_TRAIT(passenger, TRAIT_CURSED)) // sometimes you go through a window, especially with bad luck
passenger.AddElement(/datum/element/window_smashing, duration = 1.5 SECONDS)
var/throw_target = get_edge_target_turf(src, throw_direction)
passenger.throw_at(throw_target, 30, 7, force = MOVE_FORCE_OVERPOWERING)
diff --git a/code/modules/vending/_vending.dm b/code/modules/vending/_vending.dm
index 3c544552d512a..f101c5b2f7486 100644
--- a/code/modules/vending/_vending.dm
+++ b/code/modules/vending/_vending.dm
@@ -821,7 +821,7 @@
post_crush_living(living_target, was_alive)
flags_to_return |= (SUCCESSFULLY_CRUSHED_MOB|SUCCESSFULLY_CRUSHED_ATOM)
- else if (atom_target.uses_integrity && !(atom_target.invisibility > SEE_INVISIBLE_LIVING) && !(is_type_in_typecache(atom_target, GLOB.WALLITEMS_INTERIOR) || is_type_in_typecache(atom_target, GLOB.WALLITEMS_EXTERIOR)))
+ else if(check_atom_crushable(atom_target))
atom_target.take_damage(adjusted_damage, damage_type, damage_flag, FALSE, crush_dir)
crushed = TRUE
flags_to_return |= SUCCESSFULLY_CRUSHED_ATOM
@@ -861,6 +861,21 @@
/atom/movable/proc/post_tilt()
return
+/proc/check_atom_crushable(atom/atom_target)
+ /// Contains structures and items that vendors shouldn't crush when we land on them.
+ var/static/list/vendor_uncrushable_objects = list(
+ /obj/structure/chair,
+ /obj/machinery/conveyor,
+ ) + GLOB.WALLITEMS_INTERIOR + GLOB.WALLITEMS_EXTERIOR
+
+ if(is_type_in_list(atom_target, vendor_uncrushable_objects)) //make sure its not in the list of "uncrushable" stuff
+ return FALSE
+
+ if (atom_target.uses_integrity && !(atom_target.invisibility > SEE_INVISIBLE_LIVING)) //check if it has integrity + allow ninjas, etc to be crushed in cloak
+ return TRUE //SMUSH IT
+
+ return FALSE
+
/obj/machinery/vending/post_crush_living(mob/living/crushed, was_alive)
if(was_alive && crushed.stat == DEAD && crushed.client)
diff --git a/config/arenas/README.md b/config/arenas/README.md
deleted file mode 100644
index 9f31ce2349a93..0000000000000
--- a/config/arenas/README.md
+++ /dev/null
@@ -1,3 +0,0 @@
-Add admin arena dmms here.
-
-**These are fully cached so keep this directory empty by default.**
\ No newline at end of file
diff --git a/config/jobconfig.toml b/config/jobconfig.toml
index c8a5c5c3dfa5d..7106d2f2a4ef5 100644
--- a/config/jobconfig.toml
+++ b/config/jobconfig.toml
@@ -263,6 +263,13 @@
"# Spawn Positions" = 5
"# Total Positions" = 5
+[VETERAN_ADVISOR]
+"# Playtime Requirements" = 6000
+"# Required Account Age" = 7
+"# Required Character Age" = 0
+"# Spawn Positions" = 0
+"# Total Positions" = 0
+
[VIROLOGIST]
"# Playtime Requirements" = 60
"# Required Account Age" = 0
diff --git a/html/changelogs/AutoChangeLog-pr-81540.yml b/html/changelogs/AutoChangeLog-pr-81540.yml
deleted file mode 100644
index 5157e6ceeb2aa..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81540.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "IndieanaJones"
-delete-after: True
-changes:
- - balance: "Gorillas are faster, stronger, but not bigger too. Note while holding an item, they are the same speed as they were prior."
- - balance: "Gorillas now have the understanding of languages as monkeys do."
- - balance: "The Gorilla Cube Box for traitors has been replaced with a singular gorilla cube. Due to the aforementioned changes, this singular gorilla should be as scary if not scarier than 3 gorillas were prior."
- - balance: " Magillitis Serum Autoinjector now grants the resulting gorilla a slow passive regeneration effect which kicks in after not taking damage for 12 seconds."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81596.yml b/html/changelogs/AutoChangeLog-pr-81596.yml
deleted file mode 100644
index fdd8366297830..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81596.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Melbert"
-delete-after: True
-changes:
- - bugfix: "The Paddy's Claw should be properly unusable in situations which it should be properly unusable."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81599.yml b/html/changelogs/AutoChangeLog-pr-81599.yml
deleted file mode 100644
index 84bf337648e9f..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81599.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "TJatPBnJ"
-delete-after: True
-changes:
- - balance: "Power crepes are now finger food"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81605.yml b/html/changelogs/AutoChangeLog-pr-81605.yml
deleted file mode 100644
index 7f6f91ac658e2..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81605.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "ArcaneMusic"
-delete-after: True
-changes:
- - bugfix: "Fixed instances where holochip/holocredits would spawn with a total of zero credits contained within."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81627.yml b/html/changelogs/AutoChangeLog-pr-81627.yml
deleted file mode 100644
index 8961474bf7f5d..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81627.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "vinylspiders"
-delete-after: True
-changes:
- - bugfix: "fixes cardboard cutouts not updating when held and using the crayon on them to change their appearance, and fixes the alt_appearance being added to the cutout instead of the mob holding it"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81629.yml b/html/changelogs/AutoChangeLog-pr-81629.yml
deleted file mode 100644
index d7c9aa58f9c5c..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81629.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "mc-oofert"
-delete-after: True
-changes:
- - rscadd: "Added an option to deathmatch loadout dropdown that allows you to pick a random loadout"
- - bugfix: "In deathmatch, plasmamen are made humans and the UI supports more players"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81637.yml b/html/changelogs/AutoChangeLog-pr-81637.yml
deleted file mode 100644
index 1e735fde35982..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81637.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "00-Steven"
-delete-after: True
-changes:
- - bugfix: "Medical/security records now show an icon based on the registered trim, rather than showing a question mark for records with customized titles."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81638.yml b/html/changelogs/AutoChangeLog-pr-81638.yml
deleted file mode 100644
index c6d7b9e46333d..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81638.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "00-Steven"
-delete-after: True
-changes:
- - bugfix: "Newscasters no longer say \"No wanted issue posted. Have a secure day.\" when there is, in fact, an active wanted issue currently posted."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81641.yml b/html/changelogs/AutoChangeLog-pr-81641.yml
deleted file mode 100644
index 37efab9484f10..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81641.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: "JohnFulpWillard"
-delete-after: True
-changes:
- - qol: "You can use atmos machines, holopads, crayons, spray cans, and disposal bins while floored."
- - bugfix: "You can close extinguisher cabinets while floored."
- - bugfix: "You can climb onto a photocopier from the floor."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81661.yml b/html/changelogs/AutoChangeLog-pr-81661.yml
deleted file mode 100644
index 13a28048d7be8..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81661.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Singul0"
-delete-after: True
-changes:
- - bugfix: "The say TGUI would recognize :g (changeling hivemind) prefix. and give a visual indicator in it that you are talking in the right channel"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81662.yml b/html/changelogs/AutoChangeLog-pr-81662.yml
deleted file mode 100644
index ab75566b57e30..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81662.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "13spacemen"
-delete-after: True
-changes:
- - bugfix: "Blood overlays on items no longer leak onto other objects"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81671.yml b/html/changelogs/AutoChangeLog-pr-81671.yml
deleted file mode 100644
index 853a56fb32e7a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81671.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ben10Omintrix"
-delete-after: True
-changes:
- - bugfix: "fixes pokemon ai still being active when inside the pokeball"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-81684.yml b/html/changelogs/AutoChangeLog-pr-81684.yml
deleted file mode 100644
index d75725dd9ce89..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-81684.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "mc-oofert"
-delete-after: True
-changes:
- - bugfix: "You may no longer make deathmatch arenas dark with a lightswitch."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-02.yml b/html/changelogs/archive/2024-02.yml
index 3209584f8c161..e98a9540d4a2b 100644
--- a/html/changelogs/archive/2024-02.yml
+++ b/html/changelogs/archive/2024-02.yml
@@ -732,3 +732,137 @@
- rscadd: A new module, the Safety-First Head Protection module, protects you from
head trauma! Available in most modsuits expected to take hits to the head often.
And from roundstart exofabricators.
+2024-02-27:
+ 00-Steven:
+ - bugfix: Newscasters no longer say "No wanted issue posted. Have a secure day."
+ when there is, in fact, an active wanted issue currently posted.
+ - bugfix: Medical/security records now show an icon based on the registered trim,
+ rather than showing a question mark for records with customized titles.
+ 13spacemen:
+ - bugfix: Blood overlays on items no longer leak onto other objects
+ Absolucy:
+ - qol: Constructs now reuse the victim's mind instead of just moving their client
+ ArcaneMusic:
+ - bugfix: Fixed instances where holochip/holocredits would spawn with a total of
+ zero credits contained within.
+ Ben10Omintrix:
+ - bugfix: fixes pokemon ai still being active when inside the pokeball
+ Iamgoofball:
+ - balance: Adds a 1 second delay to moving up and down with the verb/keybinds to
+ disable z-level combat cheese
+ IndieanaJones:
+ - balance: Gorillas are faster, stronger, but not bigger too. Note while holding
+ an item, they are the same speed as they were prior.
+ - balance: Gorillas now have the understanding of languages as monkeys do.
+ - balance: The Gorilla Cube Box for traitors has been replaced with a singular gorilla
+ cube. Due to the aforementioned changes, this singular gorilla should be as
+ scary if not scarier than 3 gorillas were prior.
+ - balance: ' Magillitis Serum Autoinjector now grants the resulting gorilla a slow
+ passive regeneration effect which kicks in after not taking damage for 12 seconds.'
+ JohnFulpWillard:
+ - qol: You can use atmos machines, holopads, crayons, spray cans, and disposal bins
+ while floored.
+ - bugfix: You can close extinguisher cabinets while floored.
+ - bugfix: You can climb onto a photocopier from the floor.
+ Melbert:
+ - bugfix: The Paddy's Claw should be properly unusable in situations which it should
+ be properly unusable.
+ Singul0:
+ - bugfix: The say TGUI would recognize :g (changeling hivemind) prefix. and give
+ a visual indicator in it that you are talking in the right channel
+ SyncIt21:
+ - qol: adds examines & screentips for building & deconstructing both machine & computer
+ frames.
+ - qol: Adding a circuitboard from a rped to n computer frame will automatically
+ screw it in place like before.
+ - code_imp: merged procs for computer & machine frames. autodocs them where possible.
+ - code_imp: moved code for machine frame into its own file.
+ - bugfix: RCD converts miscellaneous turfs like basalt, sand, beach etc to plating
+ first & not put a wall directly on top of them
+ TJatPBnJ:
+ - balance: Power crepes are now finger food
+ mc-oofert:
+ - bugfix: You may no longer make deathmatch arenas dark with a lightswitch.
+ - rscadd: Added an option to deathmatch loadout dropdown that allows you to pick
+ a random loadout
+ - bugfix: In deathmatch, plasmamen are made humans and the UI supports more players
+ vinylspiders:
+ - bugfix: fixes cardboard cutouts not updating when held and using the crayon on
+ them to change their appearance, and fixes the alt_appearance being added to
+ the cutout instead of the mob holding it
+2024-02-28:
+ 00-Steven:
+ - bugfix: Lobby manifest shows the head/captain symbols next to heads and captains
+ with custom titles, as long as they're registered with a head/captain trim.
+ - bugfix: Fixed Bluespace RPEDs failing to apply circuits from a distance if you
+ had to select between multiple.
+ ArcaneMusic:
+ - image: New sprites for plant grafts!
+ Cheshify:
+ - bugfix: the north star's main intersections are brighter, the elevator is properly
+ lit, and a single floating poster was moved.
+ - qol: The chapel has been slightly overhauled on Birdshot, with the chaplain now
+ having a place to preach sermons.
+ - bugfix: Sparring chaplains are now able to operate on Birdshot!
+ DrDiasyl:
+ - rscadd: 'NEW TRAIT JOB: Veteran Security Advisor! Advise HoS and Captain on Security
+ matters, mentor Security Officers. Note that they are paraplegic and are suffering
+ PTSD due to their past experience.'
+ Ghommie:
+ - rscadd: Added a multi-dimensional bomb payload to the black market. It's very
+ expensive.
+ - balance: '"Freshness Jars full of Natural Bait" is now a goodie and costs 200
+ credits instead of 2000'
+ Iamgoofball:
+ - balance: xenomorph stomachs will no longer destroy items directly, refactored
+ it to use acid_act()
+ - bugfix: fixes xenomorph vore accidentally destroying mobs it wasn't supposed to
+ destroy, im thinking this was modified list in place shenanigans
+ IndieanaJones:
+ - rscadd: 'New Changeling Ability: Hive Head'
+ - bugfix: Fixed bees having an improper sprite offset
+ Jacquerel:
+ - rscadd: Displaying the voting statistics is now optional on a per-poll basis,
+ and is disabled for map voting.
+ JohnFulpWillard:
+ - qol: Intelligent monkeys now punch people instead of biting them.
+ KingkumaArt:
+ - rscadd: a list of items called vendor_nocrush that vendors dont deal integrity
+ damage to upon hitting them.
+ - bugfix: Makes vending machines no longer crush chairs and conveyors.
+ LT3:
+ - code_imp: Tram throwing now breaks grilles consistently
+ - code_imp: Tram malfunction lethality/throw chance are now a multiplier instead
+ of flat value
+ - code_imp: Tram throw chance can be adjusted
+ - code_imp: Unlucky trait is now used in tram throw calculation
+ Melbert:
+ - bugfix: Rat hearts apply their damage modifier malus correctly
+ PapaMichael:
+ - balance: Fugitive hunters will spawn early if the emergency shuttle is called.
+ softcerv:
+ - code_imp: TRAIT_DEAF now works on non-carbon mobs
+2024-02-29:
+ 13spacemen:
+ - bugfix: You can build material airlocks again
+ A.C.M.O.:
+ - bugfix: Fixed the AI hologram's ability to copy the appearance of crew members.
+ Jacquerel:
+ - image: adds a visual effect for hive head bees despawning
+ Momo8289:
+ - bugfix: Fixes the slot machine's jackpot. It should now give all of the available
+ prize money + 10,000 credits as payout for a jackpot.
+ - refactor: Converts the slot machine's UI over to TGUI
+ - rscadd: The slot machine now has a whole new type of jackpot! This one's a banger!
+ SyncIt21:
+ - bugfix: Cryostylane reaction now has a moderate & not extreme cooling effect.
+ Helps you achieve more pure amounts of Cryostylane
+ TheVekter:
+ - rscadd: Added a new law to the Artist lawset in order to encourage Artist AIs
+ to build an audience.
+ mc-oofert:
+ - bugfix: Grilles dont break by just walking into them under any circumstances
+ necromanceranne:
+ - bugfix: Being in a Swat Suit appropriately protects you from collisions with a
+ body, rather than the body thrown at you having these protections protecting
+ YOU, the victim of the collision.
diff --git a/icons/hud/lobby/signup_button.dmi b/icons/hud/lobby/signup_button.dmi
index a67cc5584424e..daa2669069742 100644
Binary files a/icons/hud/lobby/signup_button.dmi and b/icons/hud/lobby/signup_button.dmi differ
diff --git a/icons/hud/screen_gen.dmi b/icons/hud/screen_gen.dmi
index 1484e3f4042a9..608be00b2e1fb 100644
Binary files a/icons/hud/screen_gen.dmi and b/icons/hud/screen_gen.dmi differ
diff --git a/icons/mob/actions/actions_changeling.dmi b/icons/mob/actions/actions_changeling.dmi
index bb3634a1dde11..25a4e10aa578b 100644
Binary files a/icons/mob/actions/actions_changeling.dmi and b/icons/mob/actions/actions_changeling.dmi differ
diff --git a/icons/mob/clothing/head/hats.dmi b/icons/mob/clothing/head/hats.dmi
index 0fd0de8e4250e..4183d5fa6cb4c 100644
Binary files a/icons/mob/clothing/head/hats.dmi and b/icons/mob/clothing/head/hats.dmi differ
diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi
index 5b30ae65b8f23..49edcf8422f26 100644
Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ
diff --git a/icons/mob/huds/antag_hud.dmi b/icons/mob/huds/antag_hud.dmi
index aa96f2338b250..bb44e3de9568f 100644
Binary files a/icons/mob/huds/antag_hud.dmi and b/icons/mob/huds/antag_hud.dmi differ
diff --git a/icons/mob/huds/hud.dmi b/icons/mob/huds/hud.dmi
index 3dff7642a9613..7ee3267280d2a 100644
Binary files a/icons/mob/huds/hud.dmi and b/icons/mob/huds/hud.dmi differ
diff --git a/icons/obj/card.dmi b/icons/obj/card.dmi
index 6397cf6fb5b5a..5bcd1df47d929 100644
Binary files a/icons/obj/card.dmi and b/icons/obj/card.dmi differ
diff --git a/icons/obj/clothing/head/hats.dmi b/icons/obj/clothing/head/hats.dmi
index 6cca3da61f41a..b655dd1756708 100644
Binary files a/icons/obj/clothing/head/hats.dmi and b/icons/obj/clothing/head/hats.dmi differ
diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi
index d9f02085e732e..94d11e6b82040 100644
Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ
diff --git a/icons/obj/service/hydroponics/equipment.dmi b/icons/obj/service/hydroponics/equipment.dmi
index ed339a8a4209d..0fcebb3c51988 100644
Binary files a/icons/obj/service/hydroponics/equipment.dmi and b/icons/obj/service/hydroponics/equipment.dmi differ
diff --git a/sound/creatures/bee_swarm.ogg b/sound/creatures/bee_swarm.ogg
new file mode 100644
index 0000000000000..7cf5a5a3d9f2e
Binary files /dev/null and b/sound/creatures/bee_swarm.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 5df1d8c26f7cb..df071abcac476 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1997,7 +1997,6 @@
#include "code\game\machinery\computer\accounting.dm"
#include "code\game\machinery\computer\aifixer.dm"
#include "code\game\machinery\computer\apc_control.dm"
-#include "code\game\machinery\computer\arena.dm"
#include "code\game\machinery\computer\atmos_alert.dm"
#include "code\game\machinery\computer\buildandrepair.dm"
#include "code\game\machinery\computer\camera.dm"
@@ -4254,6 +4253,7 @@
#include "code\modules\jobs\job_types\spawner\zombie.dm"
#include "code\modules\jobs\job_types\station_trait\bridge_assistant.dm"
#include "code\modules\jobs\job_types\station_trait\cargo_gorilla.dm"
+#include "code\modules\jobs\job_types\station_trait\veteran_advisor.dm"
#include "code\modules\keybindings\bindings_atom.dm"
#include "code\modules\keybindings\bindings_client.dm"
#include "code\modules\keybindings\focus.dm"
diff --git a/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx b/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx
index c108966bbb757..a1c53ffb8791f 100644
--- a/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx
+++ b/tgui/packages/tgui/interfaces/ChemRecipeDebug.tsx
@@ -368,7 +368,7 @@ export const ChemRecipeDebug = (props) => {
step={0.1}
stepPixelSize={3}
value={editReaction?.editValue || 0}
- minValue={0}
+ minValue={-1000}
maxValue={1000}
disabled={editReaction === null}
onDrag={(e, value) =>
diff --git a/tgui/packages/tgui/interfaces/CrewManifest.jsx b/tgui/packages/tgui/interfaces/CrewManifest.jsx
index b521eb0dae040..d550260087bea 100644
--- a/tgui/packages/tgui/interfaces/CrewManifest.jsx
+++ b/tgui/packages/tgui/interfaces/CrewManifest.jsx
@@ -57,7 +57,7 @@ export const CrewManifest = (props) => {
)}
- {crewMember.rank === 'Captain' && (
+ {crewMember.trim === 'Captain' && (
{
/>
)}
- {commandJobs.includes(crewMember.rank) && (
+ {commandJobs.includes(crewMember.trim) && (
{
+ return amount === 1 ? '' : 's';
+};
+
+const SlotsReel = (props: SlotsReelProps) => {
+ const { reel } = props;
+ return (
+
+ {reel.map((slot, i) => (
+
+ ))}
+
+ );
+};
+
+const SlotsTile = (props: SlotsTileProps) => {
+ return (
+
+
+
+ );
+};
+
+export const SlotMachine = (props) => {
+ const { act, data } = useBackend();
+ // icons: The list of possible icons, including colour and name
+ // backendState: the current state of the slots according to the backend
+ const {
+ plays,
+ jackpots,
+ money,
+ cost,
+ state,
+ balance,
+ jackpot,
+ working: rolling,
+ paymode,
+ } = data;
+
+ return (
+
+
+
+
+ Only {cost} credit{pluralS(cost)} for a chance to win big!
+
+
+ Available prize money:{' '}
+
+ {money} credit{pluralS(money)}
+ {' '}
+
+ {paymode === 1 && (
+
+ Current jackpot:{' '}
+
+ {money + jackpot} credit{pluralS(money + jackpot)}!
+
+
+ )}
+
+ So far people have spun{' '}
+
+ {plays} time{pluralS(plays)},
+ {' '}
+ and won{' '}
+
+ {jackpots} jackpot{pluralS(jackpots)}!
+
+
+
+
+
+ {state.map((reel, i) => {
+ return ;
+ })}
+
+
+ act('spin')}
+ disabled={rolling || balance < cost}
+ >
+ Spin!
+
+
+ Balance: {balance}
+
+ act('payout')} disabled={!(balance > 0)}>
+ Refund balance
+
+
+
+
+ );
+};
diff --git a/tgui/packages/tgui/interfaces/VotePanel.tsx b/tgui/packages/tgui/interfaces/VotePanel.tsx
index eeca947b2244b..07da85e6028d2 100644
--- a/tgui/packages/tgui/interfaces/VotePanel.tsx
+++ b/tgui/packages/tgui/interfaces/VotePanel.tsx
@@ -35,6 +35,7 @@ type ActiveVote = {
vote: Vote;
question: string | null;
timeRemaining: number;
+ displayStatistics: boolean;
choices: Option[];
countMethod: number;
};
@@ -209,7 +210,9 @@ const ChoicesPanel = (props) => {
name="vote-yea"
/>
)}
- {choice.votes} Votes
+ {currentVote.displayStatistics
+ ? choice.votes + ' Votes'
+ : null}
diff --git a/tgui/packages/tgui/interfaces/common/JobToIcon.ts b/tgui/packages/tgui/interfaces/common/JobToIcon.ts
index f3ce63bea57bf..98369c7902827 100644
--- a/tgui/packages/tgui/interfaces/common/JobToIcon.ts
+++ b/tgui/packages/tgui/interfaces/common/JobToIcon.ts
@@ -52,6 +52,7 @@ export const JOB2ICON = {
'Shaft Miner': 'digging',
'Station Engineer': 'gears',
'Syndicate Operative': 'dragon',
+ 'Veteran Security Advisor': 'ribbon',
Virologist: 'virus',
Warden: 'handcuffs',
} as const;