diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_syndidome.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_syndidome.dmm
index e2b11a02964eb..228c55292fbb0 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_underground_syndidome.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_underground_syndidome.dmm
@@ -90,6 +90,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
+"bp" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"bu" = (
/obj/effect/turf_decal/siding/wood,
/obj/structure/table/wood,
@@ -216,9 +223,15 @@
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 5
},
-/obj/machinery/smartfridge/organ,
-/obj/item/organ/alien/resinspinner,
-/obj/item/organ/eyes/night_vision,
+/obj/structure/table/reinforced/plastitaniumglass,
+/obj/item/clothing/gloves/latex/coroner{
+ pixel_x = -1;
+ pixel_y = 8
+ },
+/obj/item/clothing/mask/surgical{
+ pixel_x = 6;
+ pixel_y = 10
+ },
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"cE" = (
@@ -498,9 +511,10 @@
/obj/effect/decal/cleanable/blood/gibs/down,
/turf/open/floor/iron/cafeteria,
/area/ruin/syndibiodome)
-"gX" = (
-/obj/effect/decal/cleanable/dirt,
-/obj/machinery/light/warm/directional/west,
+"gZ" = (
+/obj/machinery/door/airlock/maintenance_hatch,
+/obj/structure/cable/layer1,
+/obj/structure/cable,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"ha" = (
@@ -509,10 +523,10 @@
/turf/open/misc/asteroid/snow/icemoon,
/area/icemoon/surface/outdoors/noteleport)
"he" = (
-/mob/living/basic/gorilla/genetics,
/obj/effect/turf_decal/siding/wood/corner{
dir = 1
},
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/wood,
/area/ruin/syndibiodome)
"hf" = (
@@ -527,8 +541,8 @@
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
"hm" = (
-/mob/living/basic/gorilla/genetics,
/obj/effect/decal/cleanable/dirt/dust,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark/small,
/area/ruin/syndibiodome)
"hr" = (
@@ -639,14 +653,12 @@
},
/turf/open/floor/iron/dark/herringbone,
/area/ruin/syndibiodome)
-"iq" = (
-/obj/structure/flora/rock/pile/style_random,
-/mob/living/carbon/human/species/monkey/angry,
-/turf/open/floor/grass,
-/area/ruin/syndibiodome)
"ir" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/light/small/dim/directional/east,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"iG" = (
@@ -723,16 +735,6 @@
},
/obj/effect/decal/cleanable/blood/drip,
/obj/effect/decal/cleanable/dirt,
-/obj/structure/table/reinforced/plastitaniumglass,
-/obj/item/surgery_tray/full,
-/obj/item/clothing/gloves/latex/coroner{
- pixel_x = -1;
- pixel_y = 8
- },
-/obj/item/clothing/mask/surgical{
- pixel_x = 6;
- pixel_y = 10
- },
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"jd" = (
@@ -771,9 +773,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
-"jQ" = (
-/turf/closed/indestructible/syndicate/nodiagonal,
-/area/icemoon/surface/outdoors/noteleport)
"jR" = (
/obj/effect/decal/cleanable/blood/trails{
dir = 4
@@ -1025,9 +1024,6 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
-"mK" = (
-/turf/open/misc/asteroid/snow/icemoon,
-/area/ruin/syndibiodome)
"mV" = (
/obj/effect/turf_decal/siding/wideplating/dark,
/obj/effect/decal/cleanable/dirt/dust,
@@ -1040,6 +1036,9 @@
"mW" = (
/obj/effect/spawner/random/trash,
/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable/layer3,
+/obj/structure/cable/layer1,
+/obj/structure/cable,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"mZ" = (
@@ -1113,6 +1112,13 @@
/obj/effect/turf_decal/trimline/dark_red/line,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
+"on" = (
+/obj/machinery/door/airlock/maintenance_hatch,
+/obj/structure/cable/layer3,
+/obj/structure/cable/layer1,
+/obj/structure/cable,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"oq" = (
/obj/effect/decal/cleanable/blood/trails{
dir = 10
@@ -1147,7 +1153,7 @@
/obj/machinery/light/warm/directional/west,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt,
-/mob/living/basic/gorilla/genetics,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
"oH" = (
@@ -1346,7 +1352,6 @@
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 1
},
-/mob/living/carbon/human/species/monkey/angry,
/obj/machinery/light/warm/directional/north,
/obj/machinery/digital_clock/directional/north,
/obj/effect/decal/cleanable/dirt,
@@ -1354,8 +1359,8 @@
/area/ruin/syndibiodome)
"rQ" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/basic/gorilla/genetics,
/obj/effect/decal/cleanable/dirt/dust,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
"rX" = (
@@ -1434,7 +1439,6 @@
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/dirt/dust,
-/obj/effect/mapping_helpers/broken_machine,
/turf/open/floor/iron/dark/herringbone,
/area/ruin/syndibiodome)
"td" = (
@@ -1701,12 +1705,20 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
+"vH" = (
+/obj/effect/spawner/random/trash,
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"vJ" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/basic/gorilla/genetics,
/obj/effect/turf_decal/trimline/purple/corner,
/obj/effect/decal/cleanable/dirt/dust,
/obj/effect/decal/cleanable/dirt,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark/herringbone,
/area/ruin/syndibiodome)
"vK" = (
@@ -1959,7 +1971,6 @@
/obj/effect/turf_decal/trimline/dark/line{
dir = 1
},
-/mob/living/carbon/human/species/monkey/angry,
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 1
},
@@ -2100,7 +2111,6 @@
/turf/open/floor/grass,
/area/ruin/syndibiodome)
"yU" = (
-/mob/living/carbon/human/species/monkey/angry,
/obj/effect/turf_decal/weather/dirt{
dir = 9
},
@@ -2235,6 +2245,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
+"Az" = (
+/obj/machinery/door/airlock/maintenance_hatch,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"AA" = (
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 5
@@ -2262,9 +2279,9 @@
/obj/effect/decal/cleanable/dirt/dust,
/obj/item/storage/belt/security/webbing,
/obj/item/storage/toolbox/syndicate,
-/obj/item/gun/ballistic/automatic/pistol,
-/obj/item/ammo_box/magazine/m10mm,
-/obj/item/ammo_box/magazine/m10mm,
+/obj/item/gun/ballistic/automatic/pistol/contraband,
+/obj/item/ammo_box/magazine/m9mm,
+/obj/item/ammo_box/magazine/m9mm,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"Ba" = (
@@ -2496,7 +2513,6 @@
/turf/open/floor/iron/white/small,
/area/ruin/syndibiodome)
"EE" = (
-/mob/living/carbon/human/species/monkey/angry,
/obj/effect/decal/cleanable/blood/trails{
dir = 1
},
@@ -2727,7 +2743,6 @@
"Hs" = (
/obj/structure/flora/bush/flowers_br/style_3,
/obj/structure/flora/bush/flowers_yw/style_3,
-/mob/living/carbon/human/species/monkey/angry,
/obj/effect/gibspawner/human/bodypartless,
/obj/effect/mob_spawn/corpse/human/syndicatecommando/lessenedgear,
/turf/open/floor/grass,
@@ -2810,6 +2825,14 @@
},
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
+"Iq" = (
+/obj/machinery/light/small/dim/directional/west,
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable/layer3,
+/obj/structure/cable/layer1,
+/obj/structure/cable,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"IF" = (
/obj/effect/mob_spawn/corpse/human/syndicatecommando/lessenedgear,
/obj/effect/turf_decal/siding/wideplating/dark/end{
@@ -2947,6 +2970,13 @@
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark/herringbone,
/area/ruin/syndibiodome)
+"Kl" = (
+/obj/effect/decal/cleanable/dirt,
+/obj/structure/cable/layer3,
+/obj/structure/cable/layer1,
+/obj/structure/cable,
+/turf/open/floor/catwalk_floor/iron_dark,
+/area/ruin/syndibiodome)
"Kn" = (
/obj/effect/decal/cleanable/blood/footprints{
dir = 2
@@ -3087,6 +3117,9 @@
"LA" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/light/small/dim/directional/west,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"LB" = (
@@ -3192,6 +3225,8 @@
/turf/open/floor/iron/cafeteria,
/area/ruin/syndibiodome)
"Mr" = (
+/obj/machinery/light/warm/directional/west,
+/obj/effect/decal/cleanable/dirt,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"Mt" = (
@@ -3266,7 +3301,6 @@
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 1
},
-/mob/living/carbon/human/species/monkey/angry,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/dark/line,
/obj/effect/decal/cleanable/dirt/dust,
@@ -3348,7 +3382,7 @@
/obj/effect/turf_decal/weather/dirt{
dir = 6
},
-/mob/living/basic/gorilla/genetics,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/grass,
/area/ruin/syndibiodome)
"NN" = (
@@ -3364,7 +3398,6 @@
/obj/effect/turf_decal/siding/wideplating/dark{
dir = 6
},
-/obj/effect/gibspawner/generic,
/obj/machinery/digital_clock/directional/east,
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/mineral/plastitanium/red,
@@ -3379,11 +3412,8 @@
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
"Os" = (
-/obj/structure/bodycontainer/morgue/beeper_off{
- dir = 8
- },
/obj/effect/turf_decal/trimline/tram/filled,
-/turf/open/floor/pod/dark,
+/turf/closed/indestructible/syndicate/nodiagonal,
/area/ruin/syndibiodome)
"Oy" = (
/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium,
@@ -3392,13 +3422,6 @@
},
/turf/open/floor/plating,
/area/ruin/syndibiodome)
-"OD" = (
-/mob/living/carbon/human/species/monkey/angry,
-/obj/effect/turf_decal/weather/dirt{
- dir = 6
- },
-/turf/open/floor/grass,
-/area/ruin/syndibiodome)
"OH" = (
/obj/effect/decal/cleanable/blood/trails{
dir = 8
@@ -3428,8 +3451,8 @@
/obj/machinery/light/warm/directional/east,
/obj/item/storage/belt/security/webbing,
/obj/item/gun/ballistic/automatic/pistol/contraband,
-/obj/item/ammo_box/magazine/m10mm,
-/obj/item/ammo_box/magazine/m10mm,
+/obj/item/ammo_box/magazine/m9mm,
+/obj/item/ammo_box/magazine/m9mm,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"OM" = (
@@ -3446,6 +3469,9 @@
"ON" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/light/small/dim/directional/south,
+/obj/structure/cable,
+/obj/structure/cable/layer1,
+/obj/structure/cable/layer3,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"OO" = (
@@ -3640,7 +3666,6 @@
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"RK" = (
-/mob/living/carbon/human/species/monkey/angry,
/obj/structure/chair/office/tactical{
dir = 4
},
@@ -3659,8 +3684,9 @@
/area/icemoon/surface/outdoors/noteleport)
"RX" = (
/obj/effect/turf_decal/siding/wideplating/dark,
-/mob/living/basic/gorilla/genetics,
/obj/effect/decal/cleanable/dirt,
+/obj/effect/gibspawner/generic,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"Se" = (
@@ -3823,6 +3849,10 @@
dir = 1
},
/area/ruin/syndibiodome)
+"To" = (
+/obj/machinery/door/airlock/maintenance_hatch,
+/turf/open/floor/iron/dark,
+/area/ruin/syndibiodome)
"Tu" = (
/obj/structure/table/reinforced/plastitaniumglass,
/obj/effect/turf_decal/siding/wideplating/dark{
@@ -3897,6 +3927,7 @@
/obj/item/stack/sheet/mineral/uranium/five,
/obj/item/stack/sheet/mineral/uranium/five,
/obj/effect/decal/cleanable/dirt,
+/obj/machinery/light/warm/directional/east,
/turf/open/floor/catwalk_floor/iron_dark,
/area/ruin/syndibiodome)
"TL" = (
@@ -3971,12 +4002,12 @@
/turf/open/floor/iron/dark/small,
/area/ruin/syndibiodome)
"Ux" = (
-/mob/living/basic/gorilla/genetics,
/obj/effect/gibspawner/human/bodypartless,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/trimline/blue/corner{
dir = 4
},
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark,
/area/ruin/syndibiodome)
"Uz" = (
@@ -4223,8 +4254,8 @@
/obj/effect/decal/cleanable/blood/tracks{
dir = 4
},
-/mob/living/basic/gorilla/genetics,
/obj/effect/decal/cleanable/dirt,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/iron/dark/herringbone,
/area/ruin/syndibiodome)
"XG" = (
@@ -4362,13 +4393,13 @@
/area/ruin/syndibiodome)
"YZ" = (
/obj/effect/turf_decal/siding/wideplating/dark,
-/mob/living/basic/gorilla/genetics,
/obj/structure/fluff/fake_vent,
/obj/effect/decal/cleanable/blood/trails{
dir = 1
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/gibspawner/human/bodypartless,
+/mob/living/basic/gorilla/hostile,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/syndibiodome)
"Zd" = (
@@ -4690,7 +4721,7 @@ oq
Mc
zM
zM
-mK
+ys
ys
ys
tL
@@ -4727,8 +4758,8 @@ ck
ys
ys
zM
-Ut
-vx
+Kl
+on
xi
kw
wL
@@ -4820,8 +4851,8 @@ jS
ys
ys
zM
-Ut
-Ut
+Kl
+Kl
zM
Sr
zM
@@ -4867,7 +4898,7 @@ pg
pg
zM
zM
-Ut
+Kl
zM
zM
Ab
@@ -4914,7 +4945,7 @@ zd
ys
zM
Db
-Ut
+Kl
zM
kK
MB
@@ -4961,7 +4992,7 @@ pg
pg
zM
ic
-Ut
+Kl
zM
rK
YZ
@@ -5008,7 +5039,7 @@ uD
ys
zM
wY
-Ut
+Kl
zM
cB
ja
@@ -5102,10 +5133,10 @@ AI
ys
ys
zM
-Ut
-Ut
-zM
-zM
+Kl
+Kl
+Iq
+Ro
zM
zM
zM
@@ -5151,8 +5182,8 @@ Hi
zM
zM
Ut
-LA
-Ro
+Kl
+Ut
zM
qN
qU
@@ -5198,10 +5229,10 @@ ys
ys
zM
zM
-Ut
-Ut
-Ut
-vx
+Kl
+Kl
+Kl
+gZ
je
kt
XC
@@ -5582,7 +5613,7 @@ Fl
qN
IU
vu
-iq
+MH
YD
Fp
xz
@@ -5664,13 +5695,13 @@ ys
ck
zM
zM
-mW
-Ut
+vH
+bp
ir
-Ut
-Ut
-Ut
-vx
+bp
+bp
+bp
+Az
kw
Eq
CV
@@ -5711,7 +5742,7 @@ ys
ys
zM
MP
-Ut
+bp
zM
zM
Ut
@@ -5758,7 +5789,7 @@ ys
ys
zM
qa
-Ut
+bp
zM
zM
dS
@@ -5805,7 +5836,7 @@ ys
zM
zM
Sv
-Ut
+bp
zM
wx
RH
@@ -5852,7 +5883,7 @@ zM
zM
rZ
Ut
-Ut
+bp
zM
Ra
RX
@@ -5899,7 +5930,7 @@ zM
zM
zM
zM
-Ut
+bp
zM
Pw
Oi
@@ -5993,12 +6024,12 @@ Uc
qp
sR
zM
-Ut
-Ut
+bp
+bp
LA
-mW
-Ut
-vx
+vH
+bp
+Az
Nt
uW
Vv
@@ -6049,7 +6080,7 @@ qN
pY
XC
XC
-qN
+To
Ut
zM
Vj
@@ -6060,7 +6091,7 @@ XE
Mt
WB
iX
-OD
+cN
zM
ys
uD
@@ -6188,8 +6219,8 @@ zM
zM
zM
zM
-Vv
zM
+To
zM
LU
qN
@@ -6235,8 +6266,8 @@ zM
ek
Dc
zM
-zM
-zM
+Mr
+Ut
Mr
Ut
qN
@@ -6283,7 +6314,7 @@ MM
bu
zM
Kz
-gX
+Ut
Ut
Ut
zM
@@ -6428,7 +6459,7 @@ zM
zM
zM
ys
-jQ
+zM
zM
zM
zM
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index ed07ca2ba6784..b251d9f463ed6 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -2837,6 +2837,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"bfe" = (
@@ -2858,6 +2859,7 @@
/obj/structure/disposalpipe/junction/flip{
dir = 8
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"bfU" = (
@@ -6737,6 +6739,7 @@
/area/space/nearstation)
"cCM" = (
/obj/structure/cable,
+/obj/structure/sink/kitchen/directional/east,
/turf/open/floor/iron/kitchen/small,
/area/station/service/kitchen)
"cCP" = (
@@ -10712,15 +10715,12 @@
/turf/open/floor/iron/white,
/area/station/medical/medbay/aft)
"dZa" = (
-/obj/structure/table/reinforced,
/obj/machinery/camera/directional/west,
/obj/effect/decal/cleanable/cobweb,
-/obj/item/retractor,
-/obj/item/hemostat,
-/obj/item/cautery,
/obj/machinery/camera/autoname/directional/north,
/obj/structure/sign/poster/official/random/directional/north,
/obj/machinery/status_display/ai/directional/west,
+/obj/item/surgery_tray/full/deployed,
/turf/open/floor/iron/showroomfloor,
/area/station/medical/surgery/theatre)
"dZk" = (
@@ -13995,13 +13995,13 @@
/turf/open/floor/iron/small,
/area/station/security/office)
"fhp" = (
-/obj/structure/table,
/obj/effect/spawner/random/food_or_drink/donkpockets{
pixel_y = 6
},
/obj/effect/turf_decal/siding{
dir = 8
},
+/obj/structure/table,
/turf/open/floor/iron/dark/textured_large,
/area/station/service/kitchen)
"fhT" = (
@@ -14979,6 +14979,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"fyZ" = (
@@ -15861,6 +15862,7 @@
dir = 1
},
/obj/machinery/power/apc/auto_name/directional/south,
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"fMg" = (
@@ -17874,10 +17876,6 @@
pixel_y = 8
},
/obj/item/clothing/mask/surgical,
-/obj/item/surgical_drapes{
- pixel_x = -1;
- pixel_y = 4
- },
/obj/machinery/status_display/evac/directional/west,
/turf/open/floor/iron/showroomfloor,
/area/station/medical/surgery/theatre)
@@ -20068,6 +20066,11 @@
name = "Pharmacy Shutters Control";
req_access = list("pharmacy")
},
+/obj/item/reagent_containers/cup/bottle/multiver,
+/obj/item/reagent_containers/cup/bottle/epinephrine,
+/obj/item/reagent_containers/cup/bottle/formaldehyde,
+/obj/item/reagent_containers/cup/bottle/acidic_buffer,
+/obj/item/reagent_containers/cup/bottle/basic_buffer,
/turf/open/floor/iron/dark,
/area/station/medical/pharmacy)
"hdT" = (
@@ -24186,6 +24189,7 @@
pixel_y = 18
},
/obj/structure/extinguisher_cabinet/directional/east,
+/obj/item/circuitboard/mecha/ripley/main,
/turf/open/floor/iron/dark,
/area/station/science/robotics/lab)
"ivC" = (
@@ -25595,6 +25599,16 @@
},
/turf/open/floor/iron/dark,
/area/station/ai_monitored/security/armory)
+"iPx" = (
+/obj/machinery/atmospherics/components/trinary/filter/flipped/critical{
+ dir = 1;
+ filter_type = list(/datum/gas/nitrogen)
+ },
+/obj/effect/turf_decal/bot{
+ dir = 1
+ },
+/turf/open/floor/engine,
+/area/station/engineering/supermatter/room)
"iPy" = (
/obj/structure/cable,
/turf/open/floor/iron,
@@ -26328,6 +26342,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"jab" = (
@@ -35514,7 +35529,7 @@
"mae" = (
/obj/structure/cable,
/turf/closed/wall,
-/area/station/service/bar)
+/area/station/maintenance/central/greater)
"maf" = (
/turf/closed/wall/rust,
/area/station/hallway/primary/fore)
@@ -40681,6 +40696,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"nSd" = (
@@ -43687,6 +43703,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"oYj" = (
@@ -46106,6 +46123,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron/small,
/area/station/hallway/primary/port)
"pOQ" = (
@@ -51221,10 +51239,10 @@
pixel_y = 2
},
/obj/item/holosign_creator/robot_seat/restaurant,
-/obj/structure/table,
/obj/effect/turf_decal/siding{
dir = 9
},
+/obj/structure/table,
/turf/open/floor/iron/dark/textured_large,
/area/station/service/kitchen)
"rya" = (
@@ -52583,7 +52601,7 @@
/turf/open/floor/iron/white,
/area/station/medical/medbay/lobby)
"rVI" = (
-/obj/machinery/atmospherics/components/trinary/mixer/airmix/flipped{
+/obj/machinery/atmospherics/components/trinary/mixer/airmix/flipped/inverse{
dir = 8
},
/turf/open/floor/iron,
@@ -54601,13 +54619,7 @@
/turf/open/misc/sandy_dirt,
/area/station/security/tram)
"sGt" = (
-/obj/structure/table/reinforced,
-/obj/item/scalpel{
- pixel_y = 12
- },
-/obj/item/blood_filter,
-/obj/item/circular_saw,
-/obj/item/bonesetter,
+/obj/structure/closet/crate/freezer/surplus_limbs,
/turf/open/floor/iron/showroomfloor,
/area/station/medical/surgery/theatre)
"sGE" = (
@@ -61586,6 +61598,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"uQT" = (
@@ -62426,15 +62439,12 @@
/turf/open/floor/iron/smooth_large,
/area/station/science/robotics/mechbay)
"vfI" = (
-/obj/machinery/microwave{
- pixel_y = 5
- },
/obj/machinery/light_switch/directional/north,
/obj/structure/disposalpipe/segment{
dir = 4
},
-/obj/structure/table,
/obj/effect/turf_decal/siding/end,
+/obj/machinery/smartfridge/drying,
/turf/open/floor/iron/dark/textured_large,
/area/station/service/kitchen)
"vfK" = (
@@ -65162,9 +65172,15 @@
/turf/open/floor/iron/dark,
/area/station/command/corporate_dock)
"vTP" = (
-/obj/structure/sink/kitchen/directional/east,
/obj/machinery/firealarm/directional/west,
-/turf/open/floor/iron/kitchen/small,
+/obj/structure/table,
+/obj/machinery/microwave{
+ pixel_y = 5
+ },
+/obj/effect/turf_decal/siding/end{
+ dir = 4
+ },
+/turf/open/floor/iron/dark/textured_large,
/area/station/service/kitchen)
"vTV" = (
/turf/closed/wall/r_wall,
@@ -67829,7 +67845,7 @@
/obj/effect/spawner/random/maintenance,
/obj/structure/rack,
/turf/open/floor/plating,
-/area/station/service/bar)
+/area/station/maintenance/central/greater)
"wKO" = (
/obj/structure/disposalpipe/segment,
/obj/machinery/camera/directional/east,
@@ -69552,6 +69568,7 @@
/obj/structure/disposalpipe/segment{
dir = 4
},
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/hallway/primary/port)
"xiT" = (
@@ -90216,7 +90233,7 @@ jNV
guh
cBl
fJe
-aJb
+iPx
cay
fMB
maK
@@ -98003,8 +98020,8 @@ xRV
jVM
xjQ
jVM
-tGq
-tGq
+jVM
+jVM
xmt
xmt
xmt
@@ -100316,7 +100333,7 @@ jVM
jVM
jVM
jVM
-vkh
+jVM
lnD
fzw
bKO
@@ -101344,7 +101361,7 @@ jgb
hRc
jVM
kXC
-vkh
+jVM
dxV
jDT
fOq
@@ -101601,7 +101618,7 @@ vGe
xno
jVM
kXC
-vkh
+jVM
vkh
kWF
wtw
@@ -102115,7 +102132,7 @@ xHD
xHD
jVM
jBu
-vkh
+jVM
vkh
vkh
vkh
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 5b3d50cdadd17..26baf69940954 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -115,7 +115,7 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
#define ismoth(A) (is_species(A, /datum/species/moth))
#define isfelinid(A) (is_species(A, /datum/species/human/felinid))
#define isethereal(A) (is_species(A, /datum/species/ethereal))
-#define isvampire(A) (is_species(A,/datum/species/vampire))
+#define isvampire(A) (is_species(A,/datum/species/human/vampire))
#define isdullahan(A) (is_species(A, /datum/species/dullahan))
#define ismonkey(A) (is_species(A, /datum/species/monkey))
#define isandroid(A) (is_species(A, /datum/species/android))
diff --git a/code/__DEFINES/tracy.dm b/code/__DEFINES/tracy.dm
new file mode 100644
index 0000000000000..0a9ab8d68ee24
--- /dev/null
+++ b/code/__DEFINES/tracy.dm
@@ -0,0 +1,5 @@
+/// File path used for the "enable tracy next round" functionality
+#define TRACY_ENABLE_PATH "data/enable_tracy"
+
+/// The DLL path for byond-tracy.
+#define TRACY_DLL_PATH (world.system_type == MS_WINDOWS ? "prof.dll" : "./libprof.so")
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index f4f5688819bb2..a0448be48c039 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -391,6 +391,12 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_DETECT_STORM "detect_storm"
#define TRAIT_PRIMITIVE "primitive"
#define TRAIT_GUNFLIP "gunflip"
+/// eignore blindness or blurriness or nearsightedness
+#define TRAIT_SIGHT_BYPASS "perfect_sight"
+/// ignore traumas that make you 'hallucinate' something
+#define TRAIT_PERCEPTUAL_TRAUMA_BYPASS "trauma_bypass"
+/// mob is immune to hallucinations
+#define TRAIT_HALLUCINATION_IMMUNE "hallucination_immune"
/// Increases chance of getting special traumas, makes them harder to cure
#define TRAIT_SPECIAL_TRAUMA_BOOST "special_trauma_boost"
#define TRAIT_SPACEWALK "spacewalk"
diff --git a/code/__HELPERS/atoms.dm b/code/__HELPERS/atoms.dm
index d54b29b3f4ac9..e94d58dd69399 100644
--- a/code/__HELPERS/atoms.dm
+++ b/code/__HELPERS/atoms.dm
@@ -316,6 +316,46 @@ rough example of the "cone" made by the 3 dirs checked
loc = loc.loc
return null
+/**
+ * Line of sight check!
+ * Spawns a dummy object and then iterates through each turf to see if it's blocked by something not handled by pass_args.
+ * Contains a mid_los_check, meant to be overriden by subtypes.
+ * args:
+ * * user = Origin to start at.
+ * * target = End point.
+ * * pass_args = pass_flags given to dummy object to allow it to ignore certain types of blockades.
+ */
+/proc/los_check(atom/movable/user, mob/target, pass_args = PASSTABLE|PASSGLASS|PASSGRILLE, datum/callback/mid_check)
+ var/turf/user_turf = user.loc
+ if(!istype(user_turf))
+ return FALSE
+ var/obj/dummy = new(user_turf)
+ dummy.pass_flags |= pass_args //Grille/Glass so it can be used through common windows
+ var/turf/previous_step = user_turf
+ var/first_step = TRUE
+ for(var/turf/next_step as anything in (get_line(user_turf, target) - user_turf))
+ if(first_step)
+ for(var/obj/blocker in user_turf)
+ if(!blocker.density || !(blocker.flags_1 & ON_BORDER_1))
+ continue
+ if(blocker.CanPass(dummy, get_dir(user_turf, next_step)))
+ continue
+ return FALSE // Could not leave the first turf.
+ first_step = FALSE
+ if(next_step.density)
+ qdel(dummy)
+ return FALSE
+ for(var/atom/movable/movable as anything in next_step)
+ if(!movable.CanPass(dummy, get_dir(next_step, previous_step)))
+ qdel(dummy)
+ return FALSE
+ if(mid_check?.Invoke(user, target, pass_args, next_step, dummy) == FALSE) // specify false as it may return null if there's no check
+ qdel(dummy)
+ return FALSE
+ previous_step = next_step
+ qdel(dummy)
+ return TRUE
+
///Returns true if the src countain the atom target
/atom/proc/contains(atom/target)
if(!target)
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index c42754644bb1a..7947c8c3d14ba 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -85,9 +85,13 @@
// If this is uncommented, will attempt to load and initialize prof.dll/libprof.so by default.
// Even if it's not defined, you can pass "tracy" via -params in order to try to load it.
-// We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy/
+// We do not ship byond-tracy. Build it yourself here: https://github.com/mafemergency/byond-tracy,
+// or the fork which writes profiling data to a file: https://github.com/ParadiseSS13/byond-tracy
// #define USE_BYOND_TRACY
+// If uncommented, will display info about byond-tracy's status in the MC tab.
+// #define MC_TAB_TRACY_INFO
+
// If defined, we will compile with FULL timer debug info, rather then a limited scope
// Be warned, this increases timer creation cost by 5x
// #define TIMER_DEBUG
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 46a91854931ef..f7556662b97f1 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -275,6 +275,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_GREENTEXT_CURSED" = TRAIT_GREENTEXT_CURSED,
"TRAIT_GUNFLIP" = TRAIT_GUNFLIP,
"TRAIT_GUN_NATURAL" = TRAIT_GUN_NATURAL,
+ "TRAIT_HALLUCINATION_IMMUNE" = TRAIT_HALLUCINATION_IMMUNE,
"TRAIT_HALT_RADIATION_EFFECTS" = TRAIT_HALT_RADIATION_EFFECTS,
"TRAIT_HANDS_BLOCKED" = TRAIT_HANDS_BLOCKED,
"TRAIT_HARDLY_WOUNDED" = TRAIT_HARDLY_WOUNDED,
@@ -416,6 +417,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_PASSTABLE" = TRAIT_PASSTABLE,
"TRAIT_PASSWINDOW" = TRAIT_PASSWINDOW,
"TRAIT_PERCEIVED_AS_CLOWN" = TRAIT_PERCEIVED_AS_CLOWN,
+ "TRAIT_PERCEPTUAL_TRAUMA_BYPASS" = TRAIT_PERCEPTUAL_TRAUMA_BYPASS,
"TRAIT_PERFECT_ATTACKER" = TRAIT_PERFECT_ATTACKER,
"TRAIT_PERMANENTLY_MORTAL" = TRAIT_PERMANENTLY_MORTAL,
"TRAIT_PHOTOGRAPHER" = TRAIT_PHOTOGRAPHER,
@@ -465,6 +467,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_SHAVED" = TRAIT_SHAVED,
"TRAIT_SHIFTY_EYES" = TRAIT_SHIFTY_EYES,
"TRAIT_SHOCKIMMUNE" = TRAIT_SHOCKIMMUNE,
+ "TRAIT_SIGHT_BYPASS" = TRAIT_SIGHT_BYPASS,
"TRAIT_SIGN_LANG" = TRAIT_SIGN_LANG,
"TRAIT_SILENT_FOOTSTEPS" = TRAIT_SILENT_FOOTSTEPS,
"TRAIT_SILICON_ACCESS" = TRAIT_SILICON_ACCESS,
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index f92bb4682e1c8..a2185b0386d2e 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -151,8 +151,16 @@ GLOBAL_LIST_INIT(available_ui_styles, list(
/datum/hud/proc/client_refresh(datum/source)
SIGNAL_HANDLER
- RegisterSignal(mymob.canon_client, COMSIG_CLIENT_SET_EYE, PROC_REF(on_eye_change))
- on_eye_change(null, null, mymob.canon_client.eye)
+ var/client/client = mymob.canon_client
+ if(client.rebuild_plane_masters)
+ var/new_relay_loc = (client.byond_version > 515) ? "1,1" : "CENTER"
+ for(var/group_key as anything in master_groups)
+ var/datum/plane_master_group/group = master_groups[group_key]
+ group.relay_loc = new_relay_loc
+ group.rebuild_plane_masters()
+ client.rebuild_plane_masters = FALSE
+ RegisterSignal(client, COMSIG_CLIENT_SET_EYE, PROC_REF(on_eye_change))
+ on_eye_change(null, null, client.eye)
/datum/hud/proc/clear_client(datum/source)
SIGNAL_HANDLER
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index e1ed3284441f6..3648a1b564e8c 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -762,3 +762,11 @@
default = 100
min_val = 0
max_val = 100
+
+/// If admins with +DEBUG can initialize byond-tracy midround.
+/datum/config_entry/flag/allow_tracy_start
+ protection = CONFIG_ENTRY_LOCKED
+
+/// If admins with +DEBUG can queue byond-tracy to run the next round.
+/datum/config_entry/flag/allow_tracy_queue
+ protection = CONFIG_ENTRY_LOCKED
diff --git a/code/controllers/subsystem/blackbox.dm b/code/controllers/subsystem/blackbox.dm
index 83c666de64ac4..e869f21c61560 100644
--- a/code/controllers/subsystem/blackbox.dm
+++ b/code/controllers/subsystem/blackbox.dm
@@ -88,7 +88,7 @@ SUBSYSTEM_DEF(blackbox)
for(var/player_key in GLOB.player_details)
var/datum/player_details/PD = GLOB.player_details[player_key]
- record_feedback("tally", "client_byond_version", 1, PD.byond_version)
+ record_feedback("tally", "client_byond_version", 1, PD.full_byond_version())
/datum/controller/subsystem/blackbox/Shutdown()
sealed = FALSE
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index cf158586ce497..9d33e977e2b7f 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -173,6 +173,24 @@ SUBSYSTEM_DEF(statpanels)
list("Failsafe Controller:", Failsafe.stat_entry(), text_ref(Failsafe)),
list("","")
)
+#if defined(MC_TAB_TRACY_INFO) || defined(SPACEMAN_DMM)
+ var/static/tracy_dll
+ var/static/tracy_present
+ if(isnull(tracy_dll))
+ tracy_dll = TRACY_DLL_PATH
+ tracy_present = fexists(tracy_dll)
+ if(tracy_present)
+ if(GLOB.tracy_initialized)
+ mc_data.Insert(2, list(list("byond-tracy:", "Active (reason: [GLOB.tracy_init_reason || "N/A"])")))
+ else if(GLOB.tracy_init_error)
+ mc_data.Insert(2, list(list("byond-tracy:", "Errored ([GLOB.tracy_init_error])")))
+ else if(fexists(TRACY_ENABLE_PATH))
+ mc_data.Insert(2, list(list("byond-tracy:", "Queued for next round")))
+ else
+ mc_data.Insert(2, list(list("byond-tracy:", "Inactive")))
+ else
+ mc_data.Insert(2, list(list("byond-tracy:", "[tracy_dll] not present")))
+#endif
for(var/datum/controller/subsystem/sub_system as anything in Master.subsystems)
mc_data[++mc_data.len] = list("\[[sub_system.state_letter()]][sub_system.name]", sub_system.stat_entry(), text_ref(sub_system))
mc_data[++mc_data.len] = list("Camera Net", "Cameras: [GLOB.cameranet.cameras.len] | Chunks: [GLOB.cameranet.chunks.len]", text_ref(GLOB.cameranet))
diff --git a/code/datums/components/earprotection.dm b/code/datums/components/earprotection.dm
index 6439e49b831f5..6dfa7d9568baf 100644
--- a/code/datums/components/earprotection.dm
+++ b/code/datums/components/earprotection.dm
@@ -2,10 +2,13 @@
signals = list(COMSIG_CARBON_SOUNDBANG)
mobtype = /mob/living/carbon
proctype = PROC_REF(reducebang)
+ var/reduce_amount = 1
-/datum/component/wearertargeting/earprotection/Initialize(_valid_slots)
+/datum/component/wearertargeting/earprotection/Initialize(valid_slots, reduce_amount = 1)
. = ..()
- valid_slots = _valid_slots
+ src.valid_slots = valid_slots
+ if(reduce_amount)
+ src.reduce_amount = reduce_amount
/datum/component/wearertargeting/earprotection/proc/reducebang(datum/source, list/reflist)
- reflist[1]--
+ reflist[1] -= reduce_amount
diff --git a/code/datums/elements/cuffsnapping.dm b/code/datums/elements/cuffsnapping.dm
index df445f4acc971..1abdc4a7a6bd2 100644
--- a/code/datums/elements/cuffsnapping.dm
+++ b/code/datums/elements/cuffsnapping.dm
@@ -42,13 +42,20 @@
src.snap_time_strong = snap_time_strong
RegisterSignal(target, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine))
- RegisterSignal(target, COMSIG_ITEM_ATTACK , PROC_REF(try_cuffsnap_target))
+ RegisterSignal(target, COMSIG_ITEM_ATTACK_SECONDARY, PROC_REF(try_cuffsnap_target))
+ RegisterSignal(target, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET, PROC_REF(add_item_context))
/datum/element/cuffsnapping/Detach(datum/target)
- UnregisterSignal(target, list(COMSIG_ITEM_ATTACK, COMSIG_ATOM_EXAMINE))
-
+ UnregisterSignal(target, list(COMSIG_ITEM_ATTACK_SECONDARY, COMSIG_ATOM_EXAMINE, COMSIG_ITEM_REQUESTING_CONTEXT_FOR_TARGET))
return ..()
+/datum/element/cuffsnapping/proc/add_item_context(obj/item/source, list/context, mob/living/carbon/target, mob/living/user)
+ SIGNAL_HANDLER
+ if(!iscarbon(target) || !target.handcuffed)
+ return NONE
+ context[SCREENTIP_CONTEXT_RMB] = "Cut Restraints"
+ return CONTEXTUAL_SCREENTIP_SET
+
///signal called on parent being examined
/datum/element/cuffsnapping/proc/on_examine(datum/target, mob/user, list/examine_list)
SIGNAL_HANDLER
@@ -56,7 +63,7 @@
var/examine_string
if(isnull(snap_time_weak))
return
- examine_string = "It looks like it could cut zipties or cable restraints off someone in [snap_time_weak] seconds"
+ examine_string = "It looks like it could be used to cut zipties or cable restraints off someone in [snap_time_weak] seconds"
if(!isnull(snap_time_strong))
examine_string += ", and handcuffs in [snap_time_strong] seconds."
@@ -65,7 +72,7 @@
examine_list += span_notice(examine_string)
-/datum/element/cuffsnapping/proc/try_cuffsnap_target(obj/item/cutter, mob/living/carbon/target, mob/cutter_user, params)
+/datum/element/cuffsnapping/proc/try_cuffsnap_target(obj/item/cutter, mob/living/carbon/target, mob/living/cutter_user, params)
SIGNAL_HANDLER
if(!istype(target)) //we aren't the kind of mob that can even have cuffs, so we skip.
diff --git a/code/datums/elements/tenacious.dm b/code/datums/elements/tenacious.dm
index 4d906812c13ab..35dd5774cf4be 100644
--- a/code/datums/elements/tenacious.dm
+++ b/code/datums/elements/tenacious.dm
@@ -18,6 +18,9 @@
/datum/element/tenacious/Detach(datum/target)
UnregisterSignal(target, COMSIG_MOB_STATCHANGE)
REMOVE_TRAIT(target, TRAIT_TENACIOUS, ELEMENT_TRAIT(type))
+ var/mob/living/carbon/human/valid_target = target
+ if(valid_target.remove_movespeed_modifier(/datum/movespeed_modifier/tenacious))
+ valid_target.balloon_alert(valid_target, "your tenacity wears off")
return ..()
///signal called by the stat of the target changing
@@ -27,6 +30,5 @@
if(new_stat == SOFT_CRIT)
target.balloon_alert(target, "your tenacity kicks in")
target.add_movespeed_modifier(/datum/movespeed_modifier/tenacious)
- else
+ else if(target.remove_movespeed_modifier(/datum/movespeed_modifier/tenacious))
target.balloon_alert(target, "your tenacity wears off")
- target.remove_movespeed_modifier(/datum/movespeed_modifier/tenacious)
diff --git a/code/datums/status_effects/debuffs/blindness.dm b/code/datums/status_effects/debuffs/blindness.dm
index 06a5a46b9427b..edb10d27ba44b 100644
--- a/code/datums/status_effects/debuffs/blindness.dm
+++ b/code/datums/status_effects/debuffs/blindness.dm
@@ -11,7 +11,12 @@
// fullheal should instead remove all the sources and in turn cure this
/// Static list of signals that, when received, we force an update to our nearsighted overlay
- var/static/list/update_signals = list(SIGNAL_ADDTRAIT(TRAIT_NEARSIGHTED_CORRECTED), SIGNAL_REMOVETRAIT(TRAIT_NEARSIGHTED_CORRECTED))
+ var/static/list/update_signals = list(
+ SIGNAL_ADDTRAIT(TRAIT_NEARSIGHTED_CORRECTED),
+ SIGNAL_REMOVETRAIT(TRAIT_NEARSIGHTED_CORRECTED),
+ SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS),
+ SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS),
+ )
/// How severe is our nearsightedness right now
var/overlay_severity = 2
@@ -37,7 +42,11 @@
var/mob/living/carbon/human/human_owner = owner
if (human_owner.get_eye_scars())
return TRUE
- return !HAS_TRAIT(owner, TRAIT_NEARSIGHTED_CORRECTED)
+ if(HAS_TRAIT(owner, TRAIT_NEARSIGHTED_CORRECTED))
+ return FALSE
+ if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS))
+ return FALSE
+ return TRUE
/// Updates our nearsightd overlay, either removing it if we have the trait or adding it if we don't
/datum/status_effect/grouped/nearsighted/proc/update_nearsighted_overlay()
@@ -61,6 +70,10 @@
id = "blindness"
tick_interval = STATUS_EFFECT_NO_TICK
alert_type = /atom/movable/screen/alert/status_effect/blind
+ var/static/list/update_signals = list(
+ SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS),
+ SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS),
+ )
// This is not "remove on fullheal" as in practice,
// fullheal should instead remove all the sources and in turn cure this
@@ -68,14 +81,34 @@
if(!CAN_BE_BLIND(owner))
return FALSE
+ RegisterSignals(owner, update_signals, PROC_REF(update_blindness))
+
+ update_blindness()
+
+ return ..()
+
+/datum/status_effect/grouped/blindness/proc/update_blindness()
+ if(!CAN_BE_BLIND(owner)) // future proofing
+ qdel(src)
+ return
+
+ if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS))
+ make_unblind()
+ return
+ make_blind()
+
+/datum/status_effect/grouped/blindness/proc/make_blind()
owner.overlay_fullscreen(id, /atom/movable/screen/fullscreen/blind)
// You are blind - at most, able to make out shapes near you
owner.add_client_colour(/datum/client_colour/monochrome/blind)
- return ..()
-/datum/status_effect/grouped/blindness/on_remove()
+/datum/status_effect/grouped/blindness/proc/make_unblind()
owner.clear_fullscreen(id)
owner.remove_client_colour(/datum/client_colour/monochrome/blind)
+
+/datum/status_effect/grouped/blindness/on_remove()
+ make_unblind()
+ UnregisterSignal(owner, update_signals)
return ..()
/atom/movable/screen/alert/status_effect/blind
diff --git a/code/datums/status_effects/debuffs/hallucination.dm b/code/datums/status_effects/debuffs/hallucination.dm
index 3f24ab02e60ac..66e85f1900a23 100644
--- a/code/datums/status_effects/debuffs/hallucination.dm
+++ b/code/datums/status_effects/debuffs/hallucination.dm
@@ -14,27 +14,39 @@
/// The cooldown for when the next hallucination can occur
COOLDOWN_DECLARE(hallucination_cooldown)
-/datum/status_effect/hallucination/on_creation(mob/living/new_owner, duration)
+/datum/status_effect/hallucination/on_creation(mob/living/new_owner, duration, lower_tick_interval, upper_tick_interval)
if(isnum(duration))
src.duration = duration
+ if(isnum(lower_tick_interval))
+ src.lower_tick_interval = lower_tick_interval
+ if(isnum(upper_tick_interval))
+ src.upper_tick_interval = upper_tick_interval
return ..()
/datum/status_effect/hallucination/on_apply()
if(owner.mob_biotypes & barred_biotypes)
return FALSE
+ if(HAS_TRAIT(owner, TRAIT_HALLUCINATION_IMMUNE))
+ return FALSE
RegisterSignal(owner, COMSIG_LIVING_HEALTHSCAN, PROC_REF(on_health_scan))
+ RegisterSignal(owner, SIGNAL_ADDTRAIT(TRAIT_HALLUCINATION_IMMUNE), PROC_REF(delete_self))
if(iscarbon(owner))
RegisterSignal(owner, COMSIG_CARBON_CHECKING_BODYPART, PROC_REF(on_check_bodypart))
RegisterSignal(owner, COMSIG_CARBON_BUMPED_AIRLOCK_OPEN, PROC_REF(on_bump_airlock))
return TRUE
+/datum/status_effect/hallucination/proc/delete_self()
+ SIGNAL_HANDLER
+ qdel(src)
+
/datum/status_effect/hallucination/on_remove()
UnregisterSignal(owner, list(
COMSIG_LIVING_HEALTHSCAN,
COMSIG_CARBON_CHECKING_BODYPART,
COMSIG_CARBON_BUMPED_AIRLOCK_OPEN,
+ SIGNAL_ADDTRAIT(TRAIT_HALLUCINATION_IMMUNE),
))
/// Signal proc for [COMSIG_LIVING_HEALTHSCAN]. Show we're hallucinating to (advanced) scanners.
diff --git a/code/datums/status_effects/debuffs/screen_blur.dm b/code/datums/status_effects/debuffs/screen_blur.dm
index abdd07d3cd59b..acdce13b5a08a 100644
--- a/code/datums/status_effects/debuffs/screen_blur.dm
+++ b/code/datums/status_effects/debuffs/screen_blur.dm
@@ -18,7 +18,8 @@
return FALSE
// Refresh the blur when a client jumps into the mob, in case we get put on a clientless mob with no hud
- RegisterSignal(owner, COMSIG_MOB_LOGIN, PROC_REF(update_blur))
+ RegisterSignals(owner, list(COMSIG_MOB_LOGIN, SIGNAL_ADDTRAIT(TRAIT_SIGHT_BYPASS), SIGNAL_REMOVETRAIT(TRAIT_SIGHT_BYPASS)), PROC_REF(update_blur))
+
// Apply initial blur
update_blur()
return TRUE
@@ -43,10 +44,13 @@
if(!owner.hud_used)
return
+ var/atom/movable/plane_master_controller/game_plane_master_controller = owner.hud_used.plane_master_controllers[PLANE_MASTERS_GAME]
+ if(HAS_TRAIT(owner, TRAIT_SIGHT_BYPASS))
+ game_plane_master_controller.remove_filter("eye_blur")
+ return
+
var/time_left_in_seconds = (duration - world.time) / (1 SECONDS)
var/amount_of_blur = clamp(time_left_in_seconds * BLUR_DURATION_TO_INTENSITY, 0.6, 3)
-
- var/atom/movable/plane_master_controller/game_plane_master_controller = owner.hud_used.plane_master_controllers[PLANE_MASTERS_GAME]
game_plane_master_controller.add_filter("eye_blur", 1, gauss_blur_filter(amount_of_blur))
#undef BLUR_DURATION_TO_INTENSITY
diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm
index 96233e59405b9..856c1204c720f 100644
--- a/code/datums/storage/storage.dm
+++ b/code/datums/storage/storage.dm
@@ -693,10 +693,12 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches)
/datum/storage/proc/on_preattack(datum/source, obj/item/thing, mob/user, params)
SIGNAL_HANDLER
- if(!istype(thing) || !allow_quick_gather || thing.atom_storage)
+ if(!istype(thing) || thing == parent.loc || !allow_quick_gather || thing.atom_storage)
return
if(collection_mode == COLLECT_ONE)
+ if(thing.loc == user)
+ user.dropItemToGround(thing, silent = TRUE) //this is nessassary to update any inventory slot it is attached to
attempt_insert(thing, user)
return COMPONENT_CANCEL_ATTACK_CHAIN
diff --git a/code/datums/wires/mulebot.dm b/code/datums/wires/mulebot.dm
index beb58fb1ce3b4..ec38d72898196 100644
--- a/code/datums/wires/mulebot.dm
+++ b/code/datums/wires/mulebot.dm
@@ -29,18 +29,24 @@
if(WIRE_MOTOR1, WIRE_MOTOR2)
if(is_cut(WIRE_MOTOR1) && is_cut(WIRE_MOTOR2))
ADD_TRAIT(mule, TRAIT_IMMOBILIZED, MOTOR_LACK_TRAIT)
+ holder.audible_message(span_hear("The motors of [src] go silent."), null, 1)
else
REMOVE_TRAIT(mule, TRAIT_IMMOBILIZED, MOTOR_LACK_TRAIT)
+ holder.audible_message(span_hear("The motors of [src] whir to life!"), null, 1)
if(is_cut(WIRE_MOTOR1))
mule.set_varspeed(FAST_MOTOR_SPEED)
+ holder.audible_message(span_hear("The motors of [src] speed up!"), null, 1)
else if(is_cut(WIRE_MOTOR2))
mule.set_varspeed(AVERAGE_MOTOR_SPEED)
+ holder.audible_message(span_hear("The motors of [src] whir."), null, 1)
else
mule.set_varspeed(SLOW_MOTOR_SPEED)
+ holder.audible_message(span_hear("The motors of [src] move gently."), null, 1)
if(WIRE_AVOIDANCE)
if (!isnull(source))
log_combat(source, mule, "[is_cut(WIRE_AVOIDANCE) ? "cut" : "mended"] the MULE safety wire of")
+ holder.audible_message(span_hear("Something inside [src] clicks ominously!"), null, 1)
/datum/wires/mulebot/on_pulse(wire)
var/mob/living/simple_animal/bot/mulebot/mule = holder
diff --git a/code/game/machinery/computer/orders/order_computer/order_computer.dm b/code/game/machinery/computer/orders/order_computer/order_computer.dm
index 1b20e876ce583..edd7b7239047f 100644
--- a/code/game/machinery/computer/orders/order_computer/order_computer.dm
+++ b/code/game/machinery/computer/orders/order_computer/order_computer.dm
@@ -120,7 +120,8 @@ GLOBAL_LIST_EMPTY(order_console_products)
"cat" = item.category_index,
"ref" = REF(item),
"cost" = round(item.cost_per_order * cargo_cost_multiplier),
- "product_icon" = icon2base64(getFlatIcon(image(icon = initial(item.item_path.icon), icon_state = initial(item.item_path.icon_state)), no_anim=TRUE))
+ "icon" = item.item_path::icon,
+ "icon_state" = item.item_path::icon_state,
))
return data
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 858f2dffefff2..36828273f1944 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -548,18 +548,20 @@
if(welded || operating)
return
+ var/atom/crowbar_owner = acting_object.loc //catchs mechs and any other non-mob using a crowbar
+
if(density)
being_held_open = TRUE
- user.balloon_alert_to_viewers("holding firelock open", "holding firelock open")
+ crowbar_owner.balloon_alert_to_viewers("holding firelock open", "holding firelock open")
COOLDOWN_START(src, activation_cooldown, REACTIVATION_DELAY)
open()
- if(QDELETED(user))
+ if(QDELETED(crowbar_owner))
being_held_open = FALSE
return
- RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(handle_held_open_adjacency))
- RegisterSignal(user, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(handle_held_open_adjacency))
- RegisterSignal(user, COMSIG_QDELETING, PROC_REF(handle_held_open_adjacency))
- handle_held_open_adjacency(user)
+ RegisterSignal(crowbar_owner, COMSIG_MOVABLE_MOVED, PROC_REF(handle_held_open_adjacency))
+ RegisterSignal(crowbar_owner, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(handle_held_open_adjacency))
+ RegisterSignal(crowbar_owner, COMSIG_QDELETING, PROC_REF(handle_held_open_adjacency))
+ handle_held_open_adjacency(crowbar_owner)
else
close()
diff --git a/code/game/objects/effects/portals.dm b/code/game/objects/effects/portals.dm
index 18f633504264f..21a51ba9bcb42 100644
--- a/code/game/objects/effects/portals.dm
+++ b/code/game/objects/effects/portals.dm
@@ -130,29 +130,35 @@
linked = null
return ..()
-/obj/effect/portal/attack_ghost(mob/dead/observer/O)
- if(!teleport(O, TRUE))
+/obj/effect/portal/attack_ghost(mob/dead/observer/ghost)
+ if(!teleport(ghost, force = TRUE))
return ..()
+ return BULLET_ACT_FORCE_PIERCE
-/obj/effect/portal/proc/teleport(atom/movable/M, force = FALSE)
- if(!force && (!istype(M) || iseffect(M) || (ismecha(M) && !mech_sized) || (!isobj(M) && !ismob(M)))) //Things that shouldn't teleport.
+/obj/effect/portal/bullet_act(obj/projectile/hitting_projectile, def_zone, piercing_hit)
+ if (!teleport(hitting_projectile, force = TRUE))
+ return ..()
+ return BULLET_ACT_FORCE_PIERCE
+
+/obj/effect/portal/proc/teleport(atom/movable/moving, force = FALSE)
+ if(!force && (!istype(moving) || iseffect(moving) || (ismecha(moving) && !mech_sized) || (!isobj(moving) && !ismob(moving)))) //Things that shouldn't teleport.
return
var/turf/real_target = get_link_target_turf()
if(!istype(real_target))
return FALSE
- if(!force && (!ismecha(M) && !isprojectile(M) && M.anchored && !allow_anchored))
+ if(!force && (!ismecha(moving) && !isprojectile(moving) && moving.anchored && !allow_anchored))
return
var/no_effect = FALSE
if(last_effect == world.time || sparkless)
no_effect = TRUE
else
last_effect = world.time
- var/turf/start_turf = get_turf(M)
- if(do_teleport(M, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel, forced = force_teleport))
- if(isprojectile(M))
- var/obj/projectile/P = M
+ var/turf/start_turf = get_turf(moving)
+ if(do_teleport(moving, real_target, innate_accuracy_penalty, no_effects = no_effect, channel = teleport_channel, forced = force_teleport))
+ if(isprojectile(moving))
+ var/obj/projectile/P = moving
P.ignore_source_check = TRUE
- new /obj/effect/temp_visual/portal_animation(start_turf, src, M)
+ new /obj/effect/temp_visual/portal_animation(start_turf, src, moving)
playsound(start_turf, SFX_PORTAL_ENTER, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
playsound(real_target, SFX_PORTAL_ENTER, 50, TRUE, SHORT_RANGE_SOUND_EXTRARANGE)
return TRUE
@@ -189,7 +195,7 @@
linked = P
break
-/obj/effect/portal/permanent/teleport(atom/movable/M, force = FALSE)
+/obj/effect/portal/permanent/teleport(atom/movable/moving, force = FALSE)
set_linked() // update portal links
. = ..()
@@ -213,9 +219,9 @@
name = "one-use portal"
desc = "This is probably the worst decision you'll ever make in your life."
-/obj/effect/portal/permanent/one_way/one_use/teleport(atom/movable/M, force = FALSE)
+/obj/effect/portal/permanent/one_way/one_use/teleport(atom/movable/moving, force = FALSE)
. = ..()
- if (. && !isdead(M))
+ if (. && !isdead(moving))
expire()
/**
diff --git a/code/game/objects/items/stacks/sheets/mineral.dm b/code/game/objects/items/stacks/sheets/mineral.dm
index 0d4393efea6a4..ef3ddb77c0e44 100644
--- a/code/game/objects/items/stacks/sheets/mineral.dm
+++ b/code/game/objects/items/stacks/sheets/mineral.dm
@@ -41,6 +41,8 @@ GLOBAL_LIST_INIT(sandstone_recipes, list ( \
merge_type = /obj/item/stack/sheet/mineral/sandstone
walltype = /turf/closed/wall/mineral/sandstone
material_type = /datum/material/sandstone
+ drop_sound = SFX_STONE_DROP
+ pickup_sound = SFX_STONE_PICKUP
/obj/item/stack/sheet/mineral/sandstone/get_main_recipes()
. = ..()
diff --git a/code/game/objects/structures/ore_containers.dm b/code/game/objects/structures/ore_containers.dm
index 6bc6f680116f4..75c7a03cfcfa9 100644
--- a/code/game/objects/structures/ore_containers.dm
+++ b/code/game/objects/structures/ore_containers.dm
@@ -23,25 +23,16 @@
ui.open()
/obj/structure/ore_container/ui_data(mob/user)
- var/list/data = list()
- data["ores"] = list()
+ var/list/ores = list()
for(var/obj/item/stack/ore/ore_item in contents)
- data["ores"] += list(list(
+ ores += list(list(
"id" = REF(ore_item),
"name" = ore_item.name,
"amount" = ore_item.amount,
+ "icon" = ore_item::icon,
+ "icon_state" = ore_item::icon_state,
))
- return data
-
-/obj/structure/ore_container/ui_static_data(mob/user)
- var/list/data = list()
- data["ore_images"] = list()
- for(var/obj/item/stack/ore_item as anything in subtypesof(/obj/item/stack/ore))
- data["ore_images"] += list(list(
- "name" = initial(ore_item.name),
- "icon" = icon2base64(getFlatIcon(image(icon = initial(ore_item.icon), icon_state = initial(ore_item.icon_state)), no_anim=TRUE))
- ))
- return data
+ return list("ores" = ores)
/obj/structure/ore_container/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
diff --git a/code/game/world.dm b/code/game/world.dm
index fe55b3963b504..48ab5b1bd7c24 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -8,6 +8,13 @@
GLOBAL_VAR(restart_counter)
GLOBAL_VAR(tracy_log)
+GLOBAL_PROTECT(tracy_log)
+GLOBAL_VAR(tracy_initialized)
+GLOBAL_PROTECT(tracy_initialized)
+GLOBAL_VAR(tracy_init_error)
+GLOBAL_PROTECT(tracy_init_error)
+GLOBAL_VAR(tracy_init_reason)
+GLOBAL_PROTECT(tracy_init_reason)
/**
* WORLD INITIALIZATION
@@ -66,15 +73,29 @@ GLOBAL_VAR(tracy_log)
/world/proc/Genesis(tracy_initialized = FALSE)
RETURN_TYPE(/datum/controller/master)
+ GLOB.tracy_initialized = FALSE
+#ifndef OPENDREAM
+ if(!tracy_initialized)
#ifdef USE_BYOND_TRACY
#warn USE_BYOND_TRACY is enabled
- if(!tracy_initialized)
+ var/should_init_tracy = TRUE
+ GLOB.tracy_init_reason = "USE_BYOND_TRACY defined"
#else
- if(!tracy_initialized && (USE_TRACY_PARAMETER in params))
+ var/should_init_tracy = FALSE
+ if(USE_TRACY_PARAMETER in params)
+ should_init_tracy = TRUE
+ GLOB.tracy_init_reason = "world.params"
+ if(fexists(TRACY_ENABLE_PATH))
+ GLOB.tracy_init_reason ||= "enabled for round"
+ SEND_TEXT(world.log, "[TRACY_ENABLE_PATH] exists, initializing byond-tracy!")
+ should_init_tracy = TRUE
+ fdel(TRACY_ENABLE_PATH)
+#endif
+ if(should_init_tracy)
+ init_byond_tracy()
+ Genesis(tracy_initialized = TRUE)
+ return
#endif
- GLOB.tracy_log = init_byond_tracy()
- Genesis(tracy_initialized = TRUE)
- return
Profile(PROFILE_RESTART)
Profile(PROFILE_RESTART, type = "sendmaps")
@@ -331,6 +352,7 @@ GLOBAL_VAR(tracy_log)
if(do_hard_reboot)
log_world("World hard rebooted at [time_stamp()]")
shutdown_logging() // See comment below.
+ shutdown_byond_tracy()
auxcleanup()
TgsEndProcess()
return ..()
@@ -338,6 +360,7 @@ GLOBAL_VAR(tracy_log)
log_world("World rebooted at [time_stamp()]")
shutdown_logging() // Past this point, no logging procs can be used, at risk of data loss.
+ shutdown_byond_tracy()
auxcleanup()
TgsReboot() // TGS can decide to kill us right here, so it's important to do it last
@@ -351,6 +374,7 @@ GLOBAL_VAR(tracy_log)
call_ext(debug_server, "auxtools_shutdown")()
/world/Del()
+ shutdown_byond_tracy()
auxcleanup()
. = ..()
@@ -483,21 +507,31 @@ GLOBAL_VAR(tracy_log)
DREAMLUAU_SET_EXECUTION_LIMIT_MILLIS(tick_lag * 100)
/world/proc/init_byond_tracy()
- var/library
-
- switch (system_type)
- if (MS_WINDOWS)
- library = "prof.dll"
- if (UNIX)
- library = "libprof.so"
- else
- CRASH("Unsupported platform: [system_type]")
+ if(!fexists(TRACY_DLL_PATH))
+ SEND_TEXT(world.log, "Error initializing byond-tracy: [TRACY_DLL_PATH] not found!")
+ CRASH("Error initializing byond-tracy: [TRACY_DLL_PATH] not found!")
- var/init_result = call_ext(library, "init")("block")
+ var/init_result = call_ext(TRACY_DLL_PATH, "init")("block")
if(length(init_result) != 0 && init_result[1] == ".") // if first character is ., then it returned the output filename
- return init_result
+ SEND_TEXT(world.log, "byond-tracy initialized (logfile: [init_result])")
+ GLOB.tracy_initialized = TRUE
+ return GLOB.tracy_log = init_result
+ else if(init_result == "already initialized") // not gonna question it.
+ GLOB.tracy_initialized = TRUE
+ SEND_TEXT(world.log, "byond-tracy already initialized ([GLOB.tracy_log ? "logfile: [GLOB.tracy_log]" : "no logfile"])")
else if(init_result != "0")
+ GLOB.tracy_init_error = init_result
+ SEND_TEXT(world.log, "Error initializing byond-tracy: [init_result]")
CRASH("Error initializing byond-tracy: [init_result]")
+ else
+ GLOB.tracy_initialized = TRUE
+ SEND_TEXT(world.log, "byond-tracy initialized (no logfile)")
+
+/world/proc/shutdown_byond_tracy()
+ if(GLOB.tracy_initialized)
+ SEND_TEXT(world.log, "Shutting down byond-tracy")
+ GLOB.tracy_initialized = FALSE
+ call_ext(TRACY_DLL_PATH, "destroy")()
/world/proc/init_debugger()
var/dll = GetConfig("env", "AUXTOOLS_DEBUG_DLL")
diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm
index b6c5e10ca1d81..13f1995c9ba3d 100644
--- a/code/modules/admin/verbs/debug.dm
+++ b/code/modules/admin/verbs/debug.dm
@@ -852,3 +852,42 @@ ADMIN_VERB(check_missing_sprites, R_DEBUG, "Debug Worn Item Sprites", "We're can
actual_file_name = 'icons/mob/clothing/belt_mirror.dmi'
if(!(sprite.icon_state in icon_states(actual_file_name)))
to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE)
+
+#ifndef OPENDREAM
+ADMIN_VERB(start_tracy, R_DEBUG, "Run Tracy Now", "Start running the byond-tracy profiler immediately", ADMIN_CATEGORY_DEBUG)
+ if(GLOB.tracy_initialized)
+ to_chat(user, span_warning("byond-tracy is already running!"), avoid_highlighting = TRUE, type = MESSAGE_TYPE_DEBUG, confidential = TRUE)
+ return
+ else if(GLOB.tracy_init_error)
+ to_chat(user, span_danger("byond-tracy failed to initialize during an earlier attempt: [GLOB.tracy_init_error]"), avoid_highlighting = TRUE, type = MESSAGE_TYPE_DEBUG, confidential = TRUE)
+ return
+ message_admins(span_adminnotice("[key_name_admin(user)] is trying to start the byond-tracy profiler."))
+ log_admin("[key_name(user)] is trying to start the byond-tracy profiler.")
+ GLOB.tracy_initialized = FALSE
+ GLOB.tracy_init_reason = "[user.ckey]"
+ world.init_byond_tracy()
+ if(GLOB.tracy_init_error)
+ to_chat(user, span_danger("byond-tracy failed to initialize: [GLOB.tracy_init_error]"), avoid_highlighting = TRUE, type = MESSAGE_TYPE_DEBUG, confidential = TRUE)
+ message_admins(span_adminnotice("[key_name_admin(user)] tried to start the byond-tracy profiler, but it failed to initialize ([GLOB.tracy_init_error])"))
+ log_admin("[key_name(user)] tried to start the byond-tracy profiler, but it failed to initialize ([GLOB.tracy_init_error])")
+ return
+ to_chat(user, span_notice("byond-tracy successfully started!"), avoid_highlighting = TRUE, type = MESSAGE_TYPE_DEBUG, confidential = TRUE)
+ message_admins(span_adminnotice("[key_name_admin(user)] started the byond-tracy profiler."))
+ log_admin("[key_name(user)] started the byond-tracy profiler.")
+ if(GLOB.tracy_log)
+ rustg_file_write("[GLOB.tracy_log]", "[GLOB.log_directory]/tracy.loc")
+
+ADMIN_VERB_CUSTOM_EXIST_CHECK(start_tracy)
+ return CONFIG_GET(flag/allow_tracy_start) && fexists(TRACY_DLL_PATH)
+
+ADMIN_VERB(queue_tracy, R_DEBUG, "Toggle Tracy Next Round", "Toggle running the byond-tracy profiler next round", ADMIN_CATEGORY_DEBUG)
+ if(fexists(TRACY_ENABLE_PATH))
+ fdel(TRACY_ENABLE_PATH)
+ else
+ rustg_file_write("[user.ckey]", TRACY_ENABLE_PATH)
+ message_admins(span_adminnotice("[key_name_admin(user)] [fexists(TRACY_ENABLE_PATH) ? "enabled" : "disabled"] the byond-tracy profiler for next round."))
+ log_admin("[key_name(user)] [fexists(TRACY_ENABLE_PATH) ? "enabled" : "disabled"] the byond-tracy profiler for next round.")
+
+ADMIN_VERB_CUSTOM_EXIST_CHECK(queue_tracy)
+ return CONFIG_GET(flag/allow_tracy_queue) && fexists(TRACY_DLL_PATH)
+#endif
diff --git a/code/modules/antagonists/heretic/magic/star_touch.dm b/code/modules/antagonists/heretic/magic/star_touch.dm
index d9cd5a05eab2b..e8e824cc71851 100644
--- a/code/modules/antagonists/heretic/magic/star_touch.dm
+++ b/code/modules/antagonists/heretic/magic/star_touch.dm
@@ -201,35 +201,6 @@
if(current_target)
on_beam_hit(current_target)
-/// Checks if the beam is going through an invalid turf
-/datum/status_effect/cosmic_beam/proc/los_check(atom/movable/user, mob/target)
- var/turf/user_turf = user.loc
- if(!istype(user_turf))
- return FALSE
- var/obj/dummy = new(user_turf)
- dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE //Grille/Glass so it can be used through common windows
- var/turf/previous_step = user_turf
- var/first_step = TRUE
- for(var/turf/next_step as anything in (get_line(user_turf, target) - user_turf))
- if(first_step)
- for(var/obj/blocker in user_turf)
- if(!blocker.density || !(blocker.flags_1 & ON_BORDER_1))
- continue
- if(blocker.CanPass(dummy, get_dir(user_turf, next_step)))
- continue
- return FALSE // Could not leave the first turf.
- first_step = FALSE
- if(next_step.density)
- qdel(dummy)
- return FALSE
- for(var/atom/movable/movable as anything in next_step)
- if(!movable.CanPass(dummy, get_dir(next_step, previous_step)))
- qdel(dummy)
- return FALSE
- previous_step = next_step
- qdel(dummy)
- return TRUE
-
/// What to add when the beam connects to a target
/datum/status_effect/cosmic_beam/proc/on_beam_hit(mob/living/target)
if(!istype(target, /mob/living/basic/heretic_summon/star_gazer))
diff --git a/code/modules/client/client_colour.dm b/code/modules/client/client_colour.dm
index 4ca500a9e7198..08e79c305a454 100644
--- a/code/modules/client/client_colour.dm
+++ b/code/modules/client/client_colour.dm
@@ -220,6 +220,9 @@
/datum/client_colour/malfunction
colour = list(/*R*/ 0,0,0,0, /*G*/ 0,175,0,0, /*B*/ 0,0,0,0, /*A*/ 0,0,0,1, /*C*/0,-130,0,0) // Matrix colors
+/datum/client_colour/perceptomatrix
+ colour = list(/*R*/ 1,0,0,0, /*G*/ 0,1,0,0, /*B*/ 0,0,1,0, /*A*/ 0,0,0,1, /*C*/0,-0.02,-0.02,0) // veeery slightly pink
+
/datum/client_colour/monochrome
colour = COLOR_MATRIX_GRAYSCALE
priority = PRIORITY_HIGH //we can't see colors anyway!
diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm
index c8e9e9a64c270..fe559b2b71bfa 100644
--- a/code/modules/client/client_defines.dm
+++ b/code/modules/client/client_defines.dm
@@ -269,3 +269,7 @@
///Which ambient sound this client is currently being provided.
var/current_ambient_sound
+
+ /// Does this client's mob need to rebuild its plane masters after login?
+ /// This is currently only used so a client can switch between 515 and 516 without breaking their rendering.
+ var/rebuild_plane_masters = FALSE
diff --git a/code/modules/client/client_procs.dm b/code/modules/client/client_procs.dm
index e0f359ac1e639..bc720ddb1dcc5 100644
--- a/code/modules/client/client_procs.dm
+++ b/code/modules/client/client_procs.dm
@@ -329,10 +329,20 @@ GLOBAL_LIST_INIT(blacklisted_builds, list(
if(GLOB.player_details[ckey])
reconnecting = TRUE
player_details = GLOB.player_details[ckey]
- player_details.byond_version = full_version
+ var/old_version = player_details.byond_version
+ player_details.byond_version = byond_version
+ player_details.byond_build = byond_build
+
+#if MIN_COMPILER_VERSION > 516
+ #warn Fully change default relay_loc to "1,1", rather than changing it based on client version
+#endif
+ if(old_version != byond_version)
+ rebuild_plane_masters = TRUE
+
else
player_details = new(ckey)
- player_details.byond_version = full_version
+ player_details.byond_version = byond_version
+ player_details.byond_build = byond_build
GLOB.player_details[ckey] = player_details
diff --git a/code/modules/client/player_details.dm b/code/modules/client/player_details.dm
index 3a880dcdbb550..d0982a0c31268 100644
--- a/code/modules/client/player_details.dm
+++ b/code/modules/client/player_details.dm
@@ -1,6 +1,6 @@
///assoc list of ckey -> /datum/player_details
-GLOBAL_LIST_EMPTY(player_details)
+GLOBAL_LIST_EMPTY_TYPED(player_details, /datum/player_details)
/// Tracks information about a client between log in and log outs
/datum/player_details
@@ -18,8 +18,10 @@ GLOBAL_LIST_EMPTY(player_details)
/// Lazylist of preference slots this client has joined the round under
/// Numbers are stored as strings
var/list/joined_as_slots
- /// Version of byond this client is using
- var/byond_version = "Unknown"
+ /// Major version of BYOND this client is using.
+ var/byond_version
+ /// Build number of BYOND this client is using.
+ var/byond_build
/// Tracks achievements they have earned
var/datum/achievement_data/achievements
/// World.time this player last died
@@ -35,6 +37,12 @@ GLOBAL_LIST_EMPTY(player_details)
previous_names += html_encode("[previous_name] ([played_names[previous_name]])")
return previous_names.Join("; ")
+/// Returns the full version string (i.e 515.1642) of the BYOND version and build.
+/datum/player_details/proc/full_byond_version()
+ if(!byond_version)
+ return "Unknown"
+ return "[byond_version].[byond_build || "xxx"]"
+
/// Adds the new names to the player's played_names list on their /datum/player_details for use of admins.
/// `ckey` should be their ckey, and `data` should be an associative list with the keys being the names they played under and the values being the unique mob ID tied to that name.
/proc/log_played_names(ckey, data)
diff --git a/code/modules/clothing/head/perceptomatrix.dm b/code/modules/clothing/head/perceptomatrix.dm
new file mode 100644
index 0000000000000..f11bad99eaf5b
--- /dev/null
+++ b/code/modules/clothing/head/perceptomatrix.dm
@@ -0,0 +1,248 @@
+
+#define PERCEPTOMATRIX_INACTIVE_FLAGS SNUG_FIT|STACKABLE_HELMET_EXEMPT|STOPSPRESSUREDAMAGE|BLOCK_GAS_SMOKE_EFFECT
+#define PERCEPTOMATRIX_ACTIVE_FLAGS PERCEPTOMATRIX_INACTIVE_FLAGS|CASTING_CLOTHES // we love casting spells
+
+/// Belt which can turn you into a beast, once an anomaly core is inserted
+/obj/item/clothing/head/helmet/perceptomatrix
+ name = "perceptomatrix helm"
+ desc = "This piece of headgear harnesses the energies of a hallucinative anomaly to create a safe audiovisual replica of -all- external stimuli directly into the cerebral cortex, \
+ granting the user effective immunity to both psychic threats, and anything that would affect their perception - be it ear, eye, or even brain damage. \
+ It can also violently discharge said energy, inducing hallucinations in others."
+ icon_state = "perceptomatrix_helmet_inactive"
+ worn_icon_state = "perceptomatrix_helmet_inactive"
+ base_icon_state = "perceptomatrix_helmet"
+ force = 10
+ dog_fashion = null
+ cold_protection = HEAD
+ min_cold_protection_temperature = HELMET_MIN_TEMP_PROTECT
+ heat_protection = HEAD
+ max_heat_protection_temperature = HELMET_MAX_TEMP_PROTECT
+ strip_delay = 8 SECONDS
+ clothing_flags = PERCEPTOMATRIX_ACTIVE_FLAGS
+ clothing_traits = list(
+ /* eye/ear protection */
+ TRAIT_NOFLASH,
+ TRAIT_TRUE_NIGHT_VISION,
+ TRAIT_SIGHT_BYPASS,
+ TRAIT_EXPANDED_FOV,
+ TRAIT_GOOD_HEARING,
+ /* mental protection */
+ TRAIT_PERCEPTUAL_TRAUMA_BYPASS,
+ TRAIT_RDS_SUPPRESSED,
+ TRAIT_MADNESS_IMMUNE,
+ TRAIT_HALLUCINATION_IMMUNE,
+ /* psychic protection */
+ TRAIT_NO_MINDSWAP,
+ TRAIT_UNCONVERTABLE,
+ )
+ flags_cover = HEADCOVERSEYES|EARS_COVERED
+ flags_inv = HIDEHAIR|HIDEFACE
+ flash_protect = FLASH_PROTECTION_WELDER_SENSITIVE
+ resistance_flags = FIRE_PROOF | ACID_PROOF
+ equip_sound = 'sound/items/handling/helmet/helmet_equip1.ogg'
+ pickup_sound = 'sound/items/handling/helmet/helmet_pickup1.ogg'
+ drop_sound = 'sound/items/handling/helmet/helmet_drop1.ogg'
+ armor_type = /datum/armor/head_helmet_matrix
+ actions_types = list(/datum/action/cooldown/spell/pointed/percept_hallucination)
+
+ /// If we have a core or not
+ var/core_installed = FALSE
+ /// Active components to add onto the mob, deleted and created on core installation/removal
+ var/list/active_components = list()
+
+// weaker overall but better against energy
+/datum/armor/head_helmet_matrix
+ melee = 15
+ bullet = 15
+ laser = 45
+ energy = 60
+ bomb = 15
+ fire = 50
+ acid = 50
+ wound = 10
+
+/obj/item/clothing/head/helmet/perceptomatrix/Initialize(mapload)
+ . = ..()
+
+ update_appearance(UPDATE_ICON_STATE)
+ update_anomaly_state()
+
+/obj/item/clothing/head/helmet/perceptomatrix/equipped(mob/living/user, slot)
+ . = ..()
+ if(slot & ITEM_SLOT_HEAD)
+ RegisterSignal(user, COMSIG_MOB_BEFORE_SPELL_CAST, PROC_REF(pre_cast_core_check))
+
+/obj/item/clothing/head/helmet/perceptomatrix/dropped(mob/living/user, silent)
+ UnregisterSignal(user, COMSIG_MOB_BEFORE_SPELL_CAST)
+ ..()
+
+// Prevent casting the spell w/o the core.
+/obj/item/clothing/head/helmet/perceptomatrix/proc/pre_cast_core_check(mob/caster, datum/action/cooldown/spell/spell)
+ SIGNAL_HANDLER
+ if((!core_installed) && spell.school == SCHOOL_PSYCHIC)
+ to_chat(caster, span_warning("You can't zap minds through [src]'s shielding without a core installed!"))
+ return SPELL_CANCEL_CAST
+
+/obj/item/clothing/head/helmet/perceptomatrix/proc/update_anomaly_state()
+
+ // If the core isn't installed, or it's temporarily deactivated, disable special functions.
+ if(!core_installed)
+ clothing_flags = PERCEPTOMATRIX_INACTIVE_FLAGS
+ detach_clothing_traits(clothing_traits)
+ QDEL_LIST(active_components)
+ RemoveElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, forced = TRUE)
+ return
+
+ clothing_flags = PERCEPTOMATRIX_ACTIVE_FLAGS
+ attach_clothing_traits(initial(clothing_traits))
+
+ // When someone makes TRAIT_DEAF an element, or status effect, or whatever, give this item a way to bypass said deafness.
+ // just blocking future instances of deafness isn't what the item is meant to do but there's no proper way to do it otherwise at the moment.
+ active_components += AddComponent(/datum/component/wearertargeting/earprotection, list(ITEM_SLOT_HEAD), reduce_amount = 2) // should be same as highest value
+ active_components += AddComponent(
+ /datum/component/anti_magic, \
+ antimagic_flags = MAGIC_RESISTANCE_MIND, \
+ inventory_flags = ITEM_SLOT_HEAD, \
+ )
+ AddElement(/datum/element/wearable_client_colour, /datum/client_colour/perceptomatrix, ITEM_SLOT_HEAD, forced = TRUE)
+
+ update_icon_state()
+
+/obj/item/clothing/head/helmet/perceptomatrix/Destroy(force)
+ QDEL_LIST(active_components)
+ return ..()
+
+/obj/item/clothing/head/helmet/perceptomatrix/examine(mob/user)
+ . = ..()
+ if (!core_installed)
+ . += span_warning("It requires a hallucination anomaly core in order to function.")
+
+/obj/item/clothing/head/helmet/perceptomatrix/item_action_slot_check(slot, mob/user, datum/action/action)
+ return slot & ITEM_SLOT_HEAD
+
+/obj/item/clothing/head/helmet/perceptomatrix/update_icon_state()
+ icon_state = base_icon_state + (core_installed ? "" : "_inactive")
+ worn_icon_state = base_icon_state + (core_installed ? "" : "_inactive")
+ return ..()
+
+/obj/item/clothing/head/helmet/perceptomatrix/item_interaction(mob/user, obj/item/weapon, params)
+ if (!istype(weapon, /obj/item/assembly/signaler/anomaly/hallucination))
+ return NONE
+ balloon_alert(user, "inserting...")
+ if (!do_after(user, delay = 3 SECONDS, target = src))
+ return ITEM_INTERACT_BLOCKING
+ qdel(weapon)
+ core_installed = TRUE
+ update_anomaly_state()
+ update_appearance(UPDATE_ICON_STATE)
+ playsound(src, 'sound/machines/crate/crate_open.ogg', 50, FALSE)
+ return ITEM_INTERACT_SUCCESS
+
+/obj/item/clothing/head/helmet/perceptomatrix/functioning
+ core_installed = TRUE
+
+/datum/action/cooldown/spell/pointed/percept_hallucination
+ name = "Hallucinate"
+ desc = "Redirect perceptual energies towards a target, staggering them."
+ button_icon_state = "blind"
+ ranged_mousepointer = 'icons/effects/mouse_pointers/blind_target.dmi'
+
+ sound = 'sound/items/weapons/emitter2.ogg'
+ school = SCHOOL_PSYCHIC
+ cooldown_time = 15 SECONDS
+
+ invocation_type = INVOCATION_NONE
+ spell_requirements = NONE
+ antimagic_flags = MAGIC_RESISTANCE_MIND
+
+ active_msg = "You prepare to zap a target with hallucinations..."
+
+ /// The amount of blurriness to apply
+ var/eye_blur_duration = 7 SECONDS
+ /// The amount of stagger to apply
+ var/stagger_duration = 3 SECONDS
+ /// The amount of hallucination to apply
+ var/hallucination_duration = 25 SECONDS
+ /// Spark system
+ var/datum/effect_system/spark_spread/quantum/spark_sys
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/New(Target)
+ . = ..()
+
+ spark_sys = new /datum/effect_system/spark_spread/quantum
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/Destroy()
+ QDEL_NULL(spark_sys)
+ return ..()
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/is_valid_target(atom/cast_on)
+ . = ..()
+ if(!.)
+ return FALSE
+ if(ishuman(cast_on))
+ return TRUE
+ if(istype(cast_on, /obj/item/food/pancakes))
+ return TRUE
+
+ return FALSE
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/proc/blows_up_pancakes_with_mind(obj/item/food/pancakes/pancakes)
+
+ owner.visible_message(
+ span_userdanger("[owner] blows up [pancakes] with [owner.p_their()] mind!"),
+ span_userdanger("You blow up [pancakes] with your mind!")
+ )
+
+ for(var/mob/chef in get_hearers_in_view(7, pancakes))
+ if(!chef.mind)
+ continue
+ // if cooked by chef, or if EITHER 5% chance OR its april fools. a || (b || c)
+ if(HAS_TRAIT_FROM(pancakes, TRAIT_FOOD_CHEF_MADE, REF(chef.mind)) || (prob(5) || check_holidays(APRIL_FOOLS)))
+ chef.say("Ma fuckin' pancakes!")
+
+ playsound(pancakes, 'sound/effects/fuse.ogg', 80)
+ animate(pancakes, time = 1, pixel_z = 12, easing = ELASTIC_EASING)
+ animate(time = 1, pixel_z = 0, easing = BOUNCE_EASING)
+ for(var/i in 1 to 15)
+ animate(color = (i % 2) ? "#ffffff": "#ff6739", time = 1, easing = QUAD_EASING, flags = ANIMATION_CONTINUE)
+
+ addtimer(CALLBACK(src, PROC_REF(pancake_explosion), pancakes), 1.5 SECONDS)
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/proc/pancake_explosion(obj/pancakes)
+ explosion(pancakes, devastation_range = -1, heavy_impact_range = -1, light_impact_range = 1, flame_range = 2)
+ qdel(pancakes)
+ StartCooldown()
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/proc/cast_fx(atom/cast_on)
+ owner.Beam(cast_on, icon_state = "greyscale_lightning", beam_color = COLOR_FADED_PINK, time = 0.5 SECONDS)
+
+ spark_sys.set_up(2, 1, get_turf(owner))
+ spark_sys.start()
+ spark_sys.set_up(4, 1, get_turf(cast_on))
+ spark_sys.start()
+
+/datum/action/cooldown/spell/pointed/percept_hallucination/cast(mob/living/carbon/human/cast_on)
+ . = ..()
+
+ cast_fx(cast_on)
+
+ if(istype(cast_on, /obj/item/food/pancakes))
+ blows_up_pancakes_with_mind(cast_on)
+ return
+
+ if(cast_on.can_block_magic(antimagic_flags))
+ to_chat(cast_on, span_notice("You feel psychic energies reflecting off you."))
+ to_chat(owner, span_warning("[cast_on] deflects the energy!"))
+ return
+
+ to_chat(cast_on, span_warning("Your brain feels like it's on fire!"))
+ cast_on.emote("scream")
+ cast_on.set_eye_blur_if_lower(eye_blur_duration)
+ cast_on.adjust_staggered(stagger_duration)
+ cast_on.apply_status_effect(/datum/status_effect/hallucination, hallucination_duration, \
+ hallucination_duration * 0.2, hallucination_duration) // lower/upper hallucination freq. bound
+
+ return
+
+#undef PERCEPTOMATRIX_INACTIVE_FLAGS
+#undef PERCEPTOMATRIX_ACTIVE_FLAGS
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index afbdeef519224..a59280ff04517 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -94,9 +94,6 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
var/valid_wearer = ismob(loc)
var/mob/wearer = loc
if(istype(tool, /obj/item/cigarette))
- if(flags_cover & MASKCOVERSMOUTH)
- balloon_alert(user, "mask's mouth is covered!")
- return ..()
if(max_filters <= 0 || cig)
balloon_alert(user, "can't hold that!")
diff --git a/code/modules/detectivework/evidence.dm b/code/modules/detectivework/evidence.dm
index c81852958b4a8..59e2f0feb86b1 100644
--- a/code/modules/detectivework/evidence.dm
+++ b/code/modules/detectivework/evidence.dm
@@ -18,23 +18,13 @@
max_slots = 1,
max_specific_storage = WEIGHT_CLASS_NORMAL,
)
+ atom_storage.allow_quick_gather = TRUE
+ atom_storage.collection_mode = COLLECT_ONE
RegisterSignal(atom_storage, COMSIG_STORAGE_STORED_ITEM, PROC_REF(on_insert))
RegisterSignal(atom_storage, COMSIG_STORAGE_REMOVED_ITEM, PROC_REF(on_remove))
atom_storage.rustle_sound = 'sound/items/evidence_bag/evidence_bag_zip.ogg'
atom_storage.remove_rustle_sound = 'sound/items/evidence_bag/evidence_bag_unzip.ogg'
-/obj/item/evidencebag/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
- if(interacting_with == loc || !isitem(interacting_with) || HAS_TRAIT(interacting_with, TRAIT_COMBAT_MODE_SKIP_INTERACTION))
- return NONE
- if(atom_storage.attempt_insert(interacting_with, user))
- return ITEM_INTERACT_SUCCESS
- return NONE
-
-/obj/item/evidencebag/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
- if(atom_storage.attempt_insert(tool, user))
- return ITEM_INTERACT_SUCCESS
- return NONE
-
/obj/item/evidencebag/update_desc(updates)
. = ..()
if(!atom_storage.get_total_weight())
@@ -65,12 +55,15 @@
/obj/item/evidencebag/proc/on_insert(datum/storage/storage, obj/item/to_insert, mob/user, force)
SIGNAL_HANDLER
+
update_weight_class(to_insert.w_class)
/obj/item/evidencebag/proc/on_remove(datum/storage/storage, obj/item/to_remove, atom/remove_to_loc, silent)
SIGNAL_HANDLER
+
if(!atom_storage.get_total_weight())
return
+
update_weight_class(WEIGHT_CLASS_TINY)
/obj/item/evidencebag/attack_self(mob/user)
diff --git a/code/modules/events/wormholes.dm b/code/modules/events/wormholes.dm
index 83028d129c4a8..5db33818d1276 100644
--- a/code/modules/events/wormholes.dm
+++ b/code/modules/events/wormholes.dm
@@ -65,7 +65,7 @@ GLOBAL_LIST_EMPTY(all_wormholes) // So we can pick wormholes to teleport to
. = ..()
GLOB.all_wormholes -= src
-/obj/effect/portal/wormhole/teleport(atom/movable/M)
+/obj/effect/portal/wormhole/teleport(atom/movable/M, force = FALSE)
if(iseffect(M)) //sparks don't teleport
return
if(M.anchored)
diff --git a/code/modules/mining/equipment/wormhole_jaunter.dm b/code/modules/mining/equipment/wormhole_jaunter.dm
index 6ffcfa7bc6752..fa9b63a4658a7 100644
--- a/code/modules/mining/equipment/wormhole_jaunter.dm
+++ b/code/modules/mining/equipment/wormhole_jaunter.dm
@@ -103,7 +103,7 @@
light_on = FALSE
wibbles = FALSE
-/obj/effect/portal/jaunt_tunnel/teleport(atom/movable/M)
+/obj/effect/portal/jaunt_tunnel/teleport(atom/movable/M, force = FALSE)
. = ..()
if(.)
// KERPLUNK
diff --git a/code/modules/mining/machine_redemption.dm b/code/modules/mining/machine_redemption.dm
index 312acb6672014..24e0f53a87ab7 100644
--- a/code/modules/mining/machine_redemption.dm
+++ b/code/modules/mining/machine_redemption.dm
@@ -229,21 +229,27 @@
for(var/datum/material/material as anything in mat_container.materials)
var/amount = mat_container.materials[material]
var/sheet_amount = amount / SHEET_MATERIAL_AMOUNT
+ var/obj/sheet_type = material.sheet_type
data["materials"] += list(list(
"name" = material.name,
"id" = REF(material),
"amount" = sheet_amount,
"category" = "material",
"value" = ore_values[material.type],
+ "icon" = sheet_type::icon,
+ "icon_state" = sheet_type::icon_state,
))
for(var/research in stored_research.researched_designs)
var/datum/design/alloy = SSresearch.techweb_design_by_id(research)
+ var/obj/alloy_type = alloy.build_path
data["materials"] += list(list(
"name" = alloy.name,
"id" = alloy.id,
"category" = "alloy",
"amount" = can_smelt_alloy(alloy),
+ "icon" = alloy_type::icon,
+ "icon_state" = alloy_type::icon_state,
))
data["disconnected"] = null
@@ -274,29 +280,6 @@
)
return data
-/obj/machinery/mineral/ore_redemption/ui_static_data(mob/user)
- var/list/data = list()
-
- var/datum/component/material_container/mat_container = materials.mat_container
- if (mat_container)
- for(var/datum/material/material as anything in mat_container.materials)
- var/obj/material_display = initial(material.sheet_type)
- data["material_icons"] += list(list(
- "id" = REF(material),
- "product_icon" = icon2base64(getFlatIcon(image(icon = initial(material_display.icon), icon_state = initial(material_display.icon_state)), no_anim=TRUE)),
- ))
-
- for(var/research in stored_research.researched_designs)
- var/datum/design/alloy = SSresearch.techweb_design_by_id(research)
- var/obj/alloy_display = initial(alloy.build_path)
- data["material_icons"] += list(list(
- "id" = alloy.id,
- "product_icon" = icon2base64(getFlatIcon(image(icon = initial(alloy_display.icon), icon_state = initial(alloy_display.icon_state)), no_anim=TRUE)),
- ))
-
- return data
-
-
/obj/machinery/mineral/ore_redemption/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
. = ..()
if(.)
diff --git a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm
index 363243a283388..7e572c2d92f63 100644
--- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm
+++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm
@@ -177,6 +177,19 @@
paralyze_chance = 0
initial_size = 0.9
+/mob/living/basic/gorilla/hostile
+ name = "Feral Gorilla"
+ maxHealth = 180
+ health = 180
+ desc = "A gorilla created via \"advanced genetic science\". While not quite as strong as their wildborne brethren, this simian still packs a punch."
+ melee_damage_lower = 15
+ melee_damage_upper = 18
+ obj_damage = 25
+ speed = 0.1
+ paralyze_chance = 0
+ initial_size = 0.9
+ faction = list(FACTION_HOSTILE)
+
/mob/living/basic/gorilla/genetics/Initialize(mapload)
. = ..()
qdel(GetComponent(/datum/component/amputating_limbs))
diff --git a/code/modules/mob/living/carbon/alien/death.dm b/code/modules/mob/living/carbon/alien/death.dm
index 85092244510a7..8671a66c98aec 100644
--- a/code/modules/mob/living/carbon/alien/death.dm
+++ b/code/modules/mob/living/carbon/alien/death.dm
@@ -7,5 +7,10 @@
/mob/living/carbon/alien/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-a")
-/mob/living/carbon/alien/spawn_dust()
- new /obj/effect/decal/remains/xeno(loc)
+/mob/living/carbon/alien/spawn_dust(just_ash)
+ if(just_ash)
+ return ..()
+
+ var/obj/effect/decal/remains/xeno/bones = new(loc)
+ bones.pixel_z = -6
+ bones.pixel_w = rand(-1, 1)
diff --git a/code/modules/mob/living/carbon/alien/larva/death.dm b/code/modules/mob/living/carbon/alien/larva/death.dm
index f33ee4efdf17d..3c4500518de89 100644
--- a/code/modules/mob/living/carbon/alien/larva/death.dm
+++ b/code/modules/mob/living/carbon/alien/larva/death.dm
@@ -15,5 +15,10 @@
/mob/living/carbon/alien/larva/gib_animation()
new /obj/effect/temp_visual/gib_animation(loc, "gibbed-l")
-/mob/living/carbon/alien/larva/spawn_dust()
- new /obj/effect/decal/remains/xeno(loc)
+/mob/living/carbon/alien/larva/spawn_dust(just_ash)
+ if(just_ash)
+ return ..()
+
+ var/obj/effect/decal/remains/xeno/bones = new(loc)
+ bones.pixel_z = -6
+ bones.pixel_w = rand(-1, 1)
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 7e8fa7f1f8d2c..dad45038f137d 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -10,11 +10,17 @@ GLOBAL_LIST_EMPTY(dead_players_during_shift)
else
new /obj/effect/gibspawner/human/bodypartless(drop_location(), src, get_static_viruses())
-/mob/living/carbon/human/spawn_dust(just_ash = FALSE)
+/mob/living/carbon/human/spawn_dust(just_ash)
if(just_ash)
- new /obj/effect/decal/cleanable/ash(loc)
- else
- new /obj/effect/decal/remains/human(loc)
+ return ..()
+
+ var/bone_type = /obj/effect/decal/remains/human
+ if(isplasmaman(src))
+ bone_type = /obj/effect/decal/remains/plasma
+
+ var/obj/effect/decal/remains/human/bones = new bone_type(loc)
+ bones.pixel_z = -6
+ bones.pixel_w = rand(-1, 1)
/mob/living/carbon/human/death(gibbed)
if(stat == DEAD)
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index 5b0e64547a016..bd72ff464a958 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -1192,7 +1192,7 @@
race = /datum/species/snail
/mob/living/carbon/human/species/vampire
- race = /datum/species/vampire
+ race = /datum/species/human/vampire
/mob/living/carbon/human/species/zombie
race = /datum/species/zombie
diff --git a/code/modules/mob/living/carbon/human/species_types/vampire.dm b/code/modules/mob/living/carbon/human/species_types/vampire.dm
index d0b052a888865..44b5d9590387a 100644
--- a/code/modules/mob/living/carbon/human/species_types/vampire.dm
+++ b/code/modules/mob/living/carbon/human/species_types/vampire.dm
@@ -4,7 +4,7 @@
///maximum a vampire will drain, they will drain less if they hit their cap
#define VAMP_DRAIN_AMOUNT 50
-/datum/species/vampire
+/datum/species/human/vampire
name = "Vampire"
id = SPECIES_VAMPIRE
examine_limb_id = SPECIES_HUMAN
@@ -18,33 +18,30 @@
)
inherent_biotypes = MOB_UNDEAD|MOB_HUMANOID
changesource_flags = MIRROR_BADMIN | MIRROR_PRIDE | WABBAJACK | ERT_SPAWN
- exotic_bloodtype = "U"
+ exotic_bloodtype = "V"
blood_deficiency_drain_rate = BLOOD_DEFICIENCY_MODIFIER // vampires already passively lose blood, so this just makes them lose it slightly more quickly when they have blood deficiency.
mutantheart = /obj/item/organ/heart/vampire
mutanttongue = /obj/item/organ/tongue/vampire
- mutantstomach = null
- mutantlungs = null
- skinned_type = /obj/item/stack/sheet/animalhide/human
///some starter text sent to the vampire initially, because vampires have shit to do to stay alive
var/info_text = "You are a Vampire. You will slowly but constantly lose blood if outside of a coffin. If inside a coffin, you will slowly heal. You may gain more blood by grabbing a live victim and using your drain ability."
-/datum/species/vampire/check_roundstart_eligible()
+/datum/species/human/vampire/check_roundstart_eligible()
if(check_holidays(HALLOWEEN))
return TRUE
return ..()
-/datum/species/vampire/on_species_gain(mob/living/carbon/human/new_vampire, datum/species/old_species)
+/datum/species/human/vampire/on_species_gain(mob/living/carbon/human/new_vampire, datum/species/old_species)
. = ..()
to_chat(new_vampire, "[info_text]")
new_vampire.skin_tone = "albino"
new_vampire.update_body(0)
RegisterSignal(new_vampire, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS, PROC_REF(damage_weakness))
-/datum/species/vampire/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
+/datum/species/human/vampire/on_species_loss(mob/living/carbon/human/C, datum/species/new_species, pref_load)
. = ..()
UnregisterSignal(C, COMSIG_MOB_APPLY_DAMAGE_MODIFIERS)
-/datum/species/vampire/spec_life(mob/living/carbon/human/vampire, seconds_per_tick, times_fired)
+/datum/species/human/vampire/spec_life(mob/living/carbon/human/vampire, seconds_per_tick, times_fired)
. = ..()
if(istype(vampire.loc, /obj/structure/closet/crate/coffin))
var/need_mob_update = FALSE
@@ -66,27 +63,27 @@
vampire.adjust_fire_stacks(3 * seconds_per_tick)
vampire.ignite_mob()
-/datum/species/vampire/proc/damage_weakness(datum/source, list/damage_mods, damage_amount, damagetype, def_zone, sharpness, attack_direction, obj/item/attacking_item)
+/datum/species/human/vampire/proc/damage_weakness(datum/source, list/damage_mods, damage_amount, damagetype, def_zone, sharpness, attack_direction, obj/item/attacking_item)
SIGNAL_HANDLER
if(istype(attacking_item, /obj/item/nullrod/whip))
damage_mods += 2
-/datum/species/vampire/get_physical_attributes()
+/datum/species/human/vampire/get_physical_attributes()
return "Vampires are afflicted with the Thirst, needing to sate it by draining the blood out of another living creature. However, they do not need to breathe or eat normally. \
They will instantly turn into dust if they run out of blood or enter a holy area. However, coffins stabilize and heal them, and they can transform into bats!"
-/datum/species/vampire/get_species_description()
+/datum/species/human/vampire/get_species_description()
return "A classy Vampire! They descend upon Space Station Thirteen Every year to spook the crew! \"Bleeg!!\""
-/datum/species/vampire/get_species_lore()
+/datum/species/human/vampire/get_species_lore()
return list(
"Vampires are unholy beings blessed and cursed with The Thirst. \
The Thirst requires them to feast on blood to stay alive, and in return it gives them many bonuses. \
Because of this, Vampires have split into two clans, one that embraces their powers as a blessing and one that rejects it.",
)
-/datum/species/vampire/create_pref_unique_perks()
+/datum/species/human/vampire/create_pref_unique_perks()
var/list/to_add = list()
to_add += list(
@@ -115,7 +112,7 @@
return to_add
// Vampire blood is special, so it needs to be handled with its own entry.
-/datum/species/vampire/create_pref_blood_perks()
+/datum/species/human/vampire/create_pref_blood_perks()
var/list/to_add = list()
to_add += list(list(
@@ -132,7 +129,7 @@
return to_add
// There isn't a "Minor Undead" biotype, so we have to explain it in an override (see: dullahans)
-/datum/species/vampire/create_pref_biotypes_perks()
+/datum/species/human/vampire/create_pref_biotypes_perks()
var/list/to_add = list()
to_add += list(list(
diff --git a/code/modules/mob/living/death.dm b/code/modules/mob/living/death.dm
index 8688e256022ba..6616736a61064 100644
--- a/code/modules/mob/living/death.dm
+++ b/code/modules/mob/living/death.dm
@@ -98,7 +98,7 @@
ghostize()
QDEL_IN(src, DUST_ANIMATION_TIME) // since this is sometimes called in the middle of movement, allow half a second for movement to finish, ghosting to happen and animation to play. Looks much nicer and doesn't cause multiple runtimes.
-/// Animates turning into dust
+/// Animates turning into dust.
/// Does not delete src afterwards, BUT it will become invisible (and grey), so ensure you handle that yourself
/atom/movable/proc/dust_animation(atom/anim_loc = src.loc)
if(isnull(anim_loc)) // the effect breaks if we have a null loc
@@ -130,8 +130,19 @@
#undef DUST_ANIMATION_TIME
+/**
+ * Spawns dust / ash or remains where the mob was
+ *
+ * just_ash: If TRUE, just ash will spawn where the mob was, as opposed to remains
+ */
/mob/living/proc/spawn_dust(just_ash = FALSE)
- new /obj/effect/decal/cleanable/ash(loc)
+ var/ash_type = /obj/effect/decal/cleanable/ash
+ if(mob_size >= MOB_SIZE_LARGE)
+ ash_type = /obj/effect/decal/cleanable/ash/large
+
+ var/obj/effect/decal/cleanable/ash/ash = new ash_type(loc)
+ ash.pixel_z = -5
+ ash.pixel_w = rand(-1, 1)
/*
* Called when the mob dies. Can also be called manually to kill a mob.
diff --git a/code/modules/mob/living/emote.dm b/code/modules/mob/living/emote.dm
index 360d975cb9ed8..3b5c012d591d4 100644
--- a/code/modules/mob/living/emote.dm
+++ b/code/modules/mob/living/emote.dm
@@ -140,22 +140,27 @@
/datum/emote/living/flap/run_emote(mob/user, params, type_override, intentional)
. = ..()
- if(ishuman(user))
- var/mob/living/carbon/human/human_user = user
- var/open = FALSE
- var/obj/item/organ/wings/functional/wings = human_user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)
-
- // open/close functional wings
- if(istype(wings))
- if(wings.wings_open)
- open = TRUE
- wings.close_wings()
- else
- wings.open_wings()
- addtimer(CALLBACK(wings, open ? TYPE_PROC_REF(/obj/item/organ/wings/functional, open_wings) : TYPE_PROC_REF(/obj/item/organ/wings/functional, close_wings)), wing_time)
+ if(!ishuman(user))
+ return
+ var/mob/living/carbon/human/human_user = user
+ var/obj/item/organ/wings/wings = human_user.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS)
- // play a flapping noise if the wing has this implemented
- wings.make_flap_sound(human_user)
+ // play a flapping noise if the wing has this implemented
+ if(!istype(wings))
+ return
+ wings.make_flap_sound(human_user)
+
+ // open/close functional wings
+ var/obj/item/organ/wings/functional/wings_functional = wings
+ if(!istype(wings_functional))
+ return
+ var/open = FALSE
+ if(wings_functional.wings_open)
+ open = TRUE
+ wings_functional.close_wings()
+ else
+ wings_functional.open_wings()
+ addtimer(CALLBACK(wings_functional, open ? TYPE_PROC_REF(/obj/item/organ/wings/functional, open_wings) : TYPE_PROC_REF(/obj/item/organ/wings/functional, close_wings)), wing_time)
/datum/emote/living/flap/aflap
key = "aflap"
diff --git a/code/modules/mob/living/silicon/death.dm b/code/modules/mob/living/silicon/death.dm
index 85e749d276541..67083168eb30e 100644
--- a/code/modules/mob/living/silicon/death.dm
+++ b/code/modules/mob/living/silicon/death.dm
@@ -1,8 +1,13 @@
/mob/living/silicon/spawn_gibs()
new /obj/effect/gibspawner/robot(drop_location(), src)
-/mob/living/silicon/spawn_dust()
- new /obj/effect/decal/remains/robot(loc)
+/mob/living/silicon/spawn_dust(just_ash)
+ if(just_ash)
+ return ..()
+
+ var/obj/effect/decal/remains/robot/robones = new(loc)
+ robones.pixel_z = -6
+ robones.pixel_w = rand(-1, 1)
/mob/living/silicon/death(gibbed)
diag_hud_set_status()
diff --git a/code/modules/mob/living/silicon/robot/death.dm b/code/modules/mob/living/silicon/robot/death.dm
index 91627b5099fe5..99c5686aa5325 100644
--- a/code/modules/mob/living/silicon/robot/death.dm
+++ b/code/modules/mob/living/silicon/robot/death.dm
@@ -7,9 +7,6 @@
QDEL_NULL(mmi)
return ..()
-/mob/living/silicon/robot/spawn_dust()
- new /obj/effect/decal/remains/robot(loc)
-
/mob/living/silicon/robot/death(gibbed)
if(stat == DEAD)
return
diff --git a/code/modules/mod/modules/_module.dm b/code/modules/mod/modules/_module.dm
index 390431300d541..565919c07ecd5 100644
--- a/code/modules/mod/modules/_module.dm
+++ b/code/modules/mod/modules/_module.dm
@@ -418,7 +418,7 @@
/obj/item/mod/module/anomaly_locked
name = "MOD anomaly locked module"
desc = "A form of a module, locked behind an anomalous core to function."
- incompatible_modules = list(/obj/item/mod/module/anomaly_locked)
+ incompatible_modules = list()
/// The core item the module runs off.
var/obj/item/assembly/signaler/anomaly/core
/// Accepted types of anomaly cores.
diff --git a/code/modules/mod/modules/module_kinesis.dm b/code/modules/mod/modules/module_kinesis.dm
index 3c9ae3310b755..733e5ab40d97b 100644
--- a/code/modules/mod/modules/module_kinesis.dm
+++ b/code/modules/mod/modules/module_kinesis.dm
@@ -17,7 +17,7 @@
accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav)
required_slots = list(ITEM_SLOT_GLOVES)
/// Range of the knesis grab.
- var/grab_range = 5
+ var/grab_range = 8
/// Time between us hitting objects with kinesis.
var/hit_cooldown_time = 1 SECONDS
/// Stat required for us to grab a mob.
diff --git a/code/modules/mod/modules/modules_science.dm b/code/modules/mod/modules/modules_science.dm
index 1d15abece56d0..8cb15d35370aa 100644
--- a/code/modules/mod/modules/modules_science.dm
+++ b/code/modules/mod/modules/modules_science.dm
@@ -55,9 +55,9 @@
desc = "A module that uses a gravitational core to make the user completely weightless."
icon_state = "antigrav"
module_type = MODULE_TOGGLE
- complexity = 3
+ complexity = 2
active_power_cost = DEFAULT_CHARGE_DRAIN * 0.7
- incompatible_modules = list(/obj/item/mod/module/anomaly_locked, /obj/item/mod/module/atrocinator)
+ incompatible_modules = list(/obj/item/mod/module/atrocinator, /obj/item/mod/module/anomaly_locked/antigrav)
accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/grav)
required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT)
@@ -88,21 +88,34 @@
icon_state = "teleporter"
module_type = MODULE_ACTIVE
complexity = 3
- use_energy_cost = DEFAULT_CHARGE_DRAIN * 5
- cooldown_time = 5 SECONDS
+ use_energy_cost = DEFAULT_CHARGE_DRAIN * 25
+ cooldown_time = 4 SECONDS
+ incompatible_modules = list(/obj/item/mod/module/anomaly_locked/teleporter)
accepted_anomalies = list(/obj/item/assembly/signaler/anomaly/bluespace)
required_slots = list(ITEM_SLOT_BACK|ITEM_SLOT_BELT)
/// Time it takes to teleport
- var/teleport_time = 3 SECONDS
+ var/teleport_time = 1 SECONDS
+ /// Maximum turf range
+ var/max_range = 9
/obj/item/mod/module/anomaly_locked/teleporter/on_select_use(atom/target)
. = ..()
if(!.)
return
var/turf/open/target_turf = get_turf(target)
- if(!istype(target_turf) || target_turf.is_blocked_turf_ignore_climbable() || !(target_turf in view(mod.wearer)))
+ if(get_dist(target_turf, mod.wearer) > max_range)
+ balloon_alert(mod.wearer, "too far!")
+ return
+ if(!istype(target_turf))
balloon_alert(mod.wearer, "invalid target!")
return
+ if(target_turf.is_blocked_turf_ignore_climbable() || !los_check(mod.wearer, target, pass_args = PASSTABLE|PASSGLASS|PASSGRILLE|PASSMOB|PASSMACHINE|PASSSTRUCTURE|PASSFLAPS|PASSWINDOW))
+ balloon_alert(mod.wearer, "blocked destination!")
+ return
+ // check early so we don't go through the whole loops
+ if(!check_teleport_valid(mod.wearer, target_turf, channel = TELEPORT_CHANNEL_BLUESPACE, original_destination = target_turf))
+ balloon_alert(mod.wearer, "something holds you back!")
+ return
balloon_alert(mod.wearer, "teleporting...")
var/matrix/pre_matrix = matrix()
pre_matrix.Scale(4, 0.25)
diff --git a/code/modules/modular_computers/file_system/programs/maintenance/camera.dm b/code/modules/modular_computers/file_system/programs/maintenance/camera.dm
index f851dada495f3..e62aa35a6088c 100644
--- a/code/modules/modular_computers/file_system/programs/maintenance/camera.dm
+++ b/code/modules/modular_computers/file_system/programs/maintenance/camera.dm
@@ -11,12 +11,18 @@
circuit_comp_type = /obj/item/circuit_component/mod_program/camera
/// Camera built-into the tablet.
- var/obj/item/camera/internal_camera
+ var/obj/item/camera/app/internal_camera
/// Latest picture taken by the app.
var/datum/picture/internal_picture
/// How many pictures were taken already, used for the camera's TGUI photo display
var/picture_number = 1
+// Special type of camera for this exact usecase to prevent harddels
+/obj/item/camera/app
+ name = "internal camera"
+ desc = "Specialized internal camera protected from the hellish depths of SSWardrobe. \
+ Yell at coders if you somehow manage to see this"
+
/datum/computer_file/program/maintenance/camera/on_install()
. = ..()
internal_camera = new(computer)
diff --git a/code/modules/power/lighting/light.dm b/code/modules/power/lighting/light.dm
index 3657bb84db83a..a13483e82c5e2 100644
--- a/code/modules/power/lighting/light.dm
+++ b/code/modules/power/lighting/light.dm
@@ -725,7 +725,7 @@
plane = FLOOR_PLANE
light_type = /obj/item/light/bulb
fitting = "bulb"
- nightshift_brightness = 3
+ nightshift_brightness = 4
fire_brightness = 4.5
/obj/machinery/light/floor/get_light_offset()
diff --git a/code/modules/projectiles/guns/special/medbeam.dm b/code/modules/projectiles/guns/special/medbeam.dm
index 0ad5caf2fec82..95da571baf547 100644
--- a/code/modules/projectiles/guns/special/medbeam.dm
+++ b/code/modules/projectiles/guns/special/medbeam.dm
@@ -83,56 +83,26 @@
last_check = world.time
- if(!los_check(loc, current_target))
+ if(!los_check(loc, current_target, mid_check = CALLBACK(src, PROC_REF(mid_los_check))))
QDEL_NULL(current_beam)//this will give the target lost message
return
if(current_target)
on_beam_tick(current_target)
-/obj/item/gun/medbeam/proc/los_check(atom/movable/user, mob/target)
- var/turf/user_turf = user.loc
- if(mounted)
- user_turf = get_turf(user)
- else if(!istype(user_turf))
- return FALSE
- var/obj/dummy = new(user_turf)
- dummy.pass_flags |= PASSTABLE|PASSGLASS|PASSGRILLE //Grille/Glass so it can be used through common windows
- var/turf/previous_step = user_turf
- var/first_step = TRUE
- for(var/turf/next_step as anything in (get_line(user_turf, target) - user_turf))
- if(first_step)
- for(var/obj/blocker in user_turf)
- if(!blocker.density || !(blocker.flags_1 & ON_BORDER_1))
- continue
- if(blocker.CanPass(dummy, get_dir(user_turf, next_step)))
- continue
- return FALSE // Could not leave the first turf.
- first_step = FALSE
- if(mounted && next_step == user_turf)
-
- continue //Mechs are dense and thus fail the check
- if(next_step.density)
+/obj/item/gun/medbeam/proc/mid_los_check(atom/movable/user, mob/target, pass_args = PASSTABLE|PASSGLASS|PASSGRILLE, turf/next_step, obj/dummy)
+ for(var/obj/effect/ebeam/medical/B in next_step)// Don't cross the str-beams!
+ if(QDELETED(current_beam))
+ break //We shouldn't be processing anymore.
+ if(QDELETED(B))
+ continue
+ if(!B.owner)
+ stack_trace("beam without an owner! [B]")
+ continue
+ if(B.owner.origin != current_beam.origin)
+ explosion(B.loc, heavy_impact_range = 3, light_impact_range = 5, flash_range = 8, explosion_cause = src)
qdel(dummy)
return FALSE
- for(var/atom/movable/movable as anything in next_step)
- if(!movable.CanPass(dummy, get_dir(next_step, previous_step)))
- qdel(dummy)
- return FALSE
- for(var/obj/effect/ebeam/medical/B in next_step)// Don't cross the str-beams!
- if(QDELETED(current_beam))
- break //We shouldn't be processing anymore.
- if(QDELETED(B))
- continue
- if(!B.owner)
- stack_trace("beam without an owner! [B]")
- continue
- if(B.owner.origin != current_beam.origin)
- explosion(B.loc, heavy_impact_range = 3, light_impact_range = 5, flash_range = 8, explosion_cause = src)
- qdel(dummy)
- return FALSE
- previous_step = next_step
- qdel(dummy)
return TRUE
/obj/item/gun/medbeam/proc/on_beam_hit(mob/living/target)
diff --git a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
index b8a2250722534..ebd392f536892 100644
--- a/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
+++ b/code/modules/reagents/chemistry/reagents/impure_reagents/impure_medicine_reagents.dm
@@ -480,6 +480,7 @@ Basically, we fill the time between now and 2s from now with hands based off the
overdose_threshold = 20
self_consuming = TRUE //No pesky liver shenanigans
chemical_flags = REAGENT_DONOTSPLIT | REAGENT_DEAD_PROCESS
+ affected_organ_flags = NONE
///If we brought someone back from the dead
var/back_from_the_dead = FALSE
/// List of trait buffs to give to the affected mob, and remove as needed.
diff --git a/code/modules/spells/spell_types/self/splattercasting_spell.dm b/code/modules/spells/spell_types/self/splattercasting_spell.dm
index 184a2afab7ca2..e76f8e3c1b9bf 100644
--- a/code/modules/spells/spell_types/self/splattercasting_spell.dm
+++ b/code/modules/spells/spell_types/self/splattercasting_spell.dm
@@ -28,7 +28,7 @@
brings unimaginable momentary torment as your heart stops, and your skin grows cold. You are now \
merely a vessel for the arcane flow. Soon, all that is left is not pain, but hunger."))
- cast_on.set_species(/datum/species/vampire)
+ cast_on.set_species(/datum/species/human/vampire)
cast_on.blood_volume = BLOOD_VOLUME_NORMAL ///for predictable blood total amounts when the spell is first cast.
cast_on.AddComponent(/datum/component/splattercasting)
diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vampire.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_vampire.png
similarity index 100%
rename from code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_vampire.png
rename to code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_human_vampire.png
diff --git a/code/modules/uplink/uplink_items/device_tools.dm b/code/modules/uplink/uplink_items/device_tools.dm
index 714c3133482c4..ef2ab6fd1fddc 100644
--- a/code/modules/uplink/uplink_items/device_tools.dm
+++ b/code/modules/uplink/uplink_items/device_tools.dm
@@ -242,9 +242,9 @@
active gravitational singularities or tesla balls towards it. This will not work when the engine is still \
in containment. Because of its size, it cannot be carried. Ordering this \
sends you a small beacon that will teleport the larger beacon to your location upon activation."
- progression_minimum = 30 MINUTES
+ progression_minimum = 20 MINUTES
item = /obj/item/sbeacondrop
- cost = 10
+ cost = 4
surplus = 0 // not while there isnt one on any station
purchasable_from = ~UPLINK_ALL_SYNDIE_OPS
diff --git a/code/modules/vehicles/mecha/mecha_movement.dm b/code/modules/vehicles/mecha/mecha_movement.dm
index 9fdbf4cef8967..aaba86d7cb832 100644
--- a/code/modules/vehicles/mecha/mecha_movement.dm
+++ b/code/modules/vehicles/mecha/mecha_movement.dm
@@ -139,6 +139,8 @@
// if we're not strafing or if we are forced to rotate or if we are holding down the key
if(dir != direction && (!strafe || forcerotate || keyheld))
setDir(direction)
+ if(!(mecha_flags & QUIET_TURNS))
+ playsound(src, turnsound, 40, TRUE)
if(keyheld || !pivot_step) //If we pivot step, we don't return here so we don't just come to a stop
return TRUE
@@ -146,10 +148,6 @@
//Otherwise just walk normally
. = try_step_multiz(direction)
- //dir and olddir are the current direction of the sprite and the old direction of the sprite respectively
- if (dir != olddir && !(mecha_flags & QUIET_TURNS))
- playsound(src, turnsound, 40, TRUE)
-
if(phasing)
use_energy(phasing_energy_drain)
if(strafe)
diff --git a/config/config.txt b/config/config.txt
index 61cf30f74df0e..8f9acdca405b1 100644
--- a/config/config.txt
+++ b/config/config.txt
@@ -610,3 +610,9 @@ UPLOAD_LIMIT 524288
## Restricts admin client uploads to the server, defined in bytes, default is 5MB
UPLOAD_LIMIT_ADMIN 5242880
+
+## Uncomment to allow admins with +DEBUG to start the byond-tracy profiler during the round.
+#ALLOW_TRACY_START
+
+## Uncomment to allow admins with +DEBUG to queue the next round to run the byond-tracy profiler.
+#ALLOW_TRACY_QUEUE
diff --git a/html/changelogs/AutoChangeLog-pr-87701.yml b/html/changelogs/AutoChangeLog-pr-87701.yml
new file mode 100644
index 0000000000000..1f05ead77f3f7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-87701.yml
@@ -0,0 +1,4 @@
+author: "carlarctg"
+delete-after: True
+changes:
+ - rscadd: "Adds the Perceptomatrix Helm, a hallucination anomaly core item"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87816.yml b/html/changelogs/AutoChangeLog-pr-87816.yml
deleted file mode 100644
index cd829eb2934bd..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87816.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Fixed scanner gates saying both bypass and detection lines when malfunctioning"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87862.yml b/html/changelogs/AutoChangeLog-pr-87862.yml
deleted file mode 100644
index 68001ac6100d9..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87862.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "carlarctg"
-delete-after: True
-changes:
- - spellcheck: "spellecheck: existence not existance"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87870.yml b/html/changelogs/AutoChangeLog-pr-87870.yml
deleted file mode 100644
index c72aff1a0ed20..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87870.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - bugfix: "silo connection on some machines won't time out when changing FPS settings"
- - code_imp: "improved attack chain code for silo connection"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87885.yml b/html/changelogs/AutoChangeLog-pr-87885.yml
deleted file mode 100644
index d6582ff3aabad..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87885.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Ben10Omintrix"
-delete-after: True
-changes:
- - bugfix: "fixes seedling ai getting stuck when trying to refill water from emptied water tanks"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87887.yml b/html/changelogs/AutoChangeLog-pr-87887.yml
deleted file mode 100644
index 5b0a6f175c032..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87887.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "Absolucy"
-delete-after: True
-changes:
- - bugfix: "Admin-deleting a mob now ghostizes it beforehand, preventing a runtime error."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87898.yml b/html/changelogs/AutoChangeLog-pr-87898.yml
deleted file mode 100644
index aa4f5a81aa944..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-87898.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "xPokee"
-delete-after: True
-changes:
- - bugfix: "fixed brains turning invisible after being washed"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-87907.yml b/html/changelogs/AutoChangeLog-pr-87907.yml
new file mode 100644
index 0000000000000..f193ce7beefb7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-87907.yml
@@ -0,0 +1,4 @@
+author: "zxaber"
+delete-after: True
+changes:
+ - bugfix: "Firelocks opened by a mech will correctly close when the mech moves out of range."
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-11.yml b/html/changelogs/archive/2024-11.yml
index b4f73b08b7b85..51197f3841a72 100644
--- a/html/changelogs/archive/2024-11.yml
+++ b/html/changelogs/archive/2024-11.yml
@@ -496,3 +496,69 @@
- bugfix: Fix using chairs in holodeck to create infinite metal
xPokee, waterpig:
- code_imp: cleaned up beserk.dm
+2024-11-15:
+ Absolucy:
+ - refactor: The ORM, "ore container", and order console UIs (produce, mining, bitrunner
+ vendors) now load icons in a more efficient manner.
+ - bugfix: Admin-deleting a mob now ghostizes it beforehand, preventing a runtime
+ error.
+ Ben10Omintrix:
+ - bugfix: fixes seedling ai getting stuck when trying to refill water from emptied
+ water tanks
+ Dawnseer:
+ - bugfix: removes the gas mask check for if the gas mask mouth is covered. Now it
+ only checks for filters and other cigs
+ GremlinSeeker:
+ - bugfix: Syndicate Biodome fixes
+ Majkl-J:
+ - bugfix: Fixes SSWardrobe stealing a camera from the camera app when on a dummy,
+ causing a harddel
+ Melbert:
+ - image: Speeds up some frames of the dust animation slightly
+ - image: Dust/remains spawned after being dusted are now aligned towards the bottom
+ of the tile
+ - image: Bigger mobs now produce bigger piles of ash
+ - image: Plasmamen now dust into plasma bones
+ SmArtKar:
+ - bugfix: Many years later, projectiles finally can pass through portals - this
+ time without crashing the server.
+ - bugfix: Fixed tenacity effect printing its messages when it shouldn't be, and
+ not removing its' effects when it should've.
+ - bugfix: Fixed scanner gates saying both bypass and detection lines when malfunctioning
+ SyncIt21:
+ - bugfix: Fixed visual glitches when inserting items from an slot other than the
+ hands into evidence bags & other storages that have quick gather mode enabled
+ - bugfix: silo connection on some machines won't time out when changing FPS settings
+ - code_imp: improved attack chain code for silo connection
+ Time-Green:
+ - bugfix: Nooartrium heart damage can no longer be bypassed with non-organic hearts
+ carlarctg:
+ - bugfix: you now snip cuffs with right click to prevent accidental cuts
+ - spellcheck: 'spellecheck: existence not existance'
+ - balance: Significantly buffed the anomalock modules.
+ - balance: Anomalock modules can be used with eachother.
+ - balance: Antigravity module costs 2 complexity.
+ - balance: Teleporter module is thrice as fast at teleporting with a slightly reduced
+ cooldown, but has a much larger power cost.
+ - code_imp: Changed how teleporter tracks maximum range to be less painful to the
+ end user.
+ - refactor: Refactored LoS checks to be a proc on atom, los_check
+ - balance: Kinesis module's default range has been extended to 8.
+ - balance: Kinesis module can drag around people in critical condition or worse.
+ - bugfix: vampires are a human subtype & have stomachs/lungs
+ grungussuss:
+ - sound: sandstone blocks have the correct sound now
+ - qol: added feedback for cutting mulebot wires
+ larentoun:
+ - bugfix: Fixes a runtime when wingless creature flaps their wings
+ mc-oofert:
+ - bugfix: Added dehydrator to birdshot kitchen. Surgery theatre now has a surgery
+ tray and surplus prosthetics. An unwired hallway APC is now wired. 1st SM filter
+ is now set to Nitrogen. Chemistry closet in pharmacy now contains extra chemicals
+ to compensate for not having a chemical storage. Atmos air for distro mixer
+ now mixes correctly
+ timothymtorres:
+ - balance: Lower the telecrystal price of the singularity beacon from 10 to 4 and
+ reduce the timer to 20 minutes before it can be purchased.
+ xPokee:
+ - bugfix: fixed brains turning invisible after being washed
diff --git a/icons/effects/beam.dmi b/icons/effects/beam.dmi
index 85d450e03bdd6..41bdf992bbf41 100644
Binary files a/icons/effects/beam.dmi and b/icons/effects/beam.dmi differ
diff --git a/icons/mob/clothing/head/helmet.dmi b/icons/mob/clothing/head/helmet.dmi
index db48dda1fd61c..05fe660a33a29 100644
Binary files a/icons/mob/clothing/head/helmet.dmi and b/icons/mob/clothing/head/helmet.dmi differ
diff --git a/icons/mob/dust_animation.dmi b/icons/mob/dust_animation.dmi
index 459fc2aa3c4b3..10d8418a14453 100644
Binary files a/icons/mob/dust_animation.dmi and b/icons/mob/dust_animation.dmi differ
diff --git a/icons/obj/clothing/head/helmet.dmi b/icons/obj/clothing/head/helmet.dmi
index 621afe57ddce4..e213773717591 100644
Binary files a/icons/obj/clothing/head/helmet.dmi and b/icons/obj/clothing/head/helmet.dmi differ
diff --git a/icons/obj/devices/new_assemblies.dmi b/icons/obj/devices/new_assemblies.dmi
index 7bf96e5ba92e3..f80f89ce20a09 100644
Binary files a/icons/obj/devices/new_assemblies.dmi and b/icons/obj/devices/new_assemblies.dmi differ
diff --git a/strings/tips.txt b/strings/tips.txt
index 7d5f9f82ccc2e..2e80296af2258 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -55,6 +55,7 @@ As a Heretic, the Path of Cosmos allows you to take rightful ownership of the ve
As a Janitor Cyborg, you are the bane of all slaughter demons and even Bubblegum himself. Cleaning up blood stains will severely gimp them.
As a Janitor, if someone steals your janicart, you can instead use your space cleaner spray, grenades, water sprayer, exact bloody revenge or order another from Cargo.
As a Janitor, mousetraps can be used to create bombs or booby-trap containers.
+As a Janitor, you can command cleanbots by pointing at a tile and saying mop/clean.
As a Medical Cyborg, you can fully perform surgery and even augment people.
As a Medical Doctor, almost every type of wound can be treated at least temporarily with gauze. When in doubt, wrap it up!
As a Medical Doctor, corpses placed inside a freezer or morgue tray will have their organs frozen preventing decay. If you don't have time to revive multiple dead bodies, transfer them to the morgue temporarily!
diff --git a/tgstation.dme b/tgstation.dme
index 8ea0d99629865..73c488c1c5acc 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -244,6 +244,7 @@
#include "code\__DEFINES\time.dm"
#include "code\__DEFINES\tools.dm"
#include "code\__DEFINES\toys.dm"
+#include "code\__DEFINES\tracy.dm"
#include "code\__DEFINES\trader.dm"
#include "code\__DEFINES\transport.dm"
#include "code\__DEFINES\tts.dm"
@@ -3925,6 +3926,7 @@
#include "code\modules\clothing\head\mind_monkey_helmet.dm"
#include "code\modules\clothing\head\moth.dm"
#include "code\modules\clothing\head\papersack.dm"
+#include "code\modules\clothing\head\perceptomatrix.dm"
#include "code\modules\clothing\head\pirate.dm"
#include "code\modules\clothing\head\religious.dm"
#include "code\modules\clothing\head\soft_caps.dm"
diff --git a/tgui/packages/tgui/interfaces/OreContainer.tsx b/tgui/packages/tgui/interfaces/OreContainer.tsx
index 261523c6e9501..daae93a8edf36 100644
--- a/tgui/packages/tgui/interfaces/OreContainer.tsx
+++ b/tgui/packages/tgui/interfaces/OreContainer.tsx
@@ -2,23 +2,27 @@ import { createSearch, toTitleCase } from 'common/string';
import { useState } from 'react';
import { useBackend } from '../backend';
-import { Button, Flex, Image, Input, Section, Stack } from '../components';
+import {
+ Button,
+ DmIcon,
+ Flex,
+ Icon,
+ Input,
+ Section,
+ Stack,
+} from '../components';
import { Window } from '../layouts';
type Ores = {
id: string;
name: string;
amount: number;
-};
-
-type Ore_images = {
- name: string;
icon: string;
+ icon_state: string;
};
type Data = {
ores: Ores[];
- ore_images: Ore_images[];
};
export const OreContainer = (props) => {
@@ -58,7 +62,13 @@ export const OreContainer = (props) => {
-
+ }
+ />
@@ -87,30 +97,6 @@ export const OreContainer = (props) => {
);
};
-const RetrieveIcon = (props) => {
- const { data } = useBackend();
- const { ore_images = [] } = data;
- const { ore } = props;
-
- let icon_display = ore_images.find((icon) => icon.name === ore.name);
-
- if (!icon_display) {
- return null;
- }
-
- return (
-
- );
-};
-
const Orename = (props) => {
const { ore_name } = props;
const return_name = ore_name.split(' ');
diff --git a/tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx b/tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx
index 3bb87d7dce240..b9088f32e0d4a 100644
--- a/tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx
+++ b/tgui/packages/tgui/interfaces/OreRedemptionMachine.jsx
@@ -6,8 +6,8 @@ import {
BlockQuote,
Box,
Button,
+ DmIcon,
Icon,
- Image,
Input,
LabeledList,
Section,
@@ -175,14 +175,7 @@ export const OreRedemptionMachine = (props) => {
};
const MaterialRow = (props) => {
- const { data } = useBackend();
- const { compact } = props;
- const { material_icons } = data;
- const { material, onRelease } = props;
-
- const display = material_icons.find(
- (mat_icon) => mat_icon.id === material.id,
- );
+ const { compact, material, onRelease } = props;
const sheet_amounts = Math.floor(material.amount);
const print_amount = 5;
@@ -192,14 +185,12 @@ const MaterialRow = (props) => {
{!compact && (
- }
/>
)}
diff --git a/tgui/packages/tgui/interfaces/ProduceConsole.tsx b/tgui/packages/tgui/interfaces/ProduceConsole.tsx
index 686b194abea8c..b13fda8af077c 100644
--- a/tgui/packages/tgui/interfaces/ProduceConsole.tsx
+++ b/tgui/packages/tgui/interfaces/ProduceConsole.tsx
@@ -8,8 +8,8 @@ import {
Button,
Dimmer,
Divider,
+ DmIcon,
Icon,
- Image,
Input,
NumberInput,
Section,
@@ -26,7 +26,8 @@ type OrderDatum = {
cat: string;
ref: string;
cost: number;
- product_icon: string;
+ icon: string;
+ icon_state: string;
};
type Item = {
@@ -127,13 +128,13 @@ const ShoppingTab = (props) => {
/>{' '}
{!condensed && (
- }
/>
)}