diff --git a/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm b/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
index fd292ec768512..047d4b4c042b1 100644
--- a/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
+++ b/_maps/RandomRuins/IceRuins/icemoon_surface_smoking_room.dmm
@@ -175,11 +175,11 @@
/area/ruin/smoking_room/room)
"E" = (
/obj/item/trash/shrimp_chips,
-/obj/item/clothing/mask/cigarette/rollie/trippy{
+/obj/item/cigarette/rollie/trippy{
pixel_x = 3;
pixel_y = -1
},
-/obj/item/clothing/mask/cigarette/rollie/trippy{
+/obj/item/cigarette/rollie/trippy{
pixel_x = 3;
pixel_y = 5
},
diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
index 65c448e94c426..a81508dbe1f40 100644
--- a/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
+++ b/_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm
@@ -477,7 +477,7 @@
/obj/structure/closet/cardboard,
/obj/item/toy/plush/snakeplushie,
/obj/item/clothing/glasses/eyepatch,
-/obj/item/clothing/mask/cigarette/cigar/havana,
+/obj/item/cigarette/cigar/havana,
/turf/open/floor/plating/dumpsterair,
/area/ruin/space/has_grav/garbagetruck/foodwaste)
"wR" = (
diff --git a/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm b/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm
index 0f2f425fe6293..03a9b87ff4edf 100644
--- a/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm
+++ b/_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm
@@ -142,7 +142,7 @@
/area/ruin/space/has_grav/garbagetruck/squat)
"ih" = (
/obj/item/bedsheet/purple,
-/obj/item/clothing/mask/cigarette/space_cigarette,
+/obj/item/cigarette/space_cigarette,
/obj/structure/bed/maint,
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/fuel_pool,
@@ -373,7 +373,7 @@
/turf/open/floor/iron/smooth,
/area/ruin/space/has_grav/garbagetruck/squat)
"tu" = (
-/obj/item/clothing/mask/cigarette/robust,
+/obj/item/cigarette/robust,
/obj/structure/closet/emcloset,
/obj/item/clothing/suit/utility/fire/heavy,
/obj/item/clothing/head/utility/hardhat/welding/atmos,
@@ -758,7 +758,7 @@
pixel_x = -4;
pixel_y = 10
},
-/obj/item/clothing/mask/cigarette/space_cigarette{
+/obj/item/cigarette/space_cigarette{
pixel_x = -5;
pixel_y = 7
},
@@ -905,7 +905,7 @@
"Xv" = (
/obj/item/food/deadmouse,
/obj/item/clothing/shoes/sneakers/red,
-/obj/item/clothing/mask/cigarette/carp,
+/obj/item/cigarette/carp,
/obj/item/extinguisher/mini,
/obj/effect/decal/cleanable/fuel_pool,
/turf/open/floor/plating/dumpsterair,
diff --git a/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm b/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm
index 08175777752e6..b31a11cba31ca 100644
--- a/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm
+++ b/_maps/RandomRuins/SpaceRuins/the_faceoff.dmm
@@ -347,7 +347,7 @@
/area/ruin/space)
"mn" = (
/obj/structure/table/reinforced/plastitaniumglass,
-/obj/item/clothing/mask/cigarette/syndicate,
+/obj/item/cigarette/syndicate,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate{
pixel_y = 7
},
@@ -622,7 +622,7 @@
/area/ruin/space)
"yd" = (
/obj/structure/table/reinforced/plastitaniumglass,
-/obj/item/clothing/mask/cigarette/syndicate,
+/obj/item/cigarette/syndicate,
/obj/effect/spawner/random/entertainment/lighter,
/turf/open/floor/mineral/plastitanium/airless,
/area/ruin/space)
@@ -701,7 +701,7 @@
/area/ruin/space)
"Cz" = (
/obj/structure/table/reinforced/plastitaniumglass,
-/obj/item/clothing/mask/cigarette/syndicate,
+/obj/item/cigarette/syndicate,
/obj/effect/spawner/random/entertainment/lighter,
/turf/open/floor/iron/dark/airless,
/area/ruin/space)
diff --git a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm
index b2b8fd17fbed6..327b0f558ca37 100644
--- a/_maps/RandomRuins/SpaceRuins/the_outlet.dmm
+++ b/_maps/RandomRuins/SpaceRuins/the_outlet.dmm
@@ -564,7 +564,7 @@
/obj/item/clothing/shoes/cowboy,
/obj/item/clothing/under/costume/dutch,
/obj/item/clothing/suit/costume/poncho,
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/obj/structure/window/reinforced/spawner/directional/south,
/obj/structure/window/reinforced/spawner/directional/east,
/obj/structure/window/reinforced/spawner/directional/west,
diff --git a/_maps/RandomZLevels/TheBeach.dmm b/_maps/RandomZLevels/TheBeach.dmm
index 3f18eb1d627d3..c18eba4fbc266 100644
--- a/_maps/RandomZLevels/TheBeach.dmm
+++ b/_maps/RandomZLevels/TheBeach.dmm
@@ -346,7 +346,7 @@
/area/awaymission/beach)
"eT" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_y = 16;
pixel_x = -2
},
diff --git a/_maps/RandomZLevels/moonoutpost19.dmm b/_maps/RandomZLevels/moonoutpost19.dmm
index 479242b1fa40c..9473a5e3ba09a 100644
--- a/_maps/RandomZLevels/moonoutpost19.dmm
+++ b/_maps/RandomZLevels/moonoutpost19.dmm
@@ -6029,7 +6029,7 @@
/obj/structure/table/wood,
/obj/item/lighter,
/obj/machinery/newscaster/directional/east,
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/turf/open/floor/carpet/orange,
/area/awaymission/moonoutpost19/arrivals)
"Ov" = (
diff --git a/_maps/RandomZLevels/museum.dmm b/_maps/RandomZLevels/museum.dmm
index cdea9ba141a13..2937250b1f9ba 100644
--- a/_maps/RandomZLevels/museum.dmm
+++ b/_maps/RandomZLevels/museum.dmm
@@ -4755,7 +4755,7 @@
/obj/structure/lattice/catwalk/mining,
/obj/structure/railing,
/obj/structure/table,
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
icon_state = "cigaron";
lit = 1
},
diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm
index 54cd4e0f04646..2708d4719af1b 100644
--- a/_maps/map_files/Birdshot/birdshot.dmm
+++ b/_maps/map_files/Birdshot/birdshot.dmm
@@ -256,7 +256,7 @@
/area/station/medical/virology)
"agp" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar/cohiba,
+/obj/item/cigarette/cigar/cohiba,
/turf/open/floor/carpet,
/area/station/commons/dorms)
"agy" = (
@@ -592,9 +592,7 @@
dir = 6
},
/obj/structure/cable,
-/obj/effect/turf_decal/weather/snow/corner{
- dir = 2
- },
+/obj/effect/turf_decal/weather/snow/corner,
/turf/open/floor/iron/freezer,
/area/station/service/kitchen/coldroom)
"anJ" = (
@@ -3804,7 +3802,7 @@
/obj/structure/rack,
/obj/item/weldingtool/mini,
/obj/item/tank/internals/emergency_oxygen/empty,
-/obj/item/clothing/mask/cigarette/rollie,
+/obj/item/cigarette/rollie,
/turf/open/floor/iron/dark/smooth_large,
/area/station/maintenance/central/lesser)
"bxl" = (
@@ -4027,7 +4025,7 @@
/obj/item/stock_parts/power_store/cell/crap{
pixel_y = 5
},
-/obj/item/clothing/mask/cigarette/pipe/cobpipe{
+/obj/item/cigarette/pipe/cobpipe{
pixel_x = 1;
pixel_y = -2
},
@@ -5449,7 +5447,7 @@
pixel_y = 9;
pixel_x = 14
},
-/obj/item/clothing/mask/cigarette{
+/obj/item/cigarette{
pixel_y = 2
},
/turf/open/floor/iron/small,
@@ -10568,7 +10566,7 @@
pixel_x = -6;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette{
+/obj/item/cigarette{
pixel_x = 5;
pixel_y = 2
},
@@ -10781,6 +10779,10 @@
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible,
/obj/machinery/camera/autoname/directional/east,
/obj/machinery/light/cold/directional/east,
+/obj/machinery/power/apc/auto_name/directional/east{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"ebE" = (
@@ -18583,7 +18585,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/structure/table,
/obj/item/stack/spacecash/c1,
-/obj/item/clothing/mask/cigarette/cigar/havana,
+/obj/item/cigarette/cigar/havana,
/turf/open/floor/light/colour_cycle/dancefloor_b,
/area/station/maintenance/starboard/central)
"gJS" = (
@@ -21650,9 +21652,7 @@
"hHn" = (
/obj/effect/turf_decal/weather/snow,
/obj/structure/closet/secure_closet/freezer/fridge,
-/obj/effect/turf_decal/weather/snow/corner{
- dir = 2
- },
+/obj/effect/turf_decal/weather/snow/corner,
/obj/item/food/meat/bacon,
/obj/item/food/meat/bacon,
/obj/item/food/meat/slab/monkey,
@@ -28888,7 +28888,7 @@
/turf/open/floor/iron,
/area/station/security/prison/rec)
"jUr" = (
-/obj/item/clothing/mask/cigarette,
+/obj/item/cigarette,
/obj/item/storage/fancy/cigarettes/cigpack_robust{
pixel_y = 5;
pixel_x = 6
@@ -32622,7 +32622,7 @@
pixel_x = 5;
pixel_y = 9
},
-/obj/item/clothing/mask/cigarette/candy{
+/obj/item/cigarette/candy{
pixel_x = -3;
pixel_y = 10
},
@@ -35129,11 +35129,11 @@
/area/station/engineering/atmos)
"lNF" = (
/obj/effect/spawner/random/entertainment/lighter,
-/obj/item/clothing/mask/cigarette/rollie/mindbreaker{
+/obj/item/cigarette/rollie/mindbreaker{
pixel_x = -2;
pixel_y = 6
},
-/obj/item/clothing/mask/cigarette/rollie/trippy{
+/obj/item/cigarette/rollie/trippy{
pixel_x = 4
},
/obj/effect/mapping_helpers/burnt_floor,
@@ -35657,7 +35657,7 @@
pixel_x = 5;
pixel_y = -5
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_y = 4
},
/turf/open/floor/iron/dark/small,
@@ -35833,7 +35833,7 @@
pixel_x = -3;
pixel_y = 10
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = -1;
pixel_y = -2
},
@@ -37813,7 +37813,7 @@
pixel_y = 2
},
/obj/item/wrench,
-/obj/item/clothing/mask/cigarette/xeno{
+/obj/item/cigarette/xeno{
pixel_x = -3;
pixel_y = -9
},
@@ -40204,9 +40204,7 @@
},
/obj/effect/turf_decal/weather/snow,
/obj/structure/closet/secure_closet/freezer/meat,
-/obj/effect/turf_decal/weather/snow/corner{
- dir = 2
- },
+/obj/effect/turf_decal/weather/snow/corner,
/obj/item/food/meat/slab/monkey,
/obj/item/food/meat/slab/monkey,
/obj/item/food/meat/slab/monkey,
@@ -45658,7 +45656,7 @@
/area/station/command/corporate_suite)
"pot" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar/premium{
+/obj/item/cigarette/cigar/premium{
pixel_y = 5
},
/turf/open/floor/stone,
@@ -46919,6 +46917,7 @@
/area/station/commons/fitness/recreation)
"pHS" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"pHY" = (
@@ -51419,7 +51418,7 @@
pixel_y = -3;
pixel_x = -2
},
-/obj/item/clothing/mask/cigarette{
+/obj/item/cigarette{
pixel_x = 6;
pixel_y = 4
},
@@ -51686,7 +51685,7 @@
dir = 10
},
/obj/structure/table,
-/obj/item/clothing/mask/cigarette,
+/obj/item/cigarette,
/obj/item/toy/toy_dagger,
/obj/item/clothing/head/collectable/paper,
/obj/item/toy/figure/roboticist{
@@ -59590,7 +59589,7 @@
pixel_x = -2;
pixel_y = -3
},
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/obj/effect/mapping_helpers/broken_floor,
/obj/machinery/light_switch/directional/south,
/turf/open/floor/iron/smooth,
@@ -63821,9 +63820,7 @@
/obj/structure/disposalpipe/segment{
dir = 9
},
-/obj/effect/turf_decal/weather/snow/corner{
- dir = 2
- },
+/obj/effect/turf_decal/weather/snow/corner,
/turf/open/floor/iron/freezer,
/area/station/service/kitchen/coldroom)
"uZA" = (
@@ -73246,6 +73243,10 @@
/obj/effect/spawner/random/trash,
/turf/open/floor/plating,
/area/station/maintenance/department/science/xenobiology)
+"xHb" = (
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance)
"xHc" = (
/obj/effect/turf_decal/siding/wood{
dir = 6
@@ -125322,9 +125323,9 @@ oZz
xZJ
aVT
enG
-enG
-enG
-enG
+xHb
+xHb
+xHb
pHS
xpR
kQt
diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm
index 898ee622a1b52..ea6076af43a99 100644
--- a/_maps/map_files/Deltastation/DeltaStation2.dmm
+++ b/_maps/map_files/Deltastation/DeltaStation2.dmm
@@ -2712,15 +2712,15 @@
pixel_x = -2;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 2;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 3;
pixel_y = 1
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4
},
/obj/effect/turf_decal/tile/blue/half/contrasted{
@@ -6189,15 +6189,15 @@
"bAS" = (
/obj/structure/table/wood,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = -2;
pixel_y = 2
},
@@ -6674,6 +6674,17 @@
/obj/effect/decal/cleanable/dirt/dust,
/turf/open/floor/iron/herringbone,
/area/station/cargo/miningoffice)
+"bFD" = (
+/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible,
+/obj/effect/turf_decal/stripes/line{
+ dir = 8
+ },
+/obj/effect/turf_decal/tile/neutral/half/contrasted{
+ dir = 8
+ },
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance)
"bFS" = (
/obj/effect/turf_decal/trimline/blue/filled/warning,
/obj/structure/cable,
@@ -13910,7 +13921,7 @@
/area/station/commons/vacant_room/office)
"dtk" = (
/obj/structure/table/wood/poker,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/turf/open/floor/carpet/green,
/area/station/commons/lounge)
"dtn" = (
@@ -14666,6 +14677,10 @@
},
/turf/open/floor/iron/dark,
/area/station/science/xenobiology)
+"dDB" = (
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance)
"dDT" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/components/trinary/filter{
@@ -20741,7 +20756,9 @@
/turf/open/floor/iron/white,
/area/station/science/research)
"fff" = (
-/obj/machinery/power/apc/auto_name/directional/north,
+/obj/machinery/power/apc/auto_name/directional/north{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
/obj/structure/cable,
/obj/effect/turf_decal/tile/neutral/fourcorners,
/obj/machinery/atmospherics/pipe/layer_manifold/supply/visible{
@@ -27875,6 +27892,7 @@
dir = 6
},
/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"gQH" = (
@@ -33613,6 +33631,7 @@
/obj/effect/turf_decal/bot,
/obj/effect/turf_decal/tile/neutral/full,
/obj/machinery/holopad,
+/obj/structure/cable,
/turf/open/floor/iron/dark/smooth_large,
/area/station/science/ordnance)
"iqj" = (
@@ -34758,6 +34777,11 @@
/obj/effect/turf_decal/tile/neutral,
/turf/open/floor/iron,
/area/station/hallway/secondary/exit)
+"iFt" = (
+/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance)
"iFD" = (
/obj/effect/decal/cleanable/dirt,
/obj/structure/table/wood,
@@ -44521,6 +44545,8 @@
"lcP" = (
/obj/machinery/atmospherics/pipe/smart/simple/purple/visible/layer2,
/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/machinery/power/apc/auto_name/directional/east,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"lcT" = (
@@ -47595,6 +47621,7 @@
/obj/machinery/meter/layer2,
/obj/structure/sign/warning/no_smoking/directional/east,
/obj/effect/turf_decal/tile/neutral/fourcorners,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"lOA" = (
@@ -52036,13 +52063,13 @@
"mXr" = (
/obj/structure/cable,
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 3
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = -3
},
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/turf/open/floor/iron/grimy,
/area/station/command/heads_quarters/captain)
"mXy" = (
@@ -54527,13 +54554,13 @@
/area/station/commons/vacant_room/commissary)
"nHc" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 3
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = -3
},
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/turf/open/floor/wood,
/area/station/command/meeting_room/council)
"nHd" = (
@@ -62020,6 +62047,16 @@
/obj/effect/turf_decal/tile/neutral/fourcorners,
/turf/open/floor/iron/dark,
/area/station/ai_monitored/security/armory)
+"pDx" = (
+/obj/effect/turf_decal/siding/purple{
+ dir = 4
+ },
+/obj/effect/turf_decal/tile/neutral/half/contrasted{
+ dir = 4
+ },
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance)
"pDz" = (
/obj/machinery/quantum_server,
/obj/effect/turf_decal/bot/left,
@@ -73798,13 +73835,13 @@
pixel_x = -3;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4.5
},
/obj/structure/table/reinforced,
@@ -77225,14 +77262,14 @@
/obj/item/restraints/handcuffs{
pixel_y = 6
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 7;
pixel_y = -7
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = -3
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = -1;
pixel_y = -7
},
@@ -129272,7 +129309,7 @@ nJK
yex
iML
tgI
-uUG
+iFt
djT
kzc
kzc
@@ -129786,7 +129823,7 @@ hGI
esH
owX
asW
-nSb
+bFD
nSb
jHm
ucu
@@ -130043,7 +130080,7 @@ hNW
hNW
hNW
hNW
-hNW
+dDB
hNW
nLP
hNW
@@ -130300,7 +130337,7 @@ lzo
vbO
uXN
eqB
-eyH
+pDx
eyH
pwD
eyH
diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
index 5cb80509dd13d..5d70bb72e8081 100644
--- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm
+++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm
@@ -1932,7 +1932,7 @@
dir = 4
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"aEM" = (
/obj/structure/sign/departments/cargo,
/turf/closed/wall/r_wall,
@@ -2621,6 +2621,7 @@
/obj/effect/turf_decal/box,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/science/ordnance)
"aQy" = (
@@ -4482,7 +4483,7 @@
"bqX" = (
/obj/machinery/air_sensor/ordnance_burn_chamber,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"bqY" = (
/obj/structure/closet,
/obj/effect/spawner/random/maintenance/two,
@@ -5770,6 +5771,10 @@
},
/obj/machinery/door/firedoor/heavy,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/power/apc/auto_name/directional/north{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"bIl" = (
@@ -8439,7 +8444,7 @@
"cuB" = (
/obj/machinery/atmospherics/components/unary/outlet_injector/monitored/ordnance_burn_chamber_input,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"cuJ" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 4
@@ -15203,7 +15208,7 @@
"evc" = (
/obj/machinery/atmospherics/components/unary/vent_scrubber/on,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"evk" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -17097,10 +17102,8 @@
/turf/open/floor/iron,
/area/station/engineering/main)
"fcj" = (
-/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
-/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
-/turf/open/floor/iron,
-/area/station/science/ordnance)
+/turf/closed/wall/r_wall,
+/area/station/science/ordnance/burnchamber)
"fco" = (
/obj/effect/turf_decal/tile/bar/opposingcorners,
/obj/effect/turf_decal/siding/wood{
@@ -18698,7 +18701,7 @@
"fCS" = (
/obj/machinery/door/poddoor/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"fCW" = (
/obj/structure/extinguisher_cabinet/directional/east,
/turf/open/floor/iron/dark/textured,
@@ -20334,6 +20337,7 @@
/obj/machinery/door/firedoor/heavy,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"gcB" = (
@@ -28129,7 +28133,7 @@
/area/station/maintenance/port/fore)
"iwq" = (
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"iwx" = (
/obj/machinery/door/airlock/maintenance{
name = "Xenobiology Maintenance"
@@ -28511,7 +28515,7 @@
"iCe" = (
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"iCg" = (
/obj/effect/turf_decal/stripes/corner{
dir = 1
@@ -37270,7 +37274,7 @@
dir = 8
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"lgW" = (
/obj/machinery/meter/monitored/distro_loop,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/visible,
@@ -41966,7 +41970,7 @@
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/effect/decal/cleanable/dirt,
/obj/structure/table,
-/obj/item/clothing/mask/cigarette{
+/obj/item/cigarette{
pixel_x = 6;
pixel_y = 12
},
@@ -46876,7 +46880,7 @@
"ocd" = (
/obj/machinery/igniter/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"ocp" = (
/obj/effect/landmark/start/hangover,
/obj/effect/decal/cleanable/dirt,
@@ -56692,7 +56696,7 @@
"qTp" = (
/obj/structure/table/wood,
/obj/item/clothing/mask/fakemoustache,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/obj/item/clothing/glasses/monocle,
/obj/item/radio/intercom/directional/north,
/turf/open/floor/iron/grimy,
@@ -57966,7 +57970,7 @@
/obj/effect/mapping_helpers/airlock/locked,
/obj/effect/mapping_helpers/airlock/access/all/science/ordnance,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"rmM" = (
/obj/machinery/disposal/bin,
/obj/structure/disposalpipe/trunk{
@@ -58122,7 +58126,7 @@
"roW" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"roX" = (
/obj/effect/spawner/structure/window/reinforced,
/obj/structure/cable,
@@ -58745,7 +58749,7 @@
dir = 8
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"rzj" = (
/obj/structure/table,
/obj/item/stack/sheet/iron/fifty{
@@ -59212,6 +59216,7 @@
"rEj" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/science/ordnance)
"rEn" = (
@@ -61591,7 +61596,7 @@
},
/obj/effect/mapping_helpers/airlock/access/all/science/ordnance,
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"sqN" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -72266,7 +72271,7 @@
/area/station/cargo/drone_bay)
"vFb" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 7;
pixel_y = 10
},
@@ -75803,7 +75808,7 @@
"wKh" = (
/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"wKv" = (
/obj/structure/table,
/obj/item/radio/off,
@@ -78957,6 +78962,7 @@
/obj/machinery/atmospherics/pipe/smart/simple/yellow/visible,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
/turf/open/floor/iron,
/area/station/science/ordnance)
"xEW" = (
@@ -194431,7 +194437,7 @@ opD
mxc
hFb
hFb
-fcj
+qRO
mEL
vqv
fkN
@@ -194945,7 +194951,7 @@ opD
jGR
hFb
hFb
-fcj
+qRO
rRl
vfI
vUY
@@ -195200,9 +195206,9 @@ odm
odm
nqy
jGR
-fcj
-fcj
-fcj
+qRO
+qRO
+qRO
rRl
ndb
bnZ
@@ -195450,10 +195456,10 @@ thA
thA
rcY
iDt
-uIf
-uIf
-uIf
-uIf
+fcj
+fcj
+fcj
+fcj
roW
roW
bId
diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm
index 79f3cc97bae62..1713d3784311d 100644
--- a/_maps/map_files/MetaStation/MetaStation.dmm
+++ b/_maps/map_files/MetaStation/MetaStation.dmm
@@ -1747,7 +1747,10 @@
/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{
dir = 1
},
-/obj/machinery/firealarm/directional/east,
+/obj/machinery/power/apc/auto_name/directional/east{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"aHM" = (
@@ -3789,7 +3792,7 @@
/obj/item/clothing/mask/animal/horsehead,
/obj/structure/table/wood,
/obj/machinery/airalarm/directional/south,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/obj/item/clothing/mask/fakemoustache,
/obj/structure/sign/poster/contraband/random/directional/west,
/turf/open/floor/wood,
@@ -3812,7 +3815,7 @@
/area/station/engineering/atmospherics_engine)
"bqC" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/turf/open/floor/wood,
/area/station/commons/lounge)
"bqJ" = (
@@ -4577,7 +4580,7 @@
/obj/effect/mapping_helpers/airlock/locked,
/obj/effect/mapping_helpers/airlock/access/all/science/ordnance,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"bEA" = (
/obj/structure/cable,
/obj/machinery/camera/directional/south{
@@ -6041,7 +6044,7 @@
"cgP" = (
/obj/machinery/air_sensor/ordnance_burn_chamber,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"cgZ" = (
/obj/machinery/light_switch/directional/east,
/obj/structure/cable,
@@ -7224,7 +7227,7 @@
pixel_x = 6;
pixel_y = -4
},
-/obj/item/clothing/mask/cigarette/rollie/cannabis{
+/obj/item/cigarette/rollie/cannabis{
pixel_y = -3
},
/turf/open/space/basic,
@@ -7796,7 +7799,7 @@
dir = 1
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"cOX" = (
/obj/structure/sign/warning/radiation/rad_area/directional/north,
/obj/effect/turf_decal/stripes/line{
@@ -9912,7 +9915,7 @@
dir = 4
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"dEH" = (
/obj/effect/landmark/generic_maintenance_landmark,
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
@@ -10831,7 +10834,7 @@
"dTN" = (
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"dTQ" = (
/obj/effect/turf_decal/trimline/green/filled/corner{
dir = 4
@@ -11092,7 +11095,7 @@
/area/station/security/execution/education)
"dXU" = (
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"dYa" = (
/obj/effect/turf_decal/tile/blue/fourcorners,
/turf/open/floor/iron,
@@ -13699,7 +13702,7 @@
"eRn" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"eRR" = (
/obj/structure/table,
/obj/item/screwdriver{
@@ -13788,11 +13791,11 @@
pixel_x = -7;
pixel_y = 8
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 8
},
/obj/effect/turf_decal/siding/wood{
@@ -17237,7 +17240,7 @@
dir = 4
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"giA" = (
/turf/closed/wall/r_wall,
/area/station/tcommsat/computer)
@@ -26659,6 +26662,8 @@
dir = 4
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/machinery/firealarm/directional/east,
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"jvr" = (
@@ -28924,7 +28929,7 @@
"kgC" = (
/obj/machinery/door/poddoor/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"kgV" = (
/obj/effect/turf_decal/stripes/line{
dir = 1
@@ -37480,7 +37485,7 @@
pixel_x = -4;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/obj/item/reagent_containers/cup/glass/flask/gold,
/turf/open/floor/carpet,
/area/station/command/heads_quarters/captain/private)
@@ -38841,7 +38846,7 @@
},
/obj/effect/mapping_helpers/airlock/access/all/science/ordnance,
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"nJG" = (
/obj/effect/turf_decal/stripes/line{
dir = 8
@@ -39678,7 +39683,7 @@
dir = 8
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"oac" = (
/obj/structure/cable,
/turf/open/floor/iron,
@@ -39985,7 +39990,7 @@
dir = 1
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"oew" = (
/turf/open/floor/iron,
/area/station/commons/fitness/recreation)
@@ -49218,7 +49223,7 @@
"rtj" = (
/obj/machinery/igniter/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"rtz" = (
/obj/effect/turf_decal/siding/wood/corner,
/obj/effect/turf_decal/siding/wood{
@@ -50554,7 +50559,7 @@
/obj/machinery/light/small/directional/north,
/obj/structure/table/reinforced,
/obj/machinery/requests_console/directional/north{
- department = "Quartermaster's Desk";
+ department = "Security";
name = "Security Requests Console"
},
/obj/effect/mapping_helpers/requests_console/assistance,
@@ -50958,6 +50963,9 @@
},
/turf/open/floor/iron,
/area/station/security/prison/visit)
+"rXT" = (
+/turf/closed/wall/r_wall,
+/area/station/science/ordnance/burnchamber)
"rXW" = (
/obj/item/radio/intercom/directional/west,
/obj/structure/table/glass,
@@ -56553,7 +56561,7 @@
/obj/machinery/firealarm/directional/south,
/obj/structure/rack,
/obj/item/storage/briefcase/secure,
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/obj/effect/turf_decal/tile/blue/half/contrasted{
dir = 1
},
@@ -61134,7 +61142,7 @@
/area/station/hallway/secondary/entry)
"vwi" = (
/obj/structure/table,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/turf/open/floor/plating,
/area/station/maintenance/port)
"vwn" = (
@@ -63769,15 +63777,15 @@
pixel_x = -2;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4;
pixel_y = 1
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = -4;
pixel_y = 1
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba,
+/obj/item/cigarette/cigar/cohiba,
/obj/structure/table/wood,
/turf/open/floor/carpet,
/area/station/command/corporate_showroom)
@@ -68458,7 +68466,7 @@
"xYZ" = (
/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"xZb" = (
/obj/effect/spawner/random/structure/grille,
/turf/open/floor/plating,
@@ -100451,12 +100459,12 @@ fhi
fhi
uEo
fiS
-gyQ
+rXT
eRn
-gyQ
-gyQ
-gyQ
-gyQ
+rXT
+rXT
+rXT
+rXT
lMJ
uGg
nFa
diff --git a/_maps/map_files/Mining/Lavaland.dmm b/_maps/map_files/Mining/Lavaland.dmm
index b38b99867ab47..5bc3a711a1b03 100644
--- a/_maps/map_files/Mining/Lavaland.dmm
+++ b/_maps/map_files/Mining/Lavaland.dmm
@@ -7308,7 +7308,7 @@
},
/area/mine/laborcamp)
"Sc" = (
-/obj/item/clothing/mask/cigarette/robust{
+/obj/item/cigarette/robust{
pixel_x = 3;
pixel_y = -10
},
@@ -7608,7 +7608,7 @@
/turf/open/floor/plating,
/area/mine/laborcamp/security/maintenance)
"TX" = (
-/obj/item/clothing/mask/cigarette/robust{
+/obj/item/cigarette/robust{
pixel_x = 8;
pixel_y = 8
},
diff --git a/_maps/map_files/NorthStar/north_star.dmm b/_maps/map_files/NorthStar/north_star.dmm
index 6772e09a7ae87..3e9ca40048097 100644
--- a/_maps/map_files/NorthStar/north_star.dmm
+++ b/_maps/map_files/NorthStar/north_star.dmm
@@ -72,6 +72,13 @@
/obj/machinery/duct,
/turf/open/floor/iron,
/area/station/commons/toilet)
+"aaN" = (
+/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
+ dir = 8
+ },
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"aaO" = (
/obj/machinery/computer/atmos_alert{
dir = 4
@@ -284,7 +291,7 @@
/area/station/maintenance/floor3/starboard/fore)
"acL" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar/cohiba,
+/obj/item/cigarette/cigar/cohiba,
/obj/effect/turf_decal/trimline/blue/line{
dir = 1
},
@@ -6879,6 +6886,7 @@
/obj/machinery/atmospherics/pipe/smart/simple/scrubbers/visible/layer4{
dir = 8
},
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance/testlab)
"bJQ" = (
@@ -14447,6 +14455,7 @@
/area/station/maintenance/floor1/starboard/fore)
"dIJ" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
+/obj/structure/cable,
/turf/open/floor/iron/white,
/area/station/science/ordnance/testlab)
"dIO" = (
@@ -24699,6 +24708,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{
dir = 1
},
+/obj/structure/cable,
/turf/open/floor/iron/white,
/area/station/science/ordnance/testlab)
"gwl" = (
@@ -35289,6 +35299,7 @@
/obj/effect/turf_decal/stripes{
dir = 1
},
+/obj/structure/cable,
/turf/open/floor/iron/white,
/area/station/science/ordnance/testlab)
"jjo" = (
@@ -52999,7 +53010,7 @@
/obj/item/fishing_rod,
/obj/structure/closet,
/obj/effect/spawner/random/maintenance/three,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/turf/open/floor/pod/light,
/area/station/maintenance/floor2/starboard/fore)
"nEO" = (
@@ -59547,6 +59558,10 @@
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible{
dir = 4
},
+/obj/machinery/power/apc/auto_name/directional/north{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance/testlab)
"pqO" = (
@@ -60773,6 +60788,10 @@
dir = 8
},
/area/station/security/office)
+"pGz" = (
+/obj/structure/cable,
+/turf/open/floor/iron/dark,
+/area/station/science/ordnance/testlab)
"pGG" = (
/obj/structure/ladder,
/obj/structure/lattice/catwalk,
@@ -91253,6 +91272,7 @@
/area/station/commons/vacant_room/office)
"xxA" = (
/obj/machinery/holopad,
+/obj/structure/cable,
/turf/open/floor/iron/white,
/area/station/science/ordnance/testlab)
"xxC" = (
@@ -92288,7 +92308,7 @@
/area/station/maintenance/floor3/port)
"xJX" = (
/obj/structure/table,
-/obj/item/clothing/mask/cigarette/candy{
+/obj/item/cigarette/candy{
pixel_x = 4
},
/turf/open/floor/iron/dark/smooth_large,
@@ -315655,8 +315675,8 @@ dWz
lYx
unQ
wMU
-oUW
-rDL
+aaN
+pGz
jjj
dIJ
oTq
diff --git a/_maps/map_files/generic/CentCom.dmm b/_maps/map_files/generic/CentCom.dmm
index 30a6759d52eda..9b5baa411fa10 100644
--- a/_maps/map_files/generic/CentCom.dmm
+++ b/_maps/map_files/generic/CentCom.dmm
@@ -8578,13 +8578,13 @@
pixel_x = -3;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4.5
},
/obj/machinery/status_display/evac/directional/north,
@@ -8765,13 +8765,13 @@
pixel_x = -3;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4.5
},
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{
@@ -8996,13 +8996,13 @@
pixel_x = -3;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4.5
},
/obj/machinery/airalarm/directional/south,
@@ -9475,7 +9475,7 @@
pixel_y = 19;
pixel_x = 7
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = -6;
pixel_y = 5
},
@@ -10242,13 +10242,13 @@
pixel_x = -3;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba{
+/obj/item/cigarette/cigar/cohiba{
pixel_x = 6
},
-/obj/item/clothing/mask/cigarette/cigar/havana{
+/obj/item/cigarette/cigar/havana{
pixel_x = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4.5
},
/obj/machinery/newscaster/directional/north,
diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm
index 575b405d6afe3..c7686749c5031 100644
--- a/_maps/map_files/tramstation/tramstation.dmm
+++ b/_maps/map_files/tramstation/tramstation.dmm
@@ -1962,7 +1962,7 @@
/area/station/commons/vacant_room)
"agG" = (
/obj/structure/dresser,
-/obj/item/clothing/mask/cigarette/cigar/havana,
+/obj/item/cigarette/cigar/havana,
/turf/open/floor/iron/grimy,
/area/station/commons/vacant_room)
"agH" = (
@@ -10735,15 +10735,15 @@
pixel_x = -2;
pixel_y = 3
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = -4;
pixel_y = 1
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4;
pixel_y = 1
},
-/obj/item/clothing/mask/cigarette/cigar/cohiba,
+/obj/item/cigarette/cigar/cohiba,
/turf/open/floor/wood,
/area/station/command/meeting_room)
"cFP" = (
diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm
index 2d384218d87b7..8f3fb14e377c7 100644
--- a/_maps/map_files/wawastation/wawastation.dmm
+++ b/_maps/map_files/wawastation/wawastation.dmm
@@ -1359,7 +1359,7 @@
"awf" = (
/obj/machinery/igniter/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"awi" = (
/obj/effect/decal/cleanable/dirt/dust,
/obj/structure/cable,
@@ -6183,9 +6183,7 @@
/turf/open/floor/iron/dark,
/area/station/engineering/supermatter/room)
"ckb" = (
-/obj/effect/turf_decal/siding/dark_blue{
- dir = 2
- },
+/obj/effect/turf_decal/siding/dark_blue,
/obj/machinery/holopad,
/turf/open/floor/iron/textured_large,
/area/station/command/bridge)
@@ -6963,7 +6961,7 @@
network = list("ss13","rd")
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"cAQ" = (
/obj/vehicle/sealed/mecha/ripley/cargo,
/obj/effect/decal/cleanable/dirt,
@@ -7777,7 +7775,7 @@
dir = 8
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"cQK" = (
/obj/effect/turf_decal/trimline/blue/filled/line{
dir = 4
@@ -9421,7 +9419,6 @@
dir = 4
},
/obj/structure/chair{
- dir = 2;
name = "Defense"
},
/obj/structure/cable,
@@ -9740,7 +9737,7 @@
dir = 8
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"dyV" = (
/obj/structure/railing{
dir = 1
@@ -11522,9 +11519,7 @@
/turf/open/floor/iron/white,
/area/station/medical/treatment_center)
"ebE" = (
-/obj/effect/spawner/structure/window/hollow/end{
- dir = 2
- },
+/obj/effect/spawner/structure/window/hollow/end,
/turf/open/floor/plating,
/area/station/security/courtroom)
"ebN" = (
@@ -11607,6 +11602,7 @@
pixel_x = 3;
pixel_y = -2
},
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"edv" = (
@@ -11703,7 +11699,7 @@
"efL" = (
/obj/effect/spawner/structure/window/reinforced/plasma,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"efQ" = (
/obj/structure/cable,
/obj/effect/decal/cleanable/dirt,
@@ -11751,7 +11747,7 @@
dir = 8
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"egY" = (
/obj/machinery/light_switch/directional/west,
/turf/open/openspace,
@@ -13408,6 +13404,10 @@
pixel_y = 7
},
/obj/item/pipe_dispenser,
+/obj/machinery/power/apc/auto_name/directional/south{
+ areastring = "/area/station/science/ordnance/burnchamber"
+ },
+/obj/structure/cable,
/turf/open/floor/iron/dark,
/area/station/science/ordnance)
"eLe" = (
@@ -19388,7 +19388,7 @@
dir = 8
},
/obj/effect/spawner/random/entertainment/cigarette_pack,
-/obj/item/clothing/mask/cigarette/rollie/mindbreaker,
+/obj/item/cigarette/rollie/mindbreaker,
/obj/machinery/airalarm/directional/east,
/turf/open/floor/iron,
/area/station/cargo/miningoffice)
@@ -25359,9 +25359,7 @@
/area/station/medical/medbay/central)
"jbL" = (
/obj/machinery/door/firedoor,
-/obj/effect/turf_decal/tile/purple/anticorner/contrasted{
- dir = 2
- },
+/obj/effect/turf_decal/tile/purple/anticorner/contrasted,
/turf/open/floor/iron/white,
/area/station/science/lobby)
"jbM" = (
@@ -27400,7 +27398,6 @@
/area/station/maintenance/central/greater)
"jIY" = (
/obj/structure/chair{
- dir = 2;
name = "Defense"
},
/obj/machinery/power/apc/auto_name/directional/north,
@@ -31681,7 +31678,7 @@
dir = 8
},
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"lfu" = (
/obj/effect/turf_decal/tile/dark_red/opposingcorners,
/obj/effect/landmark/start/bartender,
@@ -32865,9 +32862,7 @@
/turf/open/floor/iron/white,
/area/station/medical/chemistry/minisat)
"lCK" = (
-/obj/effect/turf_decal/siding/dark_blue{
- dir = 2
- },
+/obj/effect/turf_decal/siding/dark_blue,
/turf/open/floor/iron/textured_large,
/area/station/command/bridge)
"lCO" = (
@@ -34548,7 +34543,7 @@
dir = 8
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"miR" = (
/obj/structure/cable,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
@@ -35734,7 +35729,7 @@
"mDx" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"mDF" = (
/obj/effect/turf_decal/trimline/blue/filled/line{
dir = 4
@@ -37036,7 +37031,7 @@
/area/station/medical/medbay/central)
"nbS" = (
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"ncc" = (
/obj/structure/flora/bush/flowers_br/style_random,
/obj/structure/window/spawner/directional/north,
@@ -37620,6 +37615,9 @@
dir = 1
},
/area/station/engineering/atmos)
+"nkM" = (
+/turf/closed/wall/r_wall,
+/area/station/science/ordnance/burnchamber)
"nli" = (
/obj/machinery/atmospherics/pipe/smart/simple/dark/visible,
/obj/machinery/airalarm/directional/east,
@@ -45215,7 +45213,7 @@
dir = 4
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"pZP" = (
/obj/machinery/atmospherics/pipe/multiz/supply/hidden/layer4,
/obj/machinery/atmospherics/pipe/multiz/scrubbers/visible/layer2,
@@ -53262,7 +53260,7 @@
pixel_y = -24
},
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"sLt" = (
/obj/machinery/camera/autoname/directional/east,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
@@ -57761,9 +57759,7 @@
/turf/open/floor/plating,
/area/station/maintenance/department/medical/central)
"uoP" = (
-/obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/co2{
- dir = 2
- },
+/obj/machinery/atmospherics/components/trinary/filter/atmos/flipped/co2,
/obj/effect/turf_decal/tile/blue/fourcorners,
/turf/open/floor/catwalk_floor/flat_white,
/area/station/medical/treatment_center)
@@ -60219,7 +60215,7 @@
dir = 4
},
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"viK" = (
/obj/effect/turf_decal/tile/dark_blue/half/contrasted{
dir = 8
@@ -60977,7 +60973,7 @@
dir = 4
},
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"vyj" = (
/obj/structure/stairs/east,
/obj/structure/railing,
@@ -61767,7 +61763,7 @@
"vMR" = (
/obj/machinery/door/poddoor/incinerator_ordmix,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"vNc" = (
/obj/machinery/modular_computer/preset/id{
dir = 1
@@ -62880,7 +62876,7 @@
"wgI" = (
/obj/machinery/air_sensor/ordnance_burn_chamber,
/turf/open/floor/engine/vacuum,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"wgK" = (
/obj/effect/turf_decal/box/corners{
dir = 8
@@ -65707,7 +65703,7 @@
"xfQ" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/closed/wall/r_wall,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"xfS" = (
/obj/structure/sign/departments/aisat/directional/east,
/obj/effect/turf_decal/tile/dark_blue/anticorner/contrasted{
@@ -67957,7 +67953,7 @@
"xXF" = (
/obj/machinery/atmospherics/components/binary/dp_vent_pump/high_volume/incinerator_ordmix,
/turf/open/floor/engine,
-/area/station/science/ordnance)
+/area/station/science/ordnance/burnchamber)
"xXY" = (
/obj/effect/turf_decal/tile/neutral/opposingcorners,
/obj/effect/turf_decal/siding/wideplating/dark/end{
@@ -111042,7 +111038,7 @@ aks
tTK
tvB
cSI
-gOY
+nkM
vxZ
dyS
lfq
@@ -111556,11 +111552,11 @@ iJZ
lcd
ecM
eKT
-gOY
+nkM
vxZ
pZK
lfq
-gOY
+nkM
cxg
cxg
vxX
@@ -112584,11 +112580,11 @@ gOY
gOY
roK
gOY
-gOY
-gOY
-gOY
-gOY
-gOY
+nkM
+nkM
+nkM
+nkM
+nkM
bwC
cLf
bwC
diff --git a/_maps/shuttles/emergency_birdshot.dmm b/_maps/shuttles/emergency_birdshot.dmm
index cb50d42c56db0..aef9231e620ed 100644
--- a/_maps/shuttles/emergency_birdshot.dmm
+++ b/_maps/shuttles/emergency_birdshot.dmm
@@ -99,7 +99,7 @@
pixel_x = 3;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/dromedary{
+/obj/item/cigarette/dromedary{
pixel_x = 8;
pixel_y = 15
},
diff --git a/_maps/shuttles/emergency_shadow.dmm b/_maps/shuttles/emergency_shadow.dmm
index de99a937b35b1..5afa72919cb28 100644
--- a/_maps/shuttles/emergency_shadow.dmm
+++ b/_maps/shuttles/emergency_shadow.dmm
@@ -468,7 +468,7 @@
},
/obj/item/kirbyplants/organic/plant21,
/obj/structure/sign/warning/hot_temp/directional/west,
-/obj/item/clothing/mask/cigarette/rollie/cannabis,
+/obj/item/cigarette/rollie/cannabis,
/turf/open/floor/iron/dark/textured_large,
/area/shuttle/escape)
"yg" = (
diff --git a/_maps/shuttles/pirate_default.dmm b/_maps/shuttles/pirate_default.dmm
index 6acff639725ff..b60aae281e0f8 100644
--- a/_maps/shuttles/pirate_default.dmm
+++ b/_maps/shuttles/pirate_default.dmm
@@ -475,7 +475,7 @@
pixel_x = 6;
pixel_y = 12
},
-/obj/item/clothing/mask/cigarette/cigar,
+/obj/item/cigarette/cigar,
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/stripes/line,
/turf/open/floor/wood,
diff --git a/_maps/shuttles/pirate_dutchman.dmm b/_maps/shuttles/pirate_dutchman.dmm
index fb36638173ed1..b599698bc6f5c 100644
--- a/_maps/shuttles/pirate_dutchman.dmm
+++ b/_maps/shuttles/pirate_dutchman.dmm
@@ -618,7 +618,7 @@
pixel_x = -4;
pixel_y = 12
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4
},
/obj/item/reagent_containers/cup/glass/drinkingglass/shotglass{
diff --git a/_maps/shuttles/whiteship_birdshot.dmm b/_maps/shuttles/whiteship_birdshot.dmm
index 593b84827bf3f..f6b31535db634 100644
--- a/_maps/shuttles/whiteship_birdshot.dmm
+++ b/_maps/shuttles/whiteship_birdshot.dmm
@@ -26,9 +26,6 @@
/obj/machinery/meter,
/turf/open/floor/catwalk_floor,
/area/shuttle/abandoned/engine)
-"bp" = (
-/turf/closed/wall/mineral/titanium/overspace,
-/area/shuttle/abandoned/engine)
"bq" = (
/obj/effect/turf_decal/siding/thinplating/dark{
dir = 1
@@ -181,11 +178,12 @@
/obj/machinery/porta_turret/centcom_shuttle/weak{
dir = 4
},
-/turf/closed/wall/mineral/titanium/overspace,
+/turf/closed/wall/mineral/titanium,
/area/shuttle/abandoned/crew)
"gj" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
- dir = 1
+ dir = 1;
+ x_offset = 4
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark/small,
@@ -339,9 +337,6 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on,
/turf/open/floor/iron/smooth_large,
/area/shuttle/abandoned/cargo)
-"ma" = (
-/turf/closed/wall/mineral/titanium/overspace,
-/area/shuttle/abandoned/cargo)
"mU" = (
/obj/structure/toilet{
pixel_y = 8
@@ -538,7 +533,7 @@
/turf/open/floor/iron/small,
/area/shuttle/abandoned/medbay)
"ry" = (
-/turf/closed/wall/mineral/titanium/overspace,
+/turf/closed/wall/mineral/titanium,
/area/shuttle/abandoned/bar)
"rO" = (
/obj/effect/decal/cleanable/dirt,
@@ -598,9 +593,6 @@
/obj/structure/sign/poster/official/random/directional/north,
/turf/open/floor/catwalk_floor,
/area/shuttle/abandoned/engine)
-"uk" = (
-/turf/closed/wall/mineral/titanium/overspace,
-/area/shuttle/abandoned/pod)
"ur" = (
/obj/effect/decal/cleanable/dirt,
/obj/machinery/atmospherics/components/unary/vent_pump/on{
@@ -1170,7 +1162,7 @@
/obj/machinery/porta_turret/centcom_shuttle/weak{
dir = 4
},
-/turf/closed/wall/mineral/titanium/overspace,
+/turf/closed/wall/mineral/titanium,
/area/shuttle/abandoned/pod)
"Ll" = (
/obj/structure/cable,
@@ -1277,7 +1269,7 @@
/obj/machinery/porta_turret/centcom_shuttle/weak{
dir = 4
},
-/turf/closed/wall/mineral/titanium/overspace,
+/turf/closed/wall/mineral/titanium,
/area/shuttle/abandoned/bridge)
"Ql" = (
/obj/effect/decal/cleanable/dirt,
@@ -1448,9 +1440,6 @@
/obj/machinery/light/built/directional/west,
/turf/open/floor/carpet/green,
/area/shuttle/abandoned/bar)
-"WG" = (
-/turf/closed/wall/mineral/titanium/overspace,
-/area/shuttle/abandoned/bridge)
"WW" = (
/obj/effect/turf_decal/tile/red/half/contrasted{
dir = 4
@@ -1538,9 +1527,9 @@
(1,1,1) = {"
lt
lt
-bp
+Gi
BH
-bp
+Gi
lt
lt
lt
@@ -1552,15 +1541,15 @@ lt
lt
lt
lt
-bp
+Gi
BH
-bp
+Gi
lt
lt
"}
(2,1,1) = {"
lt
-bp
+Gi
Om
oe
Gi
@@ -1578,7 +1567,7 @@ BH
Gi
oe
Om
-bp
+Gi
lt
"}
(3,1,1) = {"
@@ -1588,7 +1577,7 @@ Wu
RH
Gi
oe
-bp
+Gi
lt
lt
lt
@@ -1596,7 +1585,7 @@ lt
lt
lt
lt
-bp
+Gi
oe
Gi
qn
@@ -1674,7 +1663,7 @@ Gi
lt
"}
(7,1,1) = {"
-ma
+Tg
kQ
DK
er
@@ -1694,7 +1683,7 @@ uF
uF
BR
kQ
-ma
+Tg
"}
(8,1,1) = {"
kQ
@@ -1928,7 +1917,7 @@ lt
"}
(18,1,1) = {"
lt
-uk
+PN
pv
pv
pv
@@ -1946,7 +1935,7 @@ KR
JP
JP
JP
-WG
+XB
lt
"}
(19,1,1) = {"
@@ -2021,7 +2010,7 @@ lt
(22,1,1) = {"
lt
lt
-uk
+PN
pv
xr
qO
@@ -2032,12 +2021,12 @@ lt
lt
lt
lt
-WG
+XB
JP
Hk
Bs
JP
-WG
+XB
lt
lt
"}
@@ -2045,7 +2034,7 @@ lt
lt
lt
lt
-uk
+PN
BZ
BZ
Lj
@@ -2059,7 +2048,7 @@ lt
Qf
YJ
YJ
-WG
+XB
lt
lt
lt
diff --git a/_maps/shuttles/whiteship_cere.dmm b/_maps/shuttles/whiteship_cere.dmm
index aac0c4d7ada83..df697dc1739c1 100644
--- a/_maps/shuttles/whiteship_cere.dmm
+++ b/_maps/shuttles/whiteship_cere.dmm
@@ -685,7 +685,9 @@
"Hw" = (
/obj/machinery/light/small/directional/east,
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
- dir = 1
+ dir = 1;
+ x_offset = 0;
+ y_offset = 10
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/iron/dark,
diff --git a/_maps/shuttles/whiteship_donut.dmm b/_maps/shuttles/whiteship_donut.dmm
index eff7c2bfaadb7..daf150b4cdf2f 100644
--- a/_maps/shuttles/whiteship_donut.dmm
+++ b/_maps/shuttles/whiteship_donut.dmm
@@ -468,7 +468,9 @@
/area/shuttle/abandoned)
"XY" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
- dir = 1
+ dir = 1;
+ x_offset = 0;
+ y_offset = 9
},
/obj/effect/decal/cleanable/dirt,
/obj/item/disk/holodisk/donutstation/whiteship,
diff --git a/_maps/shuttles/whiteship_kilo.dmm b/_maps/shuttles/whiteship_kilo.dmm
index 8034d78126d68..3dda9d34da2a1 100644
--- a/_maps/shuttles/whiteship_kilo.dmm
+++ b/_maps/shuttles/whiteship_kilo.dmm
@@ -207,7 +207,7 @@
/obj/machinery/power/shuttle_engine/propulsion/left{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"jM" = (
/obj/structure/table,
@@ -249,8 +249,8 @@
launch_status = 0;
movement_force = list("KNOCKDOWN"=0,"THROW"=0);
name = "Mining Shuttle";
- port_direction = 4;
- preferred_direction = 8
+ port_direction = 8;
+ preferred_direction = 4
},
/turf/open/floor/plating,
/area/shuttle/abandoned/cargo)
@@ -327,7 +327,7 @@
/obj/machinery/power/shuttle_engine/propulsion{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"nt" = (
/obj/effect/turf_decal/stripes/line{
@@ -355,7 +355,7 @@
/obj/machinery/power/shuttle_engine/propulsion/right{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/bar)
"pI" = (
/obj/effect/turf_decal/delivery,
@@ -416,7 +416,7 @@
/obj/machinery/power/shuttle_engine/propulsion/right{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"rX" = (
/obj/effect/decal/cleanable/dirt,
@@ -868,7 +868,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"Nh" = (
/turf/closed/wall/mineral/plastitanium,
@@ -909,7 +909,7 @@
/obj/effect/turf_decal/stripes/line{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/bar)
"Pe" = (
/obj/machinery/button/door/directional/north{
@@ -931,7 +931,7 @@
/obj/machinery/power/shuttle_engine/propulsion/left{
dir = 8
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/bar)
"PR" = (
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden{
@@ -1031,7 +1031,9 @@
},
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
dir = 4;
- view_range = 14
+ view_range = 14;
+ y_offset = 5;
+ x_offset = 0
},
/obj/effect/turf_decal/stripes/corner{
dir = 8
diff --git a/_maps/shuttles/whiteship_obelisk.dmm b/_maps/shuttles/whiteship_obelisk.dmm
index 4b8eb9ee91b84..0f1e07b1a213e 100644
--- a/_maps/shuttles/whiteship_obelisk.dmm
+++ b/_maps/shuttles/whiteship_obelisk.dmm
@@ -206,7 +206,7 @@
/obj/machinery/power/shuttle_engine/propulsion/left{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"mQ" = (
/obj/structure/cable,
@@ -271,14 +271,14 @@
dir = 4
},
/obj/structure/window/reinforced/spawner/directional/west,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"ot" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
dir = 4;
view_range = 14;
- x_offset = -3;
- y_offset = -3
+ x_offset = -2;
+ y_offset = -7
},
/obj/effect/decal/cleanable/dirt,
/obj/effect/turf_decal/tile/dark_blue/anticorner{
@@ -438,7 +438,7 @@
/obj/effect/turf_decal/stripes{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"zj" = (
/obj/structure/cable,
@@ -699,7 +699,7 @@
/obj/machinery/power/shuttle_engine/propulsion/right{
dir = 4
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"PR" = (
/obj/structure/table/wood,
diff --git a/_maps/shuttles/whiteship_personalshuttle.dmm b/_maps/shuttles/whiteship_personalshuttle.dmm
index 8e041082bc6d9..7666f6c63add1 100644
--- a/_maps/shuttles/whiteship_personalshuttle.dmm
+++ b/_maps/shuttles/whiteship_personalshuttle.dmm
@@ -90,7 +90,7 @@
/obj/machinery/power/shuttle_engine/propulsion/right{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"cM" = (
/turf/template_noop,
@@ -100,7 +100,7 @@
dir = 1
},
/obj/structure/window/reinforced/spawner/directional/south,
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"cY" = (
/obj/machinery/atmospherics/components/unary/vent_pump/on,
@@ -372,9 +372,8 @@
"DT" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
dir = 1;
- view_range = 14;
- x_offset = -3;
- y_offset = -3
+ x_offset = 0;
+ y_offset = -5
},
/obj/effect/decal/cleanable/dirt,
/turf/open/floor/mineral/plastitanium,
@@ -523,7 +522,7 @@
/obj/machinery/power/shuttle_engine/propulsion/left{
dir = 1
},
-/turf/open/floor/plating,
+/turf/open/floor/plating/airless,
/area/shuttle/abandoned/engine)
"WL" = (
/obj/machinery/light/cold/no_nightlight/directional/west,
diff --git a/_maps/shuttles/whiteship_pubby.dmm b/_maps/shuttles/whiteship_pubby.dmm
index 56f85fcd80218..db7f00e5149c6 100644
--- a/_maps/shuttles/whiteship_pubby.dmm
+++ b/_maps/shuttles/whiteship_pubby.dmm
@@ -271,7 +271,7 @@
"lV" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
y_offset = 2;
- x_offset = -7
+ x_offset = -8
},
/obj/effect/decal/cleanable/cobweb/cobweb2,
/obj/effect/decal/cleanable/dirt,
@@ -550,7 +550,7 @@
shuttle_id = "whiteship";
launch_status = 0;
name = "White Ship";
- port_direction = 2
+ port_direction = 4
},
/turf/open/floor/plating,
/area/shuttle/abandoned)
diff --git a/_maps/shuttles/whiteship_tram.dmm b/_maps/shuttles/whiteship_tram.dmm
index 84f438accfd1d..7666e2c70ac85 100644
--- a/_maps/shuttles/whiteship_tram.dmm
+++ b/_maps/shuttles/whiteship_tram.dmm
@@ -1164,7 +1164,9 @@
/area/shuttle/abandoned/cargo)
"Ft" = (
/obj/machinery/computer/camera_advanced/shuttle_docker/whiteship{
- dir = 8
+ dir = 8;
+ x_offset = 0;
+ y_offset = 13
},
/obj/effect/turf_decal/stripes/white/corner{
dir = 1
diff --git a/_maps/templates/battlecruiser_starfury.dmm b/_maps/templates/battlecruiser_starfury.dmm
index a705c471a2564..dae5d84a869b4 100644
--- a/_maps/templates/battlecruiser_starfury.dmm
+++ b/_maps/templates/battlecruiser_starfury.dmm
@@ -2518,7 +2518,7 @@
pixel_x = -5;
pixel_y = 2
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 5;
pixel_y = 7
},
diff --git a/_maps/templates/holodeck_lounge.dmm b/_maps/templates/holodeck_lounge.dmm
index 3807be667cbf9..defc5771555d5 100644
--- a/_maps/templates/holodeck_lounge.dmm
+++ b/_maps/templates/holodeck_lounge.dmm
@@ -43,7 +43,7 @@
/area/template_noop)
"h" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/obj/effect/holodeck_effect/random_book,
/turf/open/floor/holofloor/carpet,
/area/template_noop)
@@ -256,7 +256,7 @@
/area/template_noop)
"T" = (
/obj/structure/table/wood/poker,
-/obj/item/clothing/mask/cigarette/pipe,
+/obj/item/cigarette/pipe,
/turf/open/floor/holofloor{
dir = 9;
icon_state = "wood"
diff --git a/_maps/templates/lazy_templates/nukie_base.dmm b/_maps/templates/lazy_templates/nukie_base.dmm
index febfc926cdc0e..bc136b886becf 100644
--- a/_maps/templates/lazy_templates/nukie_base.dmm
+++ b/_maps/templates/lazy_templates/nukie_base.dmm
@@ -2590,7 +2590,7 @@
pixel_x = 3;
pixel_y = 6
},
-/obj/item/clothing/mask/cigarette/robust{
+/obj/item/cigarette/robust{
pixel_x = -4;
pixel_y = 1
},
diff --git a/_maps/templates/lazy_templates/wizard_den.dmm b/_maps/templates/lazy_templates/wizard_den.dmm
index 472dde511c475..2415fe227c6b0 100644
--- a/_maps/templates/lazy_templates/wizard_den.dmm
+++ b/_maps/templates/lazy_templates/wizard_den.dmm
@@ -46,7 +46,7 @@
/area/centcom/wizard_station)
"dr" = (
/obj/structure/table/wood,
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_y = -9;
pixel_x = -5
},
diff --git a/_maps/virtual_domains/pirates.dmm b/_maps/virtual_domains/pirates.dmm
index 28e64519e5738..5ad9c23595d64 100644
--- a/_maps/virtual_domains/pirates.dmm
+++ b/_maps/virtual_domains/pirates.dmm
@@ -186,7 +186,7 @@
/obj/item/melee/energy/sword/pirate{
pixel_y = 10
},
-/obj/item/clothing/mask/cigarette/cigar{
+/obj/item/cigarette/cigar{
pixel_x = 4
},
/obj/item/lighter{
diff --git a/code/__DEFINES/antagonists.dm b/code/__DEFINES/antagonists.dm
index c865c578d6324..185ab2e3d3177 100644
--- a/code/__DEFINES/antagonists.dm
+++ b/code/__DEFINES/antagonists.dm
@@ -113,6 +113,7 @@
#define CONSTRUCT_JUGGERNAUT "Juggernaut"
#define CONSTRUCT_WRAITH "Wraith"
#define CONSTRUCT_ARTIFICER "Artificer"
+#define CONSTRUCT_HARVESTER "Harvester"
/// The Classic Wizard wizard loadout.
#define WIZARD_LOADOUT_CLASSIC "loadout_classic"
diff --git a/code/__DEFINES/colors.dm b/code/__DEFINES/colors.dm
index d1f489f0555ef..72159bde0540e 100644
--- a/code/__DEFINES/colors.dm
+++ b/code/__DEFINES/colors.dm
@@ -72,6 +72,7 @@
#define COLOR_LIME "#32CD32"
#define COLOR_DARK_LIME "#00aa00"
#define COLOR_VERY_PALE_LIME_GREEN "#DDFFD3"
+#define COLOR_HERETIC_GREEN COLOR_VERY_PALE_LIME_GREEN // i am co-opting this as heretic glow.
#define COLOR_VERY_DARK_LIME_GREEN "#003300"
#define COLOR_GREEN "#008000"
#define COLOR_CHRISTMAS_GREEN "#00873E"
@@ -130,6 +131,7 @@
#define COLOR_DARK_ORANGE "#C3630C"
#define COLOR_PRISONER_ORANGE "#A54900"
#define COLOR_DARK_MODERATE_ORANGE "#8B633B"
+#define COLOR_RUSTED_GLASS "#917c65"
#define COLOR_BROWN "#BA9F6D"
#define COLOR_DARK_BROWN "#997C4F"
diff --git a/code/__DEFINES/cult.dm b/code/__DEFINES/cult.dm
index 06393d145f8ca..005b0ca27eef8 100644
--- a/code/__DEFINES/cult.dm
+++ b/code/__DEFINES/cult.dm
@@ -9,6 +9,8 @@
#define RUNE_COLOR_SUMMON COLOR_VIBRANT_LIME
//blood magic
+/// The maximum number of cult spell slots each cultist is allowed to scribe at once.
+#define ENHANCED_BLOODCHARGE 5
#define MAX_BLOODCHARGE 4
#define RUNELESS_MAX_BLOODCHARGE 1
/// percent before rise
@@ -28,6 +30,8 @@
#define THEME_CULT "cult"
#define THEME_WIZARD "wizard"
#define THEME_HOLY "holy"
+/// Only used for heretic Harvesters, obtained from sacrificing cultists
+#define THEME_HERETIC "heretic"
/// Defines for cult item_dispensers.
#define PREVIEW_IMAGE "preview"
@@ -51,3 +55,8 @@ GLOBAL_LIST(sacrificed)
#define CULT_VICTORY 1
#define CULT_LOSS 0
#define CULT_NARSIE_KILLED -1
+
+// Used to keep track of items rewarded after a heretic is sacked.
+#define CURSED_BLADE_UNLOCKED "Cursed Blade"
+#define CRIMSON_FOCUS_UNLOCKED "Crimson Focus"
+#define PROTEON_ORB_UNLOCKED "Proteon Orb"
diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
index 3725c549df4e5..c612d174ac354 100644
--- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
+++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_main.dm
@@ -134,6 +134,9 @@
///cancel clean
#define COMSIG_ATOM_CANCEL_CLEAN (1<<0)
+/// From /obj/item/stack/make_item()
+#define COMSIG_ATOM_CONSTRUCTED "atom_constructed"
+
/// From /obj/effect/particle_effect/sparks/proc/sparks_touched(datum/source, atom/movable/singed)
#define COMSIG_ATOM_TOUCHED_SPARKS "atom_touched_sparks"
#define COMSIG_ATOM_TOUCHED_HAZARDOUS_SPARKS "atom_touched_hazardous_sparks"
diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
index ca4130ad28c67..517048bbd4d1d 100644
--- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
+++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm
@@ -204,6 +204,10 @@
#define STOP_SACRIFICE (1<<0)
/// Don't send a message for sacrificing this thing, we have our own
#define SILENCE_SACRIFICE_MESSAGE (1<<1)
+ /// Don't send a message for sacrificing this thing UNLESS it's the cult target
+ #define SILENCE_NONTARGET_SACRIFICE_MESSAGE (1<<2)
+ /// Dusts the target instead of gibbing them (no soulstone)
+ #define DUST_SACRIFICE (1<<3)
/// From /mob/living/befriend() : (mob/living/new_friend)
#define COMSIG_LIVING_BEFRIENDED "living_befriended"
diff --git a/code/__DEFINES/is_helpers.dm b/code/__DEFINES/is_helpers.dm
index 3430f97dd7dcd..ba467347e87d2 100644
--- a/code/__DEFINES/is_helpers.dm
+++ b/code/__DEFINES/is_helpers.dm
@@ -231,6 +231,8 @@ GLOBAL_LIST_INIT(turfs_pass_meteor, typecacheof(list(
#define islandmine(A) (istype(A, /obj/effect/mine))
+#define iscloset(A) (istype(A, /obj/structure/closet))
+
#define issupplypod(A) (istype(A, /obj/structure/closet/supplypod))
#define isammocasing(A) (istype(A, /obj/item/ammo_casing))
diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm
index 1a6d0d5f18dfa..f3b6020b051ba 100644
--- a/code/__DEFINES/traits/declarations.dm
+++ b/code/__DEFINES/traits/declarations.dm
@@ -98,6 +98,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
#define TRAIT_IWASBATONED "iwasbatoned"
#define TRAIT_SLEEPIMMUNE "sleep_immunity"
#define TRAIT_PUSHIMMUNE "push_immunity"
+/// can't be kicked to the side
+#define TRAIT_NO_SIDE_KICK "no_side_kick"
/// Are we immune to shocks?
#define TRAIT_SHOCKIMMUNE "shock_immunity"
/// Are we immune to specifically tesla / SM shocks?
@@ -1089,6 +1091,11 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Note this doesn't mean all spells are guaranteed to work or the mob is guaranteed to cast
#define TRAIT_CASTABLE_LOC "castable_loc"
+/// Needs above trait to work.
+/// This trait makes it so that any cast spells will attempt to transfer to the location's location.
+/// For example, a heretic inside the haunted blade's spells would emanate from the mob wielding the sword.
+#define TRAIT_SPELLS_TRANSFER_TO_LOC "spells_transfer_to_loc"
+
///Trait given by /datum/element/relay_attacker
#define TRAIT_RELAYING_ATTACKER "relaying_attacker"
@@ -1151,6 +1158,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai
/// Trait applied to objects and mobs that can attack a boulder and break it down. (See /obj/item/boulder/manual_process())
#define TRAIT_BOULDER_BREAKER "boulder_breaker"
+/// Trait given to anything linked to, not necessarily allied to, the mansus
+#define TRAIT_MANSUS_TOUCHED "mansus_touched"
+
/// Trait given to mobs wearing the clown mask
#define TRAIT_PERCEIVED_AS_CLOWN "perceived_as_clown"
/// Does this item bypass ranged armor checks?
diff --git a/code/__HELPERS/turfs.dm b/code/__HELPERS/turfs.dm
index c44845a5854b7..88509b88ce802 100644
--- a/code/__HELPERS/turfs.dm
+++ b/code/__HELPERS/turfs.dm
@@ -400,8 +400,8 @@ Turf and target are separate in case you want to teleport some distance from a t
/**
* Checks whether or not a particular typepath or subtype of it is present on a turf
*
- * Returns TRUE if an instance of the desired type or a subtype of it is found
- * Returns FALSE if the type is not found, or if no turf is supplied
+ * Returns the first instance located if an instance of the desired type or a subtype of it is found
+ * Returns null if the type is not found, or if no turf is supplied
*
* Arguments:
* * location - The turf to be checked for the desired type
@@ -409,10 +409,9 @@ Turf and target are separate in case you want to teleport some distance from a t
*/
/proc/is_type_on_turf(turf/location, type_to_find)
if(!location)
- return FALSE
- if(locate(type_to_find) in location)
- return TRUE
- return FALSE
+ return
+ var/found_type = locate(type_to_find) in location
+ return found_type
/**
* get_blueprint_data
diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm
index 9aaf244daa4a7..9823a7ff55160 100644
--- a/code/_globalvars/phobias.dm
+++ b/code/_globalvars/phobias.dm
@@ -245,7 +245,7 @@ GLOBAL_LIST_INIT(phobia_objs, list(
/obj/item/clothing/suit/hooded/carp_costume,
/obj/item/clothing/head/fedora/carpskin,
/obj/item/clothing/mask/gas/carp,
- /obj/item/clothing/mask/cigarette/carp,
+ /obj/item/cigarette/carp,
/obj/item/clothing/under/suit/carpskin,
/obj/item/food/cubancarp,
/obj/item/food/fishmeat/carp,
@@ -492,7 +492,6 @@ GLOBAL_LIST_INIT(phobia_objs, list(
/obj/item/clothing/suit/wizrobe,
/obj/item/clothing/under/rank/civilian/chaplain,
/obj/item/codex_cicatrix,
- /obj/item/cult_bastard,
/obj/item/gun/magic,
/obj/item/melee/cultblade,
/obj/item/melee/rune_carver,
diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm
index 1d0d05d521ebb..87092adcff080 100644
--- a/code/_globalvars/traits/_traits.dm
+++ b/code/_globalvars/traits/_traits.dm
@@ -56,6 +56,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_NO_MISSING_ITEM_ERROR" = TRAIT_NO_MISSING_ITEM_ERROR,
"TRAIT_NO_THROW_HITPUSH" = TRAIT_NO_THROW_HITPUSH,
"TRAIT_NOT_ENGRAVABLE" = TRAIT_NOT_ENGRAVABLE,
+ "TRAIT_SPELLS_TRANSFER_TO_LOC" = TRAIT_SPELLS_TRANSFER_TO_LOC,
"TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT" = TRAIT_ODD_CUSTOMIZABLE_FOOD_INGREDIENT,
"TRAIT_RUNECHAT_HIDDEN" = TRAIT_RUNECHAT_HIDDEN,
"TRAIT_SECLUDED_LOCATION" = TRAIT_SECLUDED_LOCATION,
@@ -149,6 +150,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE,
"TRAIT_BONSAI" = TRAIT_BONSAI,
"TRAIT_BOOZE_SLIDER" = TRAIT_BOOZE_SLIDER,
+ "TRAIT_BOXING_READY" = TRAIT_BOXING_READY,
"TRAIT_BORN_MONKEY" = TRAIT_BORN_MONKEY,
"TRAIT_BOXING_READY" = TRAIT_BOXING_READY,
"TRAIT_BRAINWASHING" = TRAIT_BRAINWASHING,
@@ -296,6 +298,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_MAGICALLY_GIFTED" = TRAIT_MAGICALLY_GIFTED,
"TRAIT_MAGICALLY_PHASED" = TRAIT_MAGICALLY_PHASED,
"TRAIT_MARTIAL_ARTS_IMMUNE" = TRAIT_MARTIAL_ARTS_IMMUNE,
+ "TRAIT_MANSUS_TOUCHED" = TRAIT_MANSUS_TOUCHED,
"TRAIT_MEDIBOTCOMINGTHROUGH" = TRAIT_MEDIBOTCOMINGTHROUGH,
"TRAIT_MEDICAL_HUD" = TRAIT_MEDICAL_HUD,
"TRAIT_MESON_VISION" = TRAIT_MESON_VISION,
@@ -535,6 +538,7 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_NO_BARCODES" = TRAIT_NO_BARCODES,
"TRAIT_NO_STORAGE_INSERT" = TRAIT_NO_STORAGE_INSERT,
"TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT,
+ "TRAIT_NO_SIDE_KICK" = TRAIT_NO_SIDE_KICK,
"TRAIT_NODROP" = TRAIT_NODROP,
"TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT,
"TRAIT_PLANT_WILDMUTATE" = TRAIT_PLANT_WILDMUTATE,
diff --git a/code/_onclick/hud/alert.dm b/code/_onclick/hud/alert.dm
index 2cfa8147c490f..f8f79f442940b 100644
--- a/code/_onclick/hud/alert.dm
+++ b/code/_onclick/hud/alert.dm
@@ -525,7 +525,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
alerttooltipstyle = "cult"
var/static/image/narnar
var/angle = 0
- var/mob/living/basic/construct/Cviewer
+ var/mob/living/basic/construct/construct_owner
/atom/movable/screen/alert/bloodsense/Initialize(mapload, datum/hud/hud_owner)
. = ..()
@@ -533,7 +533,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
START_PROCESSING(SSprocessing, src)
/atom/movable/screen/alert/bloodsense/Destroy()
- Cviewer = null
+ construct_owner = null
STOP_PROCESSING(SSprocessing, src)
return ..()
@@ -543,45 +543,53 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
if(!owner.mind)
return
+ if(isconstruct(owner))
+ construct_owner = owner
+ else
+ construct_owner = null
+
+ // construct track
+ if(construct_owner?.seeking && construct_owner.master)
+ blood_target = construct_owner.master
+ desc = "Your blood sense is leading you to [construct_owner.master]"
+
+ // cult track
var/datum/antagonist/cult/antag = owner.mind.has_antag_datum(/datum/antagonist/cult,TRUE)
- if(!antag)
- return
- var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
+ if(antag)
+ var/datum/objective/sacrifice/sac_objective = locate() in antag.cult_team.objectives
+ if(antag.cult_team.blood_target)
+ if(!get_turf(antag.cult_team.blood_target))
+ antag.cult_team.unset_blood_target()
+ else
+ blood_target = antag.cult_team.blood_target
+ if(!blood_target)
+ if(sac_objective && !sac_objective.check_completion())
+ if(icon_state == "runed_sense0")
+ return
+ animate(src, transform = null, time = 1, loop = 0)
+ angle = 0
+ cut_overlays()
+ icon_state = "runed_sense0"
+ desc = "Nar'Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
+ add_overlay(sac_objective.sac_image)
+ else
+ var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
+ if(!summon_objective)
+ return
+ var/list/location_list = list()
+ for(var/area/area_to_check in summon_objective.summon_spots)
+ location_list += area_to_check.get_original_area_name()
+ desc = "The sacrifice is complete, summon Nar'Sie! The summoning can only take place in [english_list(location_list)]!"
+ if(icon_state == "runed_sense1")
+ return
+ animate(src, transform = null, time = 1, loop = 0)
+ angle = 0
+ cut_overlays()
+ icon_state = "runed_sense1"
+ add_overlay(narnar)
+ return
- if(antag.cult_team.blood_target)
- if(!get_turf(antag.cult_team.blood_target))
- antag.cult_team.unset_blood_target()
- else
- blood_target = antag.cult_team.blood_target
- if(Cviewer?.seeking && Cviewer.master)
- blood_target = Cviewer.master
- desc = "Your blood sense is leading you to [Cviewer.master]"
- if(!blood_target)
- if(sac_objective && !sac_objective.check_completion())
- if(icon_state == "runed_sense0")
- return
- animate(src, transform = null, time = 1, loop = 0)
- angle = 0
- cut_overlays()
- icon_state = "runed_sense0"
- desc = "Nar'Sie demands that [sac_objective.target] be sacrificed before the summoning ritual can begin."
- add_overlay(sac_objective.sac_image)
- else
- var/datum/objective/eldergod/summon_objective = locate() in antag.cult_team.objectives
- if(!summon_objective)
- return
- var/list/location_list = list()
- for(var/area/area_to_check in summon_objective.summon_spots)
- location_list += area_to_check.get_original_area_name()
- desc = "The sacrifice is complete, summon Nar'Sie! The summoning can only take place in [english_list(location_list)]!"
- if(icon_state == "runed_sense1")
- return
- animate(src, transform = null, time = 1, loop = 0)
- angle = 0
- cut_overlays()
- icon_state = "runed_sense1"
- add_overlay(narnar)
- return
+ // actual tracking
var/turf/P = get_turf(blood_target)
var/turf/Q = get_turf(owner)
if(!P || !Q || (P.z != Q.z)) //The target is on a different Z level, we cannot sense that far.
@@ -593,6 +601,7 @@ or shoot a gun to move around via Newton's 3rd Law of Motion."
desc = "You are currently tracking [real_target.real_name] in [get_area_name(blood_target)]."
else
desc = "You are currently tracking [blood_target] in [get_area_name(blood_target)]."
+
var/target_angle = get_angle(Q, P)
var/target_dist = get_dist(P, Q)
cut_overlays()
diff --git a/code/datums/actions/items/cult_dagger.dm b/code/datums/actions/items/cult_dagger.dm
index 76e92c7b23198..6b188e85e9071 100644
--- a/code/datums/actions/items/cult_dagger.dm
+++ b/code/datums/actions/items/cult_dagger.dm
@@ -17,10 +17,10 @@
return ..()
/datum/action/item_action/cult_dagger/Trigger(trigger_flags)
- for(var/obj/item/held_item as anything in owner.held_items) // In case we were already holding a dagger
- if(istype(held_item, /obj/item/melee/cultblade/dagger))
- held_item.attack_self(owner)
- return
+ if(target in owner.held_items)
+ var/obj/item/target_item = target
+ target_item.attack_self(owner)
+ return
var/obj/item/target_item = target
if(owner.can_equip(target_item, ITEM_SLOT_HANDS))
owner.temporarilyRemoveItemFromInventory(target_item)
diff --git a/code/datums/elements/amputating_limbs.dm b/code/datums/components/amputating_limbs.dm
similarity index 65%
rename from code/datums/elements/amputating_limbs.dm
rename to code/datums/components/amputating_limbs.dm
index 8684a76f47fc3..bfaf52ca90ca5 100644
--- a/code/datums/elements/amputating_limbs.dm
+++ b/code/datums/components/amputating_limbs.dm
@@ -1,7 +1,5 @@
/// This component will intercept bare-handed attacks by the owner on sufficiently injured carbons and amputate random limbs instead
-/datum/element/amputating_limbs
- element_flags = ELEMENT_BESPOKE
- argument_hash_start_idx = 2
+/datum/component/amputating_limbs
/// How long does it take?
var/surgery_time
/// What is the means by which we describe the act of amputation?
@@ -12,34 +10,38 @@
var/snip_chance
/// The types of limb we can remove
var/list/target_zones
+ /// Callback for a proc right before confirming the attack. If it returns FALSE, cancel
+ var/datum/callback/pre_hit_callback
-/datum/element/amputating_limbs/Attach(
- datum/target,
+/datum/component/amputating_limbs/Initialize(
surgery_time = 5 SECONDS,
surgery_verb = "prying",
minimum_stat = SOFT_CRIT,
snip_chance = 100,
list/target_zones = list(BODY_ZONE_L_ARM, BODY_ZONE_L_LEG, BODY_ZONE_R_ARM, BODY_ZONE_R_LEG),
+ datum/callback/pre_hit_callback,
)
. = ..()
- if (!isliving(target))
- return ELEMENT_INCOMPATIBLE
+ if (!isliving(parent))
+ return COMPONENT_INCOMPATIBLE
if (!length(target_zones))
- CRASH("[src] for [target] was not provided a valid list of body zones to target.")
+ CRASH("[src] for [parent] was not provided a valid list of body zones to target.")
src.surgery_time = surgery_time
src.surgery_verb = surgery_verb
src.minimum_stat = minimum_stat
src.snip_chance = snip_chance
src.target_zones = target_zones
- RegisterSignals(target, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_amputate))
+ src.pre_hit_callback = pre_hit_callback
-/datum/element/amputating_limbs/Detach(datum/source)
- UnregisterSignal(source, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET))
- return ..()
+/datum/component/amputating_limbs/RegisterWithParent()
+ RegisterSignals(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET), PROC_REF(try_amputate))
+
+/datum/component/amputating_limbs/UnregisterFromParent()
+ UnregisterSignal(parent, list(COMSIG_LIVING_UNARMED_ATTACK, COMSIG_HOSTILE_PRE_ATTACKINGTARGET))
/// Called when you click on literally anything with your hands, see if it is an injured carbon and then try to cut it up
-/datum/element/amputating_limbs/proc/try_amputate(mob/living/surgeon, atom/victim, proximity, modifiers)
+/datum/component/amputating_limbs/proc/try_amputate(mob/living/surgeon, atom/victim, proximity, modifiers)
SIGNAL_HANDLER
if (!proximity || !iscarbon(victim) || HAS_TRAIT(victim, TRAIT_NODISMEMBER) || !prob(snip_chance))
return
@@ -52,6 +54,9 @@
surgeon.balloon_alert(surgeon, "already busy!")
return COMPONENT_CANCEL_ATTACK_CHAIN
+ if(pre_hit_callback && !pre_hit_callback.Invoke(victim))
+ return
+
var/list/valid_targets = list()
for (var/obj/item/bodypart/possible_target as anything in limbed_victim.bodyparts)
if (possible_target.bodypart_flags & BODYPART_UNREMOVABLE)
@@ -67,8 +72,9 @@
return COMPONENT_CANCEL_ATTACK_CHAIN
/// Chop one off
-/datum/element/amputating_limbs/proc/amputate(mob/living/surgeon, mob/living/carbon/victim, obj/item/bodypart/to_remove)
- surgeon.visible_message(span_warning("[surgeon] [surgery_verb] [to_remove] off of [victim]!"))
+/datum/component/amputating_limbs/proc/amputate(mob/living/surgeon, mob/living/carbon/victim, obj/item/bodypart/to_remove)
+ if(surgery_time > 0 SECONDS)
+ surgeon.visible_message(span_warning("[surgeon] is [surgery_verb] the [to_remove] off of [victim]!"))
if (surgery_time > 0 && !do_after(surgeon, delay = surgery_time, target = victim))
return
to_remove.dismember()
diff --git a/code/datums/components/cult_ritual_item.dm b/code/datums/components/cult_ritual_item.dm
index 7d9710977cecb..dedd30bda0ef5 100644
--- a/code/datums/components/cult_ritual_item.dm
+++ b/code/datums/components/cult_ritual_item.dm
@@ -128,6 +128,7 @@
INVOKE_ASYNC(src, PROC_REF(do_destroy_girder), target, cultist)
return COMPONENT_NO_AFTERATTACK
+
if(istype(target, /obj/structure/destructible/cult))
INVOKE_ASYNC(src, PROC_REF(do_unanchor_structure), target, cultist)
return COMPONENT_NO_AFTERATTACK
diff --git a/code/datums/components/damage_aura.dm b/code/datums/components/damage_aura.dm
index 98d323aa6d532..9c4e996113b84 100644
--- a/code/datums/components/damage_aura.dm
+++ b/code/datums/components/damage_aura.dm
@@ -36,6 +36,12 @@
/// Which factions are immune to the damage aura
var/list/immune_factions = null
+ /// If set, gives a message when damaged
+ var/damage_message = null
+
+ /// Probability for above.
+ var/message_probability = 0
+
/// Sets a special set of conditions for the owner
var/datum/weakref/current_owner = null
@@ -54,6 +60,8 @@
organ_damage = null,
simple_damage = 0,
immune_factions = null,
+ damage_message = null,
+ message_probability = 0,
mob/living/current_owner = null,
)
if (!isatom(parent))
@@ -72,6 +80,8 @@
src.organ_damage = organ_damage
src.simple_damage = simple_damage
src.immune_factions = immune_factions
+ src.damage_message = damage_message
+ src.message_probability = message_probability
src.current_owner = WEAKREF(current_owner)
/datum/component/damage_aura/Destroy(force)
@@ -120,6 +130,9 @@
if (candidate.health < candidate.maxHealth)
new /obj/effect/temp_visual/cosmic_gem(get_turf(candidate))
+ if(damage_message && prob(message_probability))
+ to_chat(candidate, damage_message)
+
if (iscarbon(candidate) || issilicon(candidate) || isbasicmob(candidate))
candidate.adjustBruteLoss(brute_damage * seconds_per_tick, updating_health = FALSE)
candidate.adjustFireLoss(burn_damage * seconds_per_tick, updating_health = FALSE)
diff --git a/code/datums/components/ghost_direct_control.dm b/code/datums/components/ghost_direct_control.dm
index de5bca4fcadde..fb3a2c06e8360 100644
--- a/code/datums/components/ghost_direct_control.dm
+++ b/code/datums/components/ghost_direct_control.dm
@@ -142,13 +142,20 @@
return
if (extra_control_checks && !extra_control_checks.Invoke(harbinger))
return
+
harbinger.log_message("took control of [new_body].", LOG_GAME)
+ // doesn't transfer mind because that transfers antag datum as well
new_body.key = harbinger.key
- to_chat(new_body, span_boldnotice(assumed_control_message))
- after_assumed_control?.Invoke(harbinger)
+
+ // Already qdels due to below proc but just in case
qdel(src)
-/// When someone else assumes control via some other means, get rid of our component
-/datum/component/ghost_direct_control/proc/on_login()
+/// When someone assumes control, get rid of our component
+/datum/component/ghost_direct_control/proc/on_login(mob/harbinger)
SIGNAL_HANDLER
+ // This proc is called the very moment .key is set, so we need to force mind to initialize here if we want the invoke to affect the mind of the mob
+ if(isnull(harbinger.mind))
+ harbinger.mind_initialize()
+ to_chat(harbinger, span_boldnotice(assumed_control_message))
+ after_assumed_control?.Invoke(harbinger)
qdel(src)
diff --git a/code/datums/components/spawner.dm b/code/datums/components/spawner.dm
index 29767d11ce6d1..26dbffaef6ff6 100644
--- a/code/datums/components/spawner.dm
+++ b/code/datums/components/spawner.dm
@@ -11,6 +11,8 @@
var/list/faction
/// List of weak references to things we have already created
var/list/spawned_things = list()
+ /// Callback to a proc that is called when a mob is spawned. Primarily used for sentient spawners.
+ var/datum/callback/spawn_callback
/// How many mobs can we spawn maximum each time we try to spawn? (1 - max)
var/max_spawn_per_attempt
/// Distance from the spawner to spawn mobs
@@ -19,7 +21,7 @@
var/spawn_distance_exclude
COOLDOWN_DECLARE(spawn_delay)
-/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 1 , faction = list(FACTION_MINING), spawn_text = null, spawn_distance = 1, spawn_distance_exclude = 0)
+/datum/component/spawner/Initialize(spawn_types = list(), spawn_time = 30 SECONDS, max_spawned = 5, max_spawn_per_attempt = 1 , faction = list(FACTION_MINING), spawn_text = null, datum/callback/spawn_callback = null, spawn_distance = 1, spawn_distance_exclude = 0, initial_spawn_delay = 0 SECONDS)
if (!islist(spawn_types))
CRASH("invalid spawn_types to spawn specified for spawner component!")
src.spawn_time = spawn_time
@@ -27,9 +29,13 @@
src.faction = faction
src.spawn_text = spawn_text
src.max_spawned = max_spawned
+ src.spawn_callback = spawn_callback
src.max_spawn_per_attempt = max_spawn_per_attempt
src.spawn_distance = spawn_distance
src.spawn_distance_exclude = spawn_distance_exclude
+ // If set, doesn't instantly spawn a creature when the spawner component is applied.
+ if(initial_spawn_delay)
+ COOLDOWN_START(src, spawn_delay, spawn_time)
RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(stop_spawning))
RegisterSignal(parent, COMSIG_VENT_WAVE_CONCLUDED, PROC_REF(stop_spawning))
@@ -89,6 +95,7 @@
SEND_SIGNAL(src, COMSIG_SPAWNER_SPAWNED, created)
RegisterSignal(created, COMSIG_QDELETING, PROC_REF(on_deleted))
+ spawn_callback?.Invoke(created)
if (spawn_text)
diff --git a/code/datums/components/spirit_holding.dm b/code/datums/components/spirit_holding.dm
index 578e378b51cb9..a7accc38352ee 100644
--- a/code/datums/components/spirit_holding.dm
+++ b/code/datums/components/spirit_holding.dm
@@ -6,12 +6,20 @@
/datum/component/spirit_holding
///bool on if this component is currently polling for observers to inhabit the item
var/attempting_awakening = FALSE
+ /// Allows renaming the bound item
+ var/allow_renaming
+ /// Allows channeling
+ var/allow_channeling
///mob contained in the item.
var/mob/living/basic/shade/bound_spirit
-/datum/component/spirit_holding/Initialize()
+/datum/component/spirit_holding/Initialize(datum/mind/soul_to_bind, mob/awakener, allow_renaming = TRUE, allow_channeling = TRUE)
if(!ismovable(parent)) //you may apply this to mobs, i take no responsibility for how that works out
return COMPONENT_INCOMPATIBLE
+ src.allow_renaming = allow_renaming
+ src.allow_channeling = allow_channeling
+ if(soul_to_bind)
+ bind_the_soule(soul_to_bind, awakener, soul_to_bind.name)
/datum/component/spirit_holding/Destroy(force)
. = ..()
@@ -30,7 +38,7 @@
/datum/component/spirit_holding/proc/on_examine(datum/source, mob/user, list/examine_list)
SIGNAL_HANDLER
if(!bound_spirit)
- examine_list += span_notice("[parent] sleeps. Use [parent] in your hands to attempt to awaken it.")
+ examine_list += span_notice("[parent] sleeps.[allow_channeling ? " Use [parent] in your hands to attempt to awaken it." : ""]")
return
examine_list += span_notice("[parent] is alive.")
@@ -48,6 +56,9 @@
thing.balloon_alert(user, "spirits are unwilling!")
to_chat(user, span_warning("Anomalous otherworldly energies block you from awakening [parent]!"))
return
+ if(!allow_channeling && bound_spirit)
+ to_chat(user, span_warning("Try as you might, the spirit within slumbers."))
+ return
attempting_awakening = TRUE
thing.balloon_alert(user, "channeling...")
var/mob/chosen_one = SSpolling.poll_ghosts_for_target(
@@ -74,28 +85,29 @@
// Immediately unregister to prevent making a new spirit
UnregisterSignal(parent, COMSIG_ITEM_ATTACK_SELF)
-
if(QDELETED(parent)) //if the thing that we're conjuring a spirit in has been destroyed, don't create a spirit
to_chat(ghost, span_userdanger("The new vessel for your spirit has been destroyed! You remain an unbound ghost."))
return
- bound_spirit = new(parent)
- bound_spirit.ckey = ghost.ckey
- bound_spirit.fully_replace_character_name(null, "The spirit of [parent]")
- bound_spirit.status_flags |= GODMODE
- bound_spirit.copy_languages(awakener, LANGUAGE_MASTER) //Make sure the sword can understand and communicate with the awakener.
- bound_spirit.get_language_holder().omnitongue = TRUE //Grants omnitongue
+ bind_the_soule(ghost, awakener)
- //Add new signals for parent and stop attempting to awaken
- RegisterSignal(parent, COMSIG_ATOM_RELAYMOVE, PROC_REF(block_buckle_message))
- RegisterSignal(parent, COMSIG_BIBLE_SMACKED, PROC_REF(on_bible_smacked))
+ attempting_awakening = FALSE
+ if(!allow_renaming)
+ return
// Now that all of the important things are in place for our spirit, it's time for them to choose their name.
var/valid_input_name = custom_name(awakener)
if(valid_input_name)
bound_spirit.fully_replace_character_name(null, "The spirit of [valid_input_name]")
- attempting_awakening = FALSE
+/datum/component/spirit_holding/proc/bind_the_soule(datum/mind/chosen_spirit, mob/awakener, name_override)
+ bound_spirit = new(parent)
+ chosen_spirit.transfer_to(bound_spirit)
+ bound_spirit.fully_replace_character_name(null, "The spirit of [name_override ? name_override : parent]")
+ bound_spirit.get_language_holder().omnitongue = TRUE //Grants omnitongue
+
+ RegisterSignal(parent, COMSIG_ATOM_RELAYMOVE, PROC_REF(block_buckle_message))
+ RegisterSignal(parent, COMSIG_BIBLE_SMACKED, PROC_REF(on_bible_smacked))
/**
* custom_name : Simply sends a tgui input text box to the blade asking what name they want to be called, and retries it if the input is invalid.
diff --git a/code/datums/components/supermatter_crystal.dm b/code/datums/components/supermatter_crystal.dm
index 9ff049e21fcbb..81a29b56c6d81 100644
--- a/code/datums/components/supermatter_crystal.dm
+++ b/code/datums/components/supermatter_crystal.dm
@@ -161,8 +161,8 @@
return
if(is_type_in_typecache(item, sm_item_whitelist))
return FALSE
- if(istype(item, /obj/item/clothing/mask/cigarette))
- var/obj/item/clothing/mask/cigarette/cig = item
+ if(istype(item, /obj/item/cigarette))
+ var/obj/item/cigarette/cig = item
var/clumsy = HAS_TRAIT(user, TRAIT_CLUMSY)
if(clumsy)
var/which_hand = BODY_ZONE_L_ARM
diff --git a/code/datums/elements/cult_eyes.dm b/code/datums/elements/cult_eyes.dm
index 3a46aa42c951a..3e685419836f7 100644
--- a/code/datums/elements/cult_eyes.dm
+++ b/code/datums/elements/cult_eyes.dm
@@ -1,4 +1,4 @@
-/**
+/***
* # Cult eyes element
*
* Applies and removes the glowing cult eyes
@@ -16,8 +16,7 @@
/**
* Cult eye setter proc
- *
- * Changes the eye color, and adds the glowing eye trait to the mob.
+ * * Changes the eye color, and adds the glowing eye trait to the mob.
*/
/datum/element/cult_eyes/proc/set_eyes(mob/living/target)
SIGNAL_HANDLER
diff --git a/code/datums/elements/eyestab.dm b/code/datums/elements/eyestab.dm
index 5686524d793bc..b8c0d78c4ae5c 100644
--- a/code/datums/elements/eyestab.dm
+++ b/code/datums/elements/eyestab.dm
@@ -94,8 +94,9 @@
eyes.set_organ_damage(eyes.low_threshold)
// At over 10 damage, there is a 50% chance they drop all their items
- if (prob(50))
- if (target.stat != DEAD && target.drop_all_held_items())
+ if (prob(50) && target.stat != DEAD)
+ var/list/dropped = target.drop_all_held_items()
+ if(length(dropped))
to_chat(target, span_danger("You drop what you're holding and clutch at your eyes!"))
target.adjust_eye_blur_up_to(20 SECONDS, EYESTAB_MAX_BLUR)
target.Unconscious(2 SECONDS)
diff --git a/code/datums/elements/leeching_walk.dm b/code/datums/elements/leeching_walk.dm
new file mode 100644
index 0000000000000..c0afc52b24583
--- /dev/null
+++ b/code/datums/elements/leeching_walk.dm
@@ -0,0 +1,57 @@
+/// Buffs and heals the target while standing on rust.
+/datum/element/leeching_walk
+
+/datum/element/leeching_walk/Attach(datum/target)
+ . = ..()
+ if (!isliving(target))
+ return ELEMENT_INCOMPATIBLE
+
+ RegisterSignal(target, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
+ RegisterSignal(target, COMSIG_LIVING_LIFE, PROC_REF(on_life))
+
+/datum/element/leeching_walk/Detach(datum/source)
+ . = ..()
+ UnregisterSignal(source, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_LIFE))
+
+/*
+ * Signal proc for [COMSIG_MOVABLE_MOVED].
+ *
+ * Checks if we should have baton resistance on the new turf.
+ */
+/datum/element/leeching_walk/proc/on_move(mob/source, atom/old_loc, dir, forced, list/old_locs)
+ SIGNAL_HANDLER
+
+ var/turf/mover_turf = get_turf(source)
+ if(HAS_TRAIT(mover_turf, TRAIT_RUSTY))
+ ADD_TRAIT(source, TRAIT_BATON_RESISTANCE, type)
+ return
+
+ REMOVE_TRAIT(source, TRAIT_BATON_RESISTANCE, type)
+
+/**
+ * Signal proc for [COMSIG_LIVING_LIFE].
+ *
+ * Gradually heals the heretic ([source]) on rust,
+ * including baton knockdown and stamina damage.
+ */
+/datum/element/leeching_walk/proc/on_life(mob/living/source, seconds_per_tick, times_fired)
+ SIGNAL_HANDLER
+
+ var/turf/our_turf = get_turf(source)
+ if(!HAS_TRAIT(our_turf, TRAIT_RUSTY))
+ return
+
+ // Heals all damage + Stamina
+ var/need_mob_update = FALSE
+ need_mob_update += source.adjustBruteLoss(-3, updating_health = FALSE)
+ need_mob_update += source.adjustFireLoss(-3, updating_health = FALSE)
+ need_mob_update += source.adjustToxLoss(-3, updating_health = FALSE, forced = TRUE) // Slimes are people to
+ need_mob_update += source.adjustOxyLoss(-1.5, updating_health = FALSE)
+ need_mob_update += source.adjustStaminaLoss(-10, updating_stamina = FALSE)
+ if(need_mob_update)
+ source.updatehealth()
+ // Reduces duration of stuns/etc
+ source.AdjustAllImmobility(-0.5 SECONDS)
+ // Heals blood loss
+ if(source.blood_volume < BLOOD_VOLUME_NORMAL)
+ source.blood_volume += 2.5 * seconds_per_tick
diff --git a/code/datums/elements/wall_walker.dm b/code/datums/elements/wall_walker.dm
index 92ac3318c1287..abea9db3af8da 100644
--- a/code/datums/elements/wall_walker.dm
+++ b/code/datums/elements/wall_walker.dm
@@ -4,16 +4,20 @@
argument_hash_start_idx = 2
/// What kind of walls can we pass through?
var/wall_type
+ /// What trait on turfs allows us to pass through? Can be used as OR if wall_type is null, or AND if it's set.
+ var/or_trait
/datum/element/wall_walker/Attach(
datum/target,
wall_type = /turf/closed/wall,
+ or_trait,
)
. = ..()
if (!isliving(target))
return ELEMENT_INCOMPATIBLE
src.wall_type = wall_type
+ src.or_trait = or_trait
RegisterSignal(target, COMSIG_LIVING_WALL_BUMP, PROC_REF(try_pass_wall))
RegisterSignal(target, COMSIG_LIVING_WALL_EXITED, PROC_REF(exit_wall))
@@ -23,7 +27,10 @@
/// If the wall is of the proper type, pass into it and keep hold on whatever you're pulling
/datum/element/wall_walker/proc/try_pass_wall(mob/living/passing_mob, turf/closed/bumped_wall)
- if(!istype(bumped_wall, wall_type))
+ if(wall_type && !istype(bumped_wall, wall_type))
+ return
+
+ if(or_trait && !HAS_TRAIT(bumped_wall, or_trait))
return
var/atom/movable/stored_pulling = passing_mob.pulling
diff --git a/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm b/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
index 69e78ec74b31e..a3866971aae5f 100644
--- a/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
+++ b/code/datums/greyscale/config_types/greyscale_configs/greyscale_items.dm
@@ -255,7 +255,7 @@
/datum/greyscale_config/vape
name = "Vape"
- icon_file = 'icons/obj/clothing/masks.dmi'
+ icon_file = 'icons/obj/cigarettes.dmi'
json_config = 'code/datums/greyscale/json_configs/vape.json'
/datum/greyscale_config/vape/worn
diff --git a/code/datums/looping_sounds/machinery_sounds.dm b/code/datums/looping_sounds/machinery_sounds.dm
index 2ed95232df19a..2d5e3564e6d09 100644
--- a/code/datums/looping_sounds/machinery_sounds.dm
+++ b/code/datums/looping_sounds/machinery_sounds.dm
@@ -79,6 +79,15 @@
end_sound = 'sound/machines/microwave/microwave-end.ogg'
volume = 90
+/datum/looping_sound/lathe_print
+ mid_sounds = list('sound/machines/lathe/lathe_print.ogg' = 1)
+ mid_length = 20
+ volume = 50
+ vary = TRUE
+ ignore_walls = FALSE
+ falloff_distance = 1
+ mid_length_vary = 10
+
/datum/looping_sound/jackpot
mid_length = 11
mid_sounds = list('sound/machines/roulettejackpot.ogg' = 1)
diff --git a/code/datums/quirks/negative_quirks/addict.dm b/code/datums/quirks/negative_quirks/addict.dm
index f97dae32c260f..767d9283baef0 100644
--- a/code/datums/quirks/negative_quirks/addict.dm
+++ b/code/datums/quirks/negative_quirks/addict.dm
@@ -123,7 +123,7 @@
/obj/effect/spawner/random/entertainment/cigarette_pack,
/obj/effect/spawner/random/entertainment/cigar,
/obj/effect/spawner/random/entertainment/lighter,
- /obj/item/clothing/mask/cigarette/pipe,
+ /obj/item/cigarette/pipe,
)
/datum/quirk_constant_data/smoker
@@ -162,7 +162,7 @@
. = ..()
var/mob/living/carbon/human/human_holder = quirk_holder
var/obj/item/mask_item = human_holder.get_item_by_slot(ITEM_SLOT_MASK)
- if(istype(mask_item, /obj/item/clothing/mask/cigarette))
+ if(istype(mask_item, /obj/item/cigarette))
var/obj/item/storage/fancy/cigarettes/cigarettes = drug_container_type
if(istype(mask_item, initial(cigarettes.spawn_type)))
quirk_holder.clear_mood_event("wrong_cigs")
diff --git a/code/datums/shuttles/whiteship.dm b/code/datums/shuttles/whiteship.dm
index 0b48575e057c2..b8dbcfd4bd76e 100644
--- a/code/datums/shuttles/whiteship.dm
+++ b/code/datums/shuttles/whiteship.dm
@@ -24,7 +24,7 @@
/datum/map_template/shuttle/whiteship/birdshot
suffix = "birdshot"
name = "NT Patrol Bee"
- description = "A small patrol vessel with a central corridor connecting all rooms. Features 2 small cargo bays and a brig. Spawns with an agressive and deadly Gelatinous Cube"
+ description = "A small patrol vessel with a central corridor connecting all rooms. Features 2 small cargo bays and a brig. Spawns with an aggressive and deadly Gelatinous Cube"
/datum/map_template/shuttle/whiteship/kilo
suffix = "kilo"
diff --git a/code/datums/storage/subtypes/pockets.dm b/code/datums/storage/subtypes/pockets.dm
index d441c6fdc5ff6..edf3816c274ee 100644
--- a/code/datums/storage/subtypes/pockets.dm
+++ b/code/datums/storage/subtypes/pockets.dm
@@ -108,7 +108,7 @@
/obj/item/ammo_box/magazine/toy/pistol,
/obj/item/ammo_casing,
/obj/item/lipstick,
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
/obj/item/lighter,
/obj/item/match,
/obj/item/holochip,
@@ -116,7 +116,7 @@
/obj/item/reagent_containers/cup/glass/flask),
list(/obj/item/screwdriver/power,
/obj/item/ammo_casing/rocket,
- /obj/item/clothing/mask/cigarette/pipe,
+ /obj/item/cigarette/pipe,
/obj/item/toy/crayon/spraycan)
)
@@ -134,7 +134,7 @@
/obj/item/ammo_box/magazine/m9mm,
/obj/item/ammo_casing,
/obj/item/bikehorn,
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
/obj/item/dnainjector,
/obj/item/firing_pin,
/obj/item/holochip,
@@ -158,7 +158,7 @@
),
cant_hold_list = list(
/obj/item/ammo_casing/rocket,
- /obj/item/clothing/mask/cigarette/pipe,
+ /obj/item/cigarette/pipe,
/obj/item/screwdriver/power,
/obj/item/toy/crayon/spraycan,
),
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 52fc8ac068ab9..d1025b52b321f 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -29,8 +29,11 @@
var/datum/component/material_container/materials
///direction we output onto (if 0, on top of us)
var/drop_direction = 0
+ //looping sound for printing items
+ var/datum/looping_sound/lathe_print/print_sound
/obj/machinery/autolathe/Initialize(mapload)
+ print_sound = new(src, FALSE)
materials = AddComponent( \
/datum/component/material_container, \
SSmaterials.materials_by_category[MAT_CATEGORY_ITEM_MATERIAL], \
@@ -48,6 +51,7 @@
register_context()
/obj/machinery/autolathe/Destroy()
+ QDEL_NULL(print_sound)
materials = null
QDEL_NULL(wires)
return ..()
@@ -290,6 +294,8 @@
busy = TRUE
icon_state = "autolathe_n"
SStgui.update_uis(src)
+ // play this after all checks passed individually for each item.
+ print_sound.start()
var/turf/target_location
if(drop_direction)
target_location = get_step(src, drop_direction)
@@ -387,7 +393,7 @@
*/
/obj/machinery/autolathe/proc/finalize_build()
PROTECTED_PROC(TRUE)
-
+ print_sound.stop()
icon_state = initial(icon_state)
busy = FALSE
SStgui.update_uis(src)
diff --git a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
index de2f3d82275b2..c8cfa12f9abfe 100644
--- a/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
+++ b/code/game/machinery/computer/orders/order_items/mining/order_consumables.dm
@@ -31,11 +31,11 @@
cost_per_order = 100
/datum/orderable_item/consumables/havana_cigars
- item_path = /obj/item/clothing/mask/cigarette/cigar/havana
+ item_path = /obj/item/cigarette/cigar/havana
cost_per_order = 150
/datum/orderable_item/consumables/havana_cigars
- item_path = /obj/item/clothing/mask/cigarette/cigar/havana
+ item_path = /obj/item/cigarette/cigar/havana
cost_per_order = 150
/datum/orderable_item/consumables/tracking_implants
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index c69c865f6d122..4c1d4ad2d5154 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -317,6 +317,13 @@
/obj/machinery/door/window/narsie_act()
add_atom_colour(NARSIE_WINDOW_COLOUR, FIXED_COLOUR_PRIORITY)
+/obj/machinery/door/window/rust_heretic_act()
+ add_atom_colour(COLOR_RUSTED_GLASS, FIXED_COLOUR_PRIORITY)
+ AddElement(/datum/element/rust)
+ set_armor(/datum/armor/none)
+ take_damage(get_integrity() * 0.5)
+ modify_max_integrity(max_integrity * 0.5)
+
/obj/machinery/door/window/should_atmos_process(datum/gas_mixture/air, exposed_temperature)
return (exposed_temperature > T0C + (reinf ? 1600 : 800))
diff --git a/code/game/objects/effects/decals/cleanable.dm b/code/game/objects/effects/decals/cleanable.dm
index b0af5c3ca029e..21eff5028b57e 100644
--- a/code/game/objects/effects/decals/cleanable.dm
+++ b/code/game/objects/effects/decals/cleanable.dm
@@ -84,7 +84,7 @@
qdel(src)
return
if(W.get_temperature()) //todo: make heating a reagent holder proc
- if(istype(W, /obj/item/clothing/mask/cigarette))
+ if(istype(W, /obj/item/cigarette))
return
else
var/hotness = W.get_temperature()
diff --git a/code/game/objects/effects/decals/cleanable/humans.dm b/code/game/objects/effects/decals/cleanable/humans.dm
index c95bffdc62676..0f4c9dee3127f 100644
--- a/code/game/objects/effects/decals/cleanable/humans.dm
+++ b/code/game/objects/effects/decals/cleanable/humans.dm
@@ -97,6 +97,15 @@
/obj/effect/decal/cleanable/trail_holder/can_bloodcrawl_in()
return TRUE
+// normal version of the above trail holder object for use in less convoluted things
+/obj/effect/decal/cleanable/blood/trails
+ desc = "Looks like a corpse was smeared all over the floor like ketchup. Kinda makes you hungry."
+ random_icon_states = list("trails_1", "trails_2")
+ icon_state = "trails_1"
+ beauty = -50
+ dryname = "dried tracks"
+ drydesc = "Looks like a corpse was smeared all over the floor like ketchup, but it's all dried up and nasty now, ew. You lose some of your appetite."
+
/obj/effect/decal/cleanable/blood/gibs
name = "gibs"
desc = "They look bloody and gruesome."
diff --git a/code/game/objects/effects/spawners/costume.dm b/code/game/objects/effects/spawners/costume.dm
index 6eb3f801f7365..e5280f7e66184 100644
--- a/code/game/objects/effects/spawners/costume.dm
+++ b/code/game/objects/effects/spawners/costume.dm
@@ -40,7 +40,7 @@
items = list(
/obj/item/clothing/under/rank/captain/suit,
/obj/item/clothing/head/flatcap,
- /obj/item/clothing/mask/cigarette/cigar/havana,
+ /obj/item/cigarette/cigar/havana,
/obj/item/clothing/shoes/jackboots,
)
diff --git a/code/game/objects/effects/spawners/random/entertainment.dm b/code/game/objects/effects/spawners/random/entertainment.dm
index 3ad477b0294f3..74ca4213b0dc5 100644
--- a/code/game/objects/effects/spawners/random/entertainment.dm
+++ b/code/game/objects/effects/spawners/random/entertainment.dm
@@ -121,10 +121,10 @@
icon_state = "pill"
loot = list(
/obj/item/reagent_containers/cup/glass/bottle/hooch = 50,
- /obj/item/clothing/mask/cigarette/rollie/cannabis = 15,
+ /obj/item/cigarette/rollie/cannabis = 15,
/obj/item/reagent_containers/syringe = 15,
/obj/item/cigbutt/roach = 15,
- /obj/item/clothing/mask/cigarette/rollie/mindbreaker = 5,
+ /obj/item/cigarette/rollie/mindbreaker = 5,
)
/obj/effect/spawner/random/entertainment/dice
@@ -157,23 +157,23 @@
name = "cigarette spawner"
icon_state = "cigarettes"
loot = list(
- /obj/item/clothing/mask/cigarette/space_cigarette = 3,
- /obj/item/clothing/mask/cigarette/rollie/cannabis = 3,
- /obj/item/clothing/mask/cigarette/rollie/nicotine = 3,
- /obj/item/clothing/mask/cigarette/dromedary = 2,
- /obj/item/clothing/mask/cigarette/uplift = 2,
- /obj/item/clothing/mask/cigarette/robust = 2,
- /obj/item/clothing/mask/cigarette/carp = 1,
- /obj/item/clothing/mask/cigarette/robustgold = 1,
+ /obj/item/cigarette/space_cigarette = 3,
+ /obj/item/cigarette/rollie/cannabis = 3,
+ /obj/item/cigarette/rollie/nicotine = 3,
+ /obj/item/cigarette/dromedary = 2,
+ /obj/item/cigarette/uplift = 2,
+ /obj/item/cigarette/robust = 2,
+ /obj/item/cigarette/carp = 1,
+ /obj/item/cigarette/robustgold = 1,
)
/obj/effect/spawner/random/entertainment/cigar
name = "cigar spawner"
icon_state = "cigarettes"
loot = list(
- /obj/item/clothing/mask/cigarette/cigar = 3,
- /obj/item/clothing/mask/cigarette/cigar/havana = 2,
- /obj/item/clothing/mask/cigarette/cigar/cohiba = 1,
+ /obj/item/cigarette/cigar = 3,
+ /obj/item/cigarette/cigar/havana = 2,
+ /obj/item/cigarette/cigar/cohiba = 1,
)
/obj/effect/spawner/random/entertainment/wallet_lighter
diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm
index 7c0ebfda5f4a8..27647feb924f9 100644
--- a/code/game/objects/items/cigs_lighters.dm
+++ b/code/game/objects/items/cigs_lighters.dm
@@ -94,7 +94,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
user.log_message("set [key_name(M)] on fire with [src]", LOG_ATTACK)
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ var/obj/item/cigarette/cig = help_light_cig(M)
if(!lit || !cig || user.combat_mode)
..()
return
@@ -109,7 +109,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/// Finds a cigarette on another mob to help light.
/obj/item/proc/help_light_cig(mob/living/M)
var/mask_item = M.get_item_by_slot(ITEM_SLOT_MASK)
- if(istype(mask_item, /obj/item/clothing/mask/cigarette))
+ if(istype(mask_item, /obj/item/cigarette))
return mask_item
/obj/item/match/get_temperature()
@@ -129,14 +129,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM
//////////////////
//FINE SMOKABLES//
//////////////////
-/obj/item/clothing/mask/cigarette
+/obj/item/cigarette
name = "cigarette"
desc = "A roll of tobacco and nicotine."
+ icon = 'icons/obj/cigarettes.dmi'
icon_state = "cigoff"
inhand_icon_state = "cigon" //gets overriden during intialize(), just have it for unit test sanity.
throw_speed = 0.5
w_class = WEIGHT_CLASS_TINY
- body_parts_covered = null
+ slot_flags = ITEM_SLOT_MASK
grind_results = list()
heat = 1000
throw_verb = "flick"
@@ -180,7 +181,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/// How long the current mob has been smoking this cigarette
VAR_FINAL/how_long_have_we_been_smokin = 0 SECONDS
-/obj/item/clothing/mask/cigarette/Initialize(mapload)
+/obj/item/cigarette/Initialize(mapload)
. = ..()
create_reagents(chem_volume, INJECTABLE | NO_REACT)
if(list_reagents)
@@ -193,24 +194,23 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = icon_off
inhand_icon_state = inhand_icon_off
-/obj/item/clothing/mask/cigarette/Destroy()
+/obj/item/cigarette/Destroy()
STOP_PROCESSING(SSobj, src)
QDEL_NULL(mob_smoke)
QDEL_NULL(cig_smoke)
return ..()
-/obj/item/clothing/mask/cigarette/equipped(mob/equipee, slot)
+/obj/item/cigarette/equipped(mob/equipee, slot)
. = ..()
if(!(slot & ITEM_SLOT_MASK))
UnregisterSignal(equipee, list(COMSIG_HUMAN_FORCESAY, COMSIG_ATOM_DIR_CHANGE))
return
RegisterSignal(equipee, COMSIG_HUMAN_FORCESAY, PROC_REF(on_forcesay))
RegisterSignal(equipee, COMSIG_ATOM_DIR_CHANGE, PROC_REF(on_mob_dir_change))
-
if(lit && iscarbon(loc))
make_mob_smoke(loc)
-/obj/item/clothing/mask/cigarette/dropped(mob/dropee, silent)
+/obj/item/cigarette/dropped(mob/dropee)
. = ..()
// Moving the cigarette from mask to hands (or pocket I guess) will emit a larger puff of smoke
if(!QDELETED(src) && !QDELETED(dropee) && how_long_have_we_been_smokin >= 4 SECONDS && iscarbon(dropee) && iscarbon(loc))
@@ -223,17 +223,17 @@ CIGARETTE PACKETS ARE IN FANCY.DM
QDEL_NULL(mob_smoke)
how_long_have_we_been_smokin = 0 SECONDS
-/obj/item/clothing/mask/cigarette/proc/on_forcesay(mob/living/source)
+/obj/item/cigarette/proc/on_forcesay(mob/living/source)
SIGNAL_HANDLER
source.apply_status_effect(/datum/status_effect/choke, src, lit, choke_forever ? -1 : rand(25 SECONDS, choke_time_max))
-/obj/item/clothing/mask/cigarette/proc/on_mob_dir_change(mob/living/source, old_dir, new_dir)
+/obj/item/cigarette/proc/on_mob_dir_change(mob/living/source, old_dir, new_dir)
SIGNAL_HANDLER
if(isnull(mob_smoke))
return
update_particle_position(mob_smoke, new_dir)
-/obj/item/clothing/mask/cigarette/proc/update_particle_position(obj/effect/abstract/particle_holder/to_edit, new_dir = loc.dir)
+/obj/item/cigarette/proc/update_particle_position(obj/effect/abstract/particle_holder/to_edit, new_dir = loc.dir)
var/new_x = 0
var/new_layer = initial(to_edit.layer)
if(new_dir & NORTH)
@@ -248,11 +248,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_edit.set_particle_position(new_x, 8, 0)
to_edit.layer = new_layer
-/obj/item/clothing/mask/cigarette/suicide_act(mob/living/user)
+/obj/item/cigarette/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is huffing [src] as quickly as [user.p_they()] can! It looks like [user.p_theyre()] trying to give [user.p_them()]self cancer."))
return (TOXLOSS|OXYLOSS)
-/obj/item/clothing/mask/cigarette/attackby(obj/item/W, mob/user, params)
+/obj/item/cigarette/attackby(obj/item/W, mob/user, params)
if(lit)
return ..()
@@ -270,7 +270,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, span_warning("There is nothing to smoke!"))
/// Checks that we have enough air to smoke
-/obj/item/clothing/mask/cigarette/proc/check_oxygen(mob/user)
+/obj/item/cigarette/proc/check_oxygen(mob/user)
if (reagents.has_reagent(/datum/reagent/oxygen))
return TRUE
var/datum/gas_mixture/air = return_air()
@@ -281,7 +281,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/mob/living/carbon/the_smoker = user
return the_smoker.can_breathe_helmet()
-/obj/item/clothing/mask/cigarette/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
+/obj/item/cigarette/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(lit) //can't dip if cigarette is lit (it will heat the reagents in the glass instead)
return NONE
var/obj/item/reagent_containers/cup/glass = interacting_with
@@ -298,7 +298,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
to_chat(user, span_warning("[src] is full!"))
return ITEM_INTERACT_SUCCESS
-/obj/item/clothing/mask/cigarette/update_icon_state()
+/obj/item/cigarette/update_icon_state()
. = ..()
if(lit)
icon_state = icon_on
@@ -308,7 +308,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
inhand_icon_state = inhand_icon_off
-/obj/item/clothing/mask/cigarette/proc/sparks_touched(datum/source, obj/effect/particle_effect)
+/obj/item/cigarette/proc/sparks_touched(datum/source, obj/effect/particle_effect)
SIGNAL_HANDLER
if(lit)
@@ -316,7 +316,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
light()
/// Lights the cigarette with given flavor text.
-/obj/item/clothing/mask/cigarette/proc/light(flavor_text = null)
+/obj/item/cigarette/proc/light(flavor_text = null)
if(lit)
return
@@ -357,7 +357,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(src == smoker.wear_mask)
make_mob_smoke(smoker)
-/obj/item/clothing/mask/cigarette/extinguish()
+/obj/item/cigarette/extinguish()
. = ..()
if(!lit)
return
@@ -375,7 +375,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
QDEL_NULL(cig_smoke)
QDEL_NULL(mob_smoke)
-/obj/item/clothing/mask/cigarette/proc/long_exhale(mob/living/carbon/smoker)
+/obj/item/cigarette/proc/long_exhale(mob/living/carbon/smoker)
smoker.visible_message(
span_notice("[smoker] exhales a large cloud of smoke from [src]."),
span_notice("You exhale a large cloud of smoke from [src]."),
@@ -388,7 +388,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
QDEL_IN(big_smoke, big_smoke.particles.lifespan)
/// Handles processing the reagents in the cigarette.
-/obj/item/clothing/mask/cigarette/proc/handle_reagents(seconds_per_tick)
+/obj/item/cigarette/proc/handle_reagents(seconds_per_tick)
if(!reagents.total_volume)
return
reagents.expose_temperature(heat, 0.05)
@@ -424,7 +424,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(!reagents.trans_to(smoker, to_smoke, methods = INGEST, ignore_stomach = TRUE))
reagents.remove_all(to_smoke)
-/obj/item/clothing/mask/cigarette/process(seconds_per_tick)
+/obj/item/cigarette/process(seconds_per_tick)
var/mob/living/user = isliving(loc) ? loc : null
user?.ignite_mob()
@@ -442,12 +442,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
COOLDOWN_START(src, drag_cooldown, dragtime)
handle_reagents(seconds_per_tick)
-/obj/item/clothing/mask/cigarette/attack_self(mob/user)
+/obj/item/cigarette/attack_self(mob/user)
if(lit)
put_out(user, TRUE)
return ..()
-/obj/item/clothing/mask/cigarette/proc/put_out(mob/user, done_early = FALSE)
+/obj/item/cigarette/proc/put_out(mob/user, done_early = FALSE)
var/atom/location = drop_location()
if(!isnull(user))
if(done_early)
@@ -463,13 +463,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM
new type_butt(location)
qdel(src)
-/obj/item/clothing/mask/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
+/obj/item/cigarette/attack(mob/living/carbon/M, mob/living/carbon/user)
if(!istype(M))
return ..()
if(M.on_fire && !lit)
light(span_notice("[user] lights [src] with [M]'s burning body. What a cold-blooded badass."))
return
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ var/obj/item/cigarette/cig = help_light_cig(M)
if(!lit || !cig || user.combat_mode)
return ..()
@@ -480,54 +480,54 @@ CIGARETTE PACKETS ARE IN FANCY.DM
else
cig.light(span_notice("[user] holds the [name] out for [M], and lights [M.p_their()] [cig.name]."))
-/obj/item/clothing/mask/cigarette/fire_act(exposed_temperature, exposed_volume)
+/obj/item/cigarette/fire_act(exposed_temperature, exposed_volume)
light()
-/obj/item/clothing/mask/cigarette/get_temperature()
+/obj/item/cigarette/get_temperature()
return lit * heat
-/obj/item/clothing/mask/cigarette/proc/make_mob_smoke(mob/living/smoker)
+/obj/item/cigarette/proc/make_mob_smoke(mob/living/smoker)
mob_smoke = new(smoker, /particles/smoke/cig)
update_particle_position(mob_smoke, smoker.dir)
return mob_smoke
-/obj/item/clothing/mask/cigarette/proc/make_cig_smoke()
+/obj/item/cigarette/proc/make_cig_smoke()
cig_smoke = new(src, /particles/smoke/cig)
cig_smoke.particles.scale *= 1.5
return cig_smoke
// Cigarette brands.
-/obj/item/clothing/mask/cigarette/space_cigarette
+/obj/item/cigarette/space_cigarette
desc = "A Space brand cigarette that can be smoked anywhere."
list_reagents = list(/datum/reagent/drug/nicotine = 9, /datum/reagent/oxygen = 9)
smoketime = 4 MINUTES // space cigs have a shorter burn time than normal cigs
smoke_all = TRUE // so that it doesn't runout of oxygen while being smoked in space
-/obj/item/clothing/mask/cigarette/dromedary
+/obj/item/cigarette/dromedary
desc = "A DromedaryCo brand cigarette. Contrary to popular belief, does not contain Calomel, but is reported to have a watery taste."
list_reagents = list(/datum/reagent/drug/nicotine = 13, /datum/reagent/water = 5) //camel has water
-/obj/item/clothing/mask/cigarette/uplift
+/obj/item/cigarette/uplift
desc = "An Uplift Smooth brand cigarette. Smells refreshing."
list_reagents = list(/datum/reagent/drug/nicotine = 13, /datum/reagent/consumable/menthol = 5)
-/obj/item/clothing/mask/cigarette/robust
+/obj/item/cigarette/robust
desc = "A Robust brand cigarette."
-/obj/item/clothing/mask/cigarette/robustgold
+/obj/item/cigarette/robustgold
desc = "A Robust Gold brand cigarette."
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/gold = 3) // Just enough to taste a hint of expensive metal.
-/obj/item/clothing/mask/cigarette/carp
+/obj/item/cigarette/carp
desc = "A Carp Classic brand cigarette. A small label on its side indicates that it does NOT contain carpotoxin."
-/obj/item/clothing/mask/cigarette/carp/Initialize(mapload)
+/obj/item/cigarette/carp/Initialize(mapload)
. = ..()
if(!prob(5))
return
reagents?.add_reagent(/datum/reagent/toxin/carpotoxin , 3) // They lied
-/obj/item/clothing/mask/cigarette/syndicate
+/obj/item/cigarette/syndicate
desc = "An unknown brand cigarette."
chem_volume = 60
smoketime = 2 MINUTES
@@ -535,19 +535,19 @@ CIGARETTE PACKETS ARE IN FANCY.DM
lung_harm = 1.5
list_reagents = list(/datum/reagent/drug/nicotine = 10, /datum/reagent/medicine/omnizine = 15)
-/obj/item/clothing/mask/cigarette/shadyjims
+/obj/item/cigarette/shadyjims
desc = "A Shady Jim's Super Slims cigarette."
lung_harm = 1.5
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/toxin/lipolicide = 4, /datum/reagent/ammonia = 2, /datum/reagent/toxin/plantbgone = 1, /datum/reagent/toxin = 1.5)
-/obj/item/clothing/mask/cigarette/xeno
+/obj/item/cigarette/xeno
desc = "A Xeno Filtered brand cigarette."
lung_harm = 2
list_reagents = list (/datum/reagent/drug/nicotine = 20, /datum/reagent/medicine/regen_jelly = 15, /datum/reagent/drug/krokodil = 4)
// Rollies.
-/obj/item/clothing/mask/cigarette/rollie
+/obj/item/cigarette/rollie
name = "rollie"
desc = "A roll of dried plant matter wrapped in thin paper."
icon_state = "spliffoff"
@@ -560,7 +560,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
list_reagents = null
choke_time_max = 40 SECONDS
-/obj/item/clothing/mask/cigarette/rollie/Initialize(mapload)
+/obj/item/cigarette/rollie/Initialize(mapload)
name = pick(list(
"bifta",
"bifter",
@@ -606,20 +606,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM
pixel_x = rand(-5, 5)
pixel_y = rand(-5, 5)
-/obj/item/clothing/mask/cigarette/rollie/nicotine
+/obj/item/cigarette/rollie/nicotine
list_reagents = list(/datum/reagent/drug/nicotine = 15)
-/obj/item/clothing/mask/cigarette/rollie/trippy
+/obj/item/cigarette/rollie/trippy
list_reagents = list(/datum/reagent/drug/nicotine = 15, /datum/reagent/drug/mushroomhallucinogen = 35)
starts_lit = TRUE
-/obj/item/clothing/mask/cigarette/rollie/cannabis
+/obj/item/cigarette/rollie/cannabis
list_reagents = list(/datum/reagent/drug/cannabis = 15)
-/obj/item/clothing/mask/cigarette/rollie/mindbreaker
+/obj/item/cigarette/rollie/mindbreaker
list_reagents = list(/datum/reagent/toxin/mindbreaker = 35, /datum/reagent/toxin/lipolicide = 15)
-/obj/item/clothing/mask/cigarette/candy
+/obj/item/cigarette/candy
name = "\improper Little Timmy's candy cigarette"
desc = "For all ages*! Doesn't contain any amount of nicotine. Health and safety risks can be read on the tip of the cigarette."
smoketime = 2 MINUTES
@@ -633,7 +633,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
list_reagents = list(/datum/reagent/consumable/sugar = 20)
choke_time_max = 70 SECONDS // This shit really is deadly
-/obj/item/clothing/mask/cigarette/candy/nicotine
+/obj/item/cigarette/candy/nicotine
desc = "For all ages*! Doesn't contain any* amount of nicotine. Health and safety risks can be read on the tip of the cigarette."
type_butt = /obj/item/food/candy_trash/nicotine
list_reagents = list(/datum/reagent/consumable/sugar = 20, /datum/reagent/drug/nicotine = 20) //oh no!
@@ -653,7 +653,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
////////////
// CIGARS //
////////////
-/obj/item/clothing/mask/cigarette/cigar
+/obj/item/cigarette/cigar
name = "cigar"
desc = "A brown roll of tobacco and... well, you're not quite sure. This thing's huge!"
icon_state = "cigaroff"
@@ -669,11 +669,11 @@ CIGARETTE PACKETS ARE IN FANCY.DM
list_reagents = list(/datum/reagent/drug/nicotine = 25)
choke_time_max = 40 SECONDS
-/obj/item/clothing/mask/cigarette/cigar/premium
+/obj/item/cigarette/cigar/premium
name = "premium cigar"
//this is the version that actually spawns in premium cigar cases, the distinction is made so that the smoker quirk can differentiate between the default cigar box and its subtypes
-/obj/item/clothing/mask/cigarette/cigar/cohiba
+/obj/item/cigarette/cigar/cohiba
name = "\improper Cohiba Robusto cigar"
desc = "There's little more you could want from a cigar."
icon_state = "cigar2off"
@@ -683,7 +683,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
chem_volume = 80
list_reagents = list(/datum/reagent/drug/nicotine = 40)
-/obj/item/clothing/mask/cigarette/cigar/havana
+/obj/item/cigarette/cigar/havana
name = "premium Havanian cigar"
desc = "A cigar fit for only the best of the best."
icon_state = "cigar2off"
@@ -696,7 +696,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/cigbutt
name = "cigarette butt"
desc = "A manky old cigarette butt."
- icon = 'icons/obj/clothing/masks.dmi'
+ icon = 'icons/obj/cigarettes.dmi'
icon_state = "cigbutt"
w_class = WEIGHT_CLASS_TINY
throwforce = 0
@@ -710,7 +710,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/////////////////
//SMOKING PIPES//
/////////////////
-/obj/item/clothing/mask/cigarette/pipe
+/obj/item/cigarette/pipe
name = "smoking pipe"
desc = "A pipe, for smoking. Probably made of meerschaum or something."
icon_state = "pipeoff"
@@ -727,15 +727,15 @@ CIGARETTE PACKETS ARE IN FANCY.DM
///name of the stuff packed inside this pipe
var/packeditem
-/obj/item/clothing/mask/cigarette/pipe/Initialize(mapload)
+/obj/item/cigarette/pipe/Initialize(mapload)
. = ..()
update_appearance(UPDATE_NAME)
-/obj/item/clothing/mask/cigarette/pipe/update_name()
+/obj/item/cigarette/pipe/update_name()
. = ..()
name = packeditem ? "[packeditem]-packed [initial(name)]" : "empty [initial(name)]"
-/obj/item/clothing/mask/cigarette/pipe/put_out(mob/user, done_early = FALSE)
+/obj/item/cigarette/pipe/put_out(mob/user, done_early = FALSE)
lit = FALSE
if(done_early)
user.visible_message(span_notice("[user] puts out [src]."), span_notice("You put out [src]."))
@@ -748,7 +748,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
STOP_PROCESSING(SSobj, src)
QDEL_NULL(cig_smoke)
-/obj/item/clothing/mask/cigarette/pipe/attackby(obj/item/thing, mob/user, params)
+/obj/item/cigarette/pipe/attackby(obj/item/thing, mob/user, params)
if(!istype(thing, /obj/item/food/grown))
return ..()
@@ -769,7 +769,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
qdel(to_smoke)
-/obj/item/clothing/mask/cigarette/pipe/attack_self(mob/user)
+/obj/item/cigarette/pipe/attack_self(mob/user)
var/atom/location = drop_location()
if(packeditem && !lit)
to_chat(user, span_notice("You empty [src] onto [location]."))
@@ -781,7 +781,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
return
return ..()
-/obj/item/clothing/mask/cigarette/pipe/cobpipe
+/obj/item/cigarette/pipe/cobpipe
name = "corn cob pipe"
desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects."
icon_state = "cobpipeoff"
@@ -962,7 +962,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(lit && M.ignite_mob())
message_admins("[ADMIN_LOOKUPFLW(user)] set [key_name_admin(M)] on fire with [src] at [AREACOORD(user)]")
log_game("[key_name(user)] set [key_name(M)] on fire with [src] at [AREACOORD(user)]")
- var/obj/item/clothing/mask/cigarette/cig = help_light_cig(M)
+ var/obj/item/cigarette/cig = help_light_cig(M)
if(!lit || !cig || user.combat_mode)
..()
return
@@ -1110,13 +1110,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/obj/item/rollingpaper/Initialize(mapload)
. = ..()
- AddComponent(/datum/component/customizable_reagent_holder, /obj/item/clothing/mask/cigarette/rollie, CUSTOM_INGREDIENT_ICON_NOCHANGE, ingredient_type=CUSTOM_INGREDIENT_TYPE_DRYABLE, max_ingredients=2)
+ AddComponent(/datum/component/customizable_reagent_holder, /obj/item/cigarette/rollie, CUSTOM_INGREDIENT_ICON_NOCHANGE, ingredient_type=CUSTOM_INGREDIENT_TYPE_DRYABLE, max_ingredients=2)
///////////////
//VAPE NATION//
///////////////
-/obj/item/clothing/mask/vape
+/obj/item/vape
name = "\improper E-Cigarette"
desc = "A classy and highly sophisticated electronic cigarette, for classy and dignified gentlemen. A warning label reads \"Warning: Do not fill with flammable materials.\""//<<< i'd vape to that.
icon_state = "vape"
@@ -1126,6 +1126,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
greyscale_colors = "#2e2e2e"
inhand_icon_state = null
w_class = WEIGHT_CLASS_TINY
+ slot_flags = ITEM_SLOT_MASK
flags_1 = IS_PLAYER_COLORABLE_1
/// The capacity of the vape.
@@ -1139,16 +1140,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM
/// Whether the vape has been overloaded to spread smoke.
var/super = FALSE
-/obj/item/clothing/mask/vape/Initialize(mapload)
+/obj/item/vape/Initialize(mapload)
. = ..()
create_reagents(chem_volume, NO_REACT)
reagents.add_reagent(/datum/reagent/drug/nicotine, 50)
-/obj/item/clothing/mask/vape/suicide_act(mob/living/user)
+/obj/item/vape/suicide_act(mob/living/user)
user.visible_message(span_suicide("[user] is puffin hard on dat vape, [user.p_they()] trying to join the vape life on a whole notha plane!"))//it doesn't give you cancer, it is cancer
return (TOXLOSS|OXYLOSS)
-/obj/item/clothing/mask/vape/screwdriver_act(mob/living/user, obj/item/tool)
+/obj/item/vape/screwdriver_act(mob/living/user, obj/item/tool)
if(!screw)
screw = TRUE
to_chat(user, span_notice("You open the cap on [src]."))
@@ -1169,7 +1170,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_state = initial(icon_state)
set_greyscale(new_config = initial(greyscale_config))
-/obj/item/clothing/mask/vape/multitool_act(mob/living/user, obj/item/tool)
+/obj/item/vape/multitool_act(mob/living/user, obj/item/tool)
. = TRUE
if(screw && !(obj_flags & EMAGGED))//also kinky
if(!super)
@@ -1186,7 +1187,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(screw && (obj_flags & EMAGGED))
to_chat(user, span_warning("[src] can't be modified!"))
-/obj/item/clothing/mask/vape/emag_act(mob/user, obj/item/card/emag/emag_card) // I WON'T REGRET WRITTING THIS, SURLY.
+/obj/item/vape/emag_act(mob/user, obj/item/card/emag/emag_card) // I WON'T REGRET WRITTING THIS, SURLY.
if (!screw)
balloon_alert(user, "open the cap first!")
@@ -1206,12 +1207,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
sp.start()
return TRUE
-/obj/item/clothing/mask/vape/attack_self(mob/user)
+/obj/item/vape/attack_self(mob/user)
if(reagents.total_volume > 0)
to_chat(user, span_notice("You empty [src] of all reagents."))
reagents.clear_reagents()
-/obj/item/clothing/mask/vape/equipped(mob/user, slot)
+/obj/item/vape/equipped(mob/user, slot)
. = ..()
if(!(slot & ITEM_SLOT_MASK))
return
@@ -1224,13 +1225,13 @@ CIGARETTE PACKETS ARE IN FANCY.DM
reagents.flags &= ~(NO_REACT)
START_PROCESSING(SSobj, src)
-/obj/item/clothing/mask/vape/dropped(mob/user)
+/obj/item/vape/dropped(mob/user)
. = ..()
if(user.get_item_by_slot(ITEM_SLOT_MASK) == src)
reagents.flags |= NO_REACT
STOP_PROCESSING(SSobj, src)
-/obj/item/clothing/mask/vape/proc/handle_reagents()
+/obj/item/vape/proc/handle_reagents()
if(!reagents.total_volume)
return
@@ -1253,7 +1254,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
if(!reagents.trans_to(vaper, REAGENTS_METABOLISM, methods = INGEST, ignore_stomach = TRUE))
reagents.remove_all(REAGENTS_METABOLISM)
-/obj/item/clothing/mask/vape/process(seconds_per_tick)
+/obj/item/vape/process(seconds_per_tick)
var/mob/living/M = loc
if(isliving(loc))
@@ -1292,34 +1293,34 @@ CIGARETTE PACKETS ARE IN FANCY.DM
handle_reagents()
-/obj/item/clothing/mask/vape/red
+/obj/item/vape/red
greyscale_colors = "#A02525"
flags_1 = NONE
-/obj/item/clothing/mask/vape/blue
+/obj/item/vape/blue
greyscale_colors = "#294A98"
flags_1 = NONE
-/obj/item/clothing/mask/vape/purple
+/obj/item/vape/purple
greyscale_colors = "#9900CC"
flags_1 = NONE
-/obj/item/clothing/mask/vape/green
+/obj/item/vape/green
greyscale_colors = "#3D9829"
flags_1 = NONE
-/obj/item/clothing/mask/vape/yellow
+/obj/item/vape/yellow
greyscale_colors = "#DAC20E"
flags_1 = NONE
-/obj/item/clothing/mask/vape/orange
+/obj/item/vape/orange
greyscale_colors = "#da930e"
flags_1 = NONE
-/obj/item/clothing/mask/vape/black
+/obj/item/vape/black
greyscale_colors = "#2e2e2e"
flags_1 = NONE
-/obj/item/clothing/mask/vape/white
+/obj/item/vape/white
greyscale_colors = "#DCDCDC"
flags_1 = NONE
diff --git a/code/game/objects/items/food/snacks.dm b/code/game/objects/items/food/snacks.dm
index 1c3cb7736cec0..cb64c6df52204 100644
--- a/code/game/objects/items/food/snacks.dm
+++ b/code/game/objects/items/food/snacks.dm
@@ -157,7 +157,7 @@
/obj/item/food/candy_trash
name = "candy cigarette butt"
- icon = 'icons/obj/clothing/masks.dmi'
+ icon = 'icons/obj/cigarettes.dmi'
icon_state = "candybum"
desc = "The leftover from a smoked-out candy cigarette. Can be eaten!"
food_reagents = list(
diff --git a/code/game/objects/items/plushes.dm b/code/game/objects/items/plushes.dm
index c56e1eb7cdc15..35e4c7ff72e9f 100644
--- a/code/game/objects/items/plushes.dm
+++ b/code/game/objects/items/plushes.dm
@@ -676,7 +676,7 @@
)
AddElement(/datum/element/connect_loc, loc_connections)
-/obj/item/toy/plush/goatplushie/attackby(obj/item/clothing/mask/cigarette/rollie/fat_dart, mob/user, params)
+/obj/item/toy/plush/goatplushie/attackby(obj/item/cigarette/rollie/fat_dart, mob/user, params)
if(!istype(fat_dart))
return ..()
if(splat)
diff --git a/code/game/objects/items/rcd/RSF.dm b/code/game/objects/items/rcd/RSF.dm
index b267ecd05cf14..ef0be22acc476 100644
--- a/code/game/objects/items/rcd/RSF.dm
+++ b/code/game/objects/items/rcd/RSF.dm
@@ -45,7 +45,7 @@ RSF
/obj/item/toy/cards/deck = 200,
/obj/item/paper = 10,
/obj/item/pen = 50,
- /obj/item/clothing/mask/cigarette = 10,
+ /obj/item/cigarette = 10,
)
///An associated list of fuel and it's value
var/list/matter_by_item = list(/obj/item/rcd_ammo = 10,)
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 662f94c61d5e1..cc9bc3bcb9659 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -326,7 +326,7 @@ GLOBAL_LIST_INIT(wood_recipes, list ( \
new/datum/stack_recipe("apiary", /obj/structure/beebox, 40, time = 5 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
new/datum/stack_recipe("mannequin", /obj/structure/mannequin/wood, 25, time = 5 SECONDS, crafting_flags = CRAFT_ONE_PER_TURF, category = CAT_ENTERTAINMENT), \
new/datum/stack_recipe("tiki mask", /obj/item/clothing/mask/gas/tiki_mask, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
- new/datum/stack_recipe("smoking pipe", /obj/item/clothing/mask/cigarette/pipe, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
+ new/datum/stack_recipe("smoking pipe", /obj/item/cigarette/pipe, 2, crafting_flags = NONE, category = CAT_CLOTHING), \
new/datum/stack_recipe("honey frame", /obj/item/honey_frame, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
new/datum/stack_recipe("wooden bucket", /obj/item/reagent_containers/cup/bucket/wooden, 3, time = 1 SECONDS, crafting_flags = NONE, category = CAT_CONTAINERS),\
new/datum/stack_recipe("rake", /obj/item/cultivator/rake, 5, time = 1 SECONDS, crafting_flags = NONE, category = CAT_TOOLS),\
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 4258465f3a07e..c748ba4c494a1 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -426,6 +426,7 @@
if(created)
created.setDir(builder.dir)
+ SEND_SIGNAL(created, COMSIG_ATOM_CONSTRUCTED, builder)
on_item_crafted(builder, created)
// Use up the material
diff --git a/code/game/objects/items/storage/bags.dm b/code/game/objects/items/storage/bags.dm
index e363687618988..996cd933647a1 100644
--- a/code/game/objects/items/storage/bags.dm
+++ b/code/game/objects/items/storage/bags.dm
@@ -363,7 +363,7 @@
atom_storage.max_specific_storage = WEIGHT_CLASS_BULKY //Plates are required bulky to keep them out of backpacks
atom_storage.set_holdable(
can_hold_list = list(
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
/obj/item/food,
/obj/item/kitchen,
/obj/item/lighter,
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index 4aa93cc543332..1c5490301a5c0 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -202,7 +202,7 @@
w_class = WEIGHT_CLASS_TINY
throwforce = 0
slot_flags = ITEM_SLOT_BELT
- spawn_type = /obj/item/clothing/mask/cigarette/space_cigarette
+ spawn_type = /obj/item/cigarette/space_cigarette
spawn_count = 6
custom_price = PAYCHECK_CREW
age_restricted = TRUE
@@ -233,18 +233,18 @@
/obj/item/storage/fancy/cigarettes/Initialize(mapload)
. = ..()
atom_storage.display_contents = FALSE
- atom_storage.set_holdable(list(/obj/item/clothing/mask/cigarette, /obj/item/lighter))
+ atom_storage.set_holdable(list(/obj/item/cigarette, /obj/item/lighter))
register_context()
/obj/item/storage/fancy/cigarettes/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
. = ..()
if(interacting_with != user) // you can quickly put a cigarette in your mouth only
return ..()
- quick_remove_item(/obj/item/clothing/mask/cigarette, user, equip_to_mouth = TRUE)
+ quick_remove_item(/obj/item/cigarette, user, equip_to_mouth = TRUE)
/obj/item/storage/fancy/cigarettes/attack_hand_secondary(mob/user, list/modifiers)
. = ..()
- quick_remove_item(/obj/item/clothing/mask/cigarette, user)
+ quick_remove_item(/obj/item/cigarette, user)
return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN
/obj/item/storage/fancy/cigarettes/click_alt(mob/user)
@@ -252,7 +252,7 @@
if(lighter)
quick_remove_item(lighter, user)
else
- quick_remove_item(/obj/item/clothing/mask/cigarette, user)
+ quick_remove_item(/obj/item/cigarette, user)
return CLICK_ACTION_SUCCESS
/// Removes an item or puts it in mouth from the packet, if any
@@ -316,49 +316,49 @@
desc = "A packet of six imported DromedaryCo cancer sticks. A label on the packaging reads, \"Wouldn't a slow death make a change?\""
icon_state = "dromedary"
base_icon_state = "dromedary"
- spawn_type = /obj/item/clothing/mask/cigarette/dromedary
+ spawn_type = /obj/item/cigarette/dromedary
/obj/item/storage/fancy/cigarettes/cigpack_uplift
name = "\improper Uplift Smooth packet"
desc = "Your favorite brand, now menthol flavored."
icon_state = "uplift"
base_icon_state = "uplift"
- spawn_type = /obj/item/clothing/mask/cigarette/uplift
+ spawn_type = /obj/item/cigarette/uplift
/obj/item/storage/fancy/cigarettes/cigpack_robust
name = "\improper Robust packet"
desc = "Smoked by the robust."
icon_state = "robust"
base_icon_state = "robust"
- spawn_type = /obj/item/clothing/mask/cigarette/robust
+ spawn_type = /obj/item/cigarette/robust
/obj/item/storage/fancy/cigarettes/cigpack_robustgold
name = "\improper Robust Gold packet"
desc = "Smoked by the truly robust."
icon_state = "robustg"
base_icon_state = "robustg"
- spawn_type = /obj/item/clothing/mask/cigarette/robustgold
+ spawn_type = /obj/item/cigarette/robustgold
/obj/item/storage/fancy/cigarettes/cigpack_carp
name = "\improper Carp Classic packet"
desc = "Since 2313."
icon_state = "carp"
base_icon_state = "carp"
- spawn_type = /obj/item/clothing/mask/cigarette/carp
+ spawn_type = /obj/item/cigarette/carp
/obj/item/storage/fancy/cigarettes/cigpack_syndicate
name = "cigarette packet"
desc = "An obscure brand of cigarettes."
icon_state = "syndie"
base_icon_state = "syndie"
- spawn_type = /obj/item/clothing/mask/cigarette/syndicate
+ spawn_type = /obj/item/cigarette/syndicate
/obj/item/storage/fancy/cigarettes/cigpack_midori
name = "\improper Midori Tabako packet"
desc = "You can't understand the runes, but the packet smells funny."
icon_state = "midori"
base_icon_state = "midori"
- spawn_type = /obj/item/clothing/mask/cigarette/rollie/nicotine
+ spawn_type = /obj/item/cigarette/rollie/nicotine
/obj/item/storage/fancy/cigarettes/cigpack_candy
name = "\improper Timmy's First Candy Smokes packet"
@@ -366,42 +366,42 @@
icon_state = "candy"
base_icon_state = "candy"
contents_tag = "candy cigarette"
- spawn_type = /obj/item/clothing/mask/cigarette/candy
+ spawn_type = /obj/item/cigarette/candy
candy = TRUE
age_restricted = FALSE
/obj/item/storage/fancy/cigarettes/cigpack_candy/Initialize(mapload)
. = ..()
if(prob(7))
- spawn_type = /obj/item/clothing/mask/cigarette/candy/nicotine //uh oh!
+ spawn_type = /obj/item/cigarette/candy/nicotine //uh oh!
/obj/item/storage/fancy/cigarettes/cigpack_shadyjims
name = "\improper Shady Jim's Super Slims packet"
desc = "Is your weight slowing you down? Having trouble running away from gravitational singularities? Can't stop stuffing your mouth? Smoke Shady Jim's Super Slims and watch all that fat burn away. Guaranteed results!"
icon_state = "shadyjim"
base_icon_state = "shadyjim"
- spawn_type = /obj/item/clothing/mask/cigarette/shadyjims
+ spawn_type = /obj/item/cigarette/shadyjims
/obj/item/storage/fancy/cigarettes/cigpack_xeno
name = "\improper Xeno Filtered packet"
desc = "Loaded with 100% pure slime. And also nicotine."
icon_state = "slime"
base_icon_state = "slime"
- spawn_type = /obj/item/clothing/mask/cigarette/xeno
+ spawn_type = /obj/item/cigarette/xeno
/obj/item/storage/fancy/cigarettes/cigpack_cannabis
name = "\improper Freak Brothers' Special packet"
desc = "A label on the packaging reads, \"Endorsed by Phineas, Freddy and Franklin.\""
icon_state = "midori"
base_icon_state = "midori"
- spawn_type = /obj/item/clothing/mask/cigarette/rollie/cannabis
+ spawn_type = /obj/item/cigarette/rollie/cannabis
/obj/item/storage/fancy/cigarettes/cigpack_mindbreaker
name = "\improper Leary's Delight packet"
desc = "Banned in over 36 galaxies."
icon_state = "shadyjim"
base_icon_state = "shadyjim"
- spawn_type = /obj/item/clothing/mask/cigarette/rollie/mindbreaker
+ spawn_type = /obj/item/cigarette/rollie/mindbreaker
/obj/item/storage/fancy/rollingpapers
name = "rolling paper pack"
@@ -437,14 +437,14 @@
base_icon_state = "cigarcase"
w_class = WEIGHT_CLASS_NORMAL
contents_tag = "premium cigar"
- spawn_type = /obj/item/clothing/mask/cigarette/cigar/premium
+ spawn_type = /obj/item/cigarette/cigar/premium
spawn_count = 5
spawn_coupon = FALSE
display_cigs = FALSE
/obj/item/storage/fancy/cigarettes/cigars/Initialize(mapload)
. = ..()
- atom_storage.set_holdable(/obj/item/clothing/mask/cigarette/cigar)
+ atom_storage.set_holdable(/obj/item/cigarette/cigar)
/obj/item/storage/fancy/cigarettes/cigars/update_icon_state()
. = ..()
@@ -456,7 +456,7 @@
if(!open_status)
return
var/cigar_position = 1 //generate sprites for cigars in the box
- for(var/obj/item/clothing/mask/cigarette/cigar/smokes in contents)
+ for(var/obj/item/cigarette/cigar/smokes in contents)
. += "[smokes.icon_off]_[cigar_position]"
cigar_position++
@@ -465,14 +465,14 @@
desc = "A case of imported Cohiba cigars, renowned for their strong flavor."
icon_state = "cohibacase"
base_icon_state = "cohibacase"
- spawn_type = /obj/item/clothing/mask/cigarette/cigar/cohiba
+ spawn_type = /obj/item/cigarette/cigar/cohiba
/obj/item/storage/fancy/cigarettes/cigars/havana
name = "\improper premium Havanian cigar case"
desc = "A case of classy Havanian cigars."
icon_state = "cohibacase"
base_icon_state = "cohibacase"
- spawn_type = /obj/item/clothing/mask/cigarette/cigar/havana
+ spawn_type = /obj/item/cigarette/cigar/havana
/*
* Heart Shaped Box w/ Chocolates
diff --git a/code/game/objects/items/storage/wallets.dm b/code/game/objects/items/storage/wallets.dm
index 469a14e0e7810..e485d6997f05f 100644
--- a/code/game/objects/items/storage/wallets.dm
+++ b/code/game/objects/items/storage/wallets.dm
@@ -18,7 +18,7 @@
/obj/item/stack/spacecash,
/obj/item/holochip,
/obj/item/card,
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
/obj/item/clothing/accessory/dogtag,
/obj/item/coin,
/obj/item/coupon,
diff --git a/code/game/objects/items/tools/crowbar.dm b/code/game/objects/items/tools/crowbar.dm
index b4185732ce96c..c6b0d52cdc1c3 100644
--- a/code/game/objects/items/tools/crowbar.dm
+++ b/code/game/objects/items/tools/crowbar.dm
@@ -160,8 +160,8 @@
return COMPONENT_NO_DEFAULT_MESSAGE
/obj/item/crowbar/power/syndicate
- name = "Syndicate jaws of life"
- desc = "A pocket sized re-engineered copy of Nanotrasen's standard jaws of life. Can be used to force open airlocks in its crowbar configuration."
+ name = "jaws of death"
+ desc = "An improved, faster, and smaller copy of Nanotrasen's standard jaws of life. Can be used to force open airlocks in its crowbar configuration."
icon_state = "jaws_syndie"
w_class = WEIGHT_CLASS_SMALL
toolspeed = 0.5
diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm
index e8b5ed4c13d43..1783d4b236a63 100644
--- a/code/game/objects/structures/beds_chairs/chair.dm
+++ b/code/game/objects/structures/beds_chairs/chair.dm
@@ -11,7 +11,7 @@
integrity_failure = 0.1
custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT)
layer = OBJ_LAYER
- interaction_flags_mouse_drop = NEED_HANDS | NEED_DEXTERITY
+ interaction_flags_mouse_drop = ALLOW_RESTING
var/buildstacktype = /obj/item/stack/sheet/iron
var/buildstackamount = 1
@@ -437,7 +437,6 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0)
buildstacktype = /obj/item/stack/sheet/bronze
buildstackamount = 1
item_chair = null
- interaction_flags_click = NEED_DEXTERITY
/// Total rotations made
var/turns = 0
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index 28b5e7923a8a1..4484e3c512ef3 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -1013,7 +1013,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
return FALSE
return TRUE
-/obj/structure/closet/container_resist_act(mob/living/user)
+/obj/structure/closet/container_resist_act(mob/living/user, loc_required = TRUE)
if(isstructure(loc))
relay_container_resist_act(user, loc)
if(opened)
@@ -1038,7 +1038,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets)
addtimer(CALLBACK(src, PROC_REF(check_if_shake)), 1 SECONDS)
if(do_after(user,(breakout_time), target = src))
- if(!user || user.stat != CONSCIOUS || user.loc != src || opened || (!locked && !welded) )
+ if(!user || user.stat != CONSCIOUS || (loc_required && (user.loc != src)) || opened || (!locked && !welded) )
return
//we check after a while whether there is a point of resisting anymore and whether the user is capable of resisting
user.visible_message(span_danger("[user] successfully broke out of [src]!"),
diff --git a/code/game/objects/structures/crates_lockers/closets/bodybag.dm b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
index 8eb5cc3b8c0d4..ac8b444e47dc7 100644
--- a/code/game/objects/structures/crates_lockers/closets/bodybag.dm
+++ b/code/game/objects/structures/crates_lockers/closets/bodybag.dm
@@ -276,7 +276,7 @@
else
icon_state = initial(icon_state)
-/obj/structure/closet/body_bag/environmental/prisoner/container_resist_act(mob/living/user)
+/obj/structure/closet/body_bag/environmental/prisoner/container_resist_act(mob/living/user, loc_required = TRUE)
/// copy-pasted with changes because flavor text as well as some other misc stuff
if(opened)
return
diff --git a/code/game/objects/structures/lavaland/ore_vent.dm b/code/game/objects/structures/lavaland/ore_vent.dm
index c1e81862ac934..27e05b6dc540d 100644
--- a/code/game/objects/structures/lavaland/ore_vent.dm
+++ b/code/game/objects/structures/lavaland/ore_vent.dm
@@ -560,7 +560,7 @@
boss_string = "A giant, armored behemoth"
if(/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner)
boss_string = "A bloody drillmark"
- if(/mob/living/simple_animal/hostile/megafauna/wendigo)
+ if(/mob/living/simple_animal/hostile/megafauna/wendigo/noportal)
boss_string = "A chilling skull"
. += span_notice("[boss_string] is etched onto the side of the vent.")
@@ -585,7 +585,7 @@
icon_state_tapped = "ore_vent_ice_active"
defending_mobs = list(
/mob/living/simple_animal/hostile/megafauna/demonic_frost_miner,
- /mob/living/simple_animal/hostile/megafauna/wendigo,
+ /mob/living/simple_animal/hostile/megafauna/wendigo/noportal,
/mob/living/simple_animal/hostile/megafauna/colossus,
)
diff --git a/code/game/objects/structures/spawner.dm b/code/game/objects/structures/spawner.dm
index 5f9450e435838..743d76ef182b2 100644
--- a/code/game/objects/structures/spawner.dm
+++ b/code/game/objects/structures/spawner.dm
@@ -70,7 +70,9 @@
spawn_time = spawn_time, \
max_spawned = max_mobs, \
faction = faction, \
- spawn_text = spawn_text, \
+ spawn_text = spawn_text,\
+ spawn_callback = CALLBACK(src, PROC_REF(on_mob_spawn)), \
+ initial_spawn_delay = !mapload, \
)
/obj/structure/spawner/attack_animal(mob/living/simple_animal/user, list/modifiers)
@@ -78,6 +80,8 @@
return
return ..()
+/obj/structure/spawner/proc/on_mob_spawn(atom/created_atom)
+ return
/obj/structure/spawner/syndicate
name = "warp beacon"
@@ -226,3 +230,74 @@
newmob.desc = "It's [living_mob], but [living_mob.p_their()] flesh has an ashy texture, and [living_mob.p_their()] face is featureless save an eerie smile."
src.visible_message(span_warning("[living_mob] reemerges from the link!"))
qdel(living_mob)
+
+/obj/structure/spawner/sentient
+ var/role_name = "A sentient mob"
+ var/assumed_control_message = "You are a sentient mob from a badly coded spawner"
+
+/obj/structure/spawner/sentient/Initialize(mapload)
+ . = ..()
+ notify_ghosts(
+ "A [name] has been created in \the [get_area(src)]!",
+ source = src,
+ header = "Sentient Spawner Created",
+ notify_flags = NOTIFY_CATEGORY_NOFLASH,
+ )
+
+/obj/structure/spawner/sentient/on_mob_spawn(atom/created_atom)
+ created_atom.AddComponent(\
+ /datum/component/ghost_direct_control,\
+ role_name = src.role_name,\
+ assumed_control_message = src.assumed_control_message,\
+ after_assumed_control = CALLBACK(src, PROC_REF(became_player_controlled)),\
+ )
+
+/obj/structure/spawner/sentient/proc/became_player_controlled(mob/proteon)
+ return
+
+/obj/structure/spawner/sentient/proteon_spawner
+ name = "eldritch gateway"
+ desc = "A dizzying structure that somehow links into Nar'Sie's own domain. The screams of the damned echo continously."
+ icon = 'icons/obj/antags/cult/structures.dmi'
+ icon_state = "hole"
+ light_power = 2
+ light_color = COLOR_CULT_RED
+ max_integrity = 50
+ density = FALSE
+ max_mobs = 2
+ spawn_time = 15 SECONDS
+ mob_types = list(/mob/living/basic/construct/proteon/hostile)
+ spawn_text = "arises from"
+ faction = list(FACTION_CULT)
+ role_name = "A proteon cult construct"
+ assumed_control_message = null
+
+/obj/structure/spawner/sentient/proteon_spawner/examine_status(mob/user)
+ if(IS_CULTIST(user) || !isliving(user))
+ return span_cult("It's at [round(atom_integrity * 100 / max_integrity)]% stability.")
+ return ..()
+
+/obj/structure/spawner/sentient/proteon_spawner/examine(mob/user)
+ . = ..()
+ if(!IS_CULTIST(user) && isliving(user))
+ var/mob/living/living_user = user
+ living_user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15)
+ . += span_danger("The voices of the damned echo relentlessly in your mind, continously rebounding on the walls of your self the more you focus on [src]. Your head pounds, better keep away...")
+ else
+ . += span_cult("The gateway will create one weak proteon construct every [spawn_time * 0.1] seconds, up to a total of [max_mobs], that may be controlled by the spirits of the dead.")
+
+/obj/structure/spawner/sentient/proteon_spawner/became_player_controlled(mob/living/basic/construct/proteon/proteon)
+ proteon.mind.add_antag_datum(/datum/antagonist/cult)
+ proteon.add_filter("awoken_proteon", 3, list("type" = "outline", "color" = COLOR_CULT_RED, "size" = 2))
+ visible_message(span_cult_bold("[proteon] awakens, glowing an eerie red as it stirs from its stupor!"))
+ playsound(proteon, 'sound/items/haunted/ghostitemattack.ogg', 100, TRUE)
+ proteon.balloon_alert_to_viewers("awoken!")
+ addtimer(CALLBACK(src, PROC_REF(remove_wake_outline), proteon), 8 SECONDS)
+
+/obj/structure/spawner/sentient/proteon_spawner/proc/remove_wake_outline(mob/proteon)
+ proteon.remove_filter("awoken_proteon")
+ proteon.add_filter("sentient_proteon", 3, list("type" = "outline", "color" = COLOR_CULT_RED, "size" = 2, "alpha" = 40))
+
+/obj/structure/spawner/sentient/proteon_spawner/handle_deconstruct(disassembled)
+ playsound('sound/hallucinations/veryfar_noise.ogg', 125)
+ visible_message(span_cult_bold("[src] completely falls apart, the screams of the damned reaching a feverous pitch before slowly fading away into nothing."))
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 70d2cad97ca88..0076019532118 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -568,6 +568,14 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/spawner, 0)
MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/unanchored/spawner, 0)
+// You can't rust glass! So only reinforced glass can be impacted.
+/obj/structure/window/reinforced/rust_heretic_act()
+ add_atom_colour(COLOR_RUSTED_GLASS, FIXED_COLOUR_PRIORITY)
+ AddElement(/datum/element/rust)
+ set_armor(/datum/armor/none)
+ take_damage(get_integrity() * 0.5)
+ modify_max_integrity(max_integrity * 0.5)
+
/obj/structure/window/plasma
name = "plasma window"
desc = "A window made out of a plasma-silicate alloy. It looks insanely tough to break and burn through."
diff --git a/code/game/turfs/open/lava.dm b/code/game/turfs/open/lava.dm
index 53450b85db0df..23e2b6b38db84 100644
--- a/code/game/turfs/open/lava.dm
+++ b/code/game/turfs/open/lava.dm
@@ -205,8 +205,8 @@
to_chat(user, span_warning("You need one rod to build a heatproof lattice."))
return
// Light a cigarette in the lava
- if(istype(C, /obj/item/clothing/mask/cigarette))
- var/obj/item/clothing/mask/cigarette/ciggie = C
+ if(istype(C, /obj/item/cigarette))
+ var/obj/item/cigarette/ciggie = C
if(ciggie.lit)
to_chat(user, span_warning("The [ciggie.name] is already lit!"))
return TRUE
diff --git a/code/modules/antagonists/_common/antag_spawner.dm b/code/modules/antagonists/_common/antag_spawner.dm
index bc22eedbfa189..440feb91b7622 100644
--- a/code/modules/antagonists/_common/antag_spawner.dm
+++ b/code/modules/antagonists/_common/antag_spawner.dm
@@ -443,7 +443,7 @@
name = "Syndicate Monkey Agent Kit"
head = /obj/item/clothing/head/fedora
- mask = /obj/item/clothing/mask/cigarette/syndicate
+ mask = /obj/item/cigarette/syndicate
uniform = /obj/item/clothing/under/syndicate
l_pocket = /obj/item/reagent_containers/cup/soda_cans/monkey_energy
r_pocket = /obj/item/storage/fancy/cigarettes/cigpack_syndicate
diff --git a/code/modules/antagonists/cult/blood_magic.dm b/code/modules/antagonists/cult/blood_magic.dm
index 192d9c4e66d5a..eb55138a4483a 100644
--- a/code/modules/antagonists/cult/blood_magic.dm
+++ b/code/modules/antagonists/cult/blood_magic.dm
@@ -12,6 +12,8 @@
default_button_position = DEFAULT_BLOODSPELLS
var/list/spells = list()
var/channeling = FALSE
+ /// If the magic has been enhanced somehow, likely due to a crimson focus.
+ var/magic_enhanced = FALSE
/datum/action/innate/cult/blood_magic/Remove()
for(var/X in spells)
@@ -29,7 +31,7 @@
var/atom/movable/screen/movable/action_button/button = viewers[hud]
var/position = screen_loc_to_offset(button.screen_loc)
var/list/position_list = list()
- for(var/possible_position in 1 to MAX_BLOODCHARGE)
+ for(var/possible_position in 1 to magic_enhanced ? ENHANCED_BLOODCHARGE : MAX_BLOODCHARGE)
position_list += possible_position
for(var/datum/action/innate/cult/blood_spell/blood_spell in spells)
if(blood_spell.positioned)
@@ -50,10 +52,10 @@
rune = TRUE
break
if(rune)
- limit = MAX_BLOODCHARGE
+ limit = magic_enhanced ? ENHANCED_BLOODCHARGE : MAX_BLOODCHARGE
if(length(spells) >= limit)
if(rune)
- to_chat(owner, span_cult_italic("You cannot store more than [MAX_BLOODCHARGE] spells. Pick a spell to remove."))
+ to_chat(owner, span_cult_italic("You cannot store more than [limit] spells. Pick a spell to remove."))
else
to_chat(owner, span_cult_bold_italic("You cannot store more than [RUNELESS_MAX_BLOODCHARGE] spells without an empowering rune! Pick a spell to remove."))
var/nullify_spell = tgui_input_list(owner, "Spell to remove", "Current Spells", spells)
@@ -86,10 +88,15 @@
else
to_chat(owner, span_cult_italic("You are already invoking blood magic!"))
return
- if(do_after(owner, 100 - rune*60, target = owner))
+ var/spell_carving_timer = 10 SECONDS
+ if(rune)
+ spell_carving_timer = 4 SECONDS
+ if(magic_enhanced)
+ spell_carving_timer *= 0.5
+ if(do_after(owner, spell_carving_timer, target = owner))
if(ishuman(owner))
var/mob/living/carbon/human/human_owner = owner
- human_owner.bleed(40 - rune*32)
+ human_owner.bleed(rune ? 8 : 40)
var/datum/action/innate/cult/blood_spell/new_spell = new BS(owner.mind)
new_spell.Grant(owner, src)
spells += new_spell
@@ -428,19 +435,35 @@
return
var/datum/antagonist/cult/cultist = IS_CULTIST(user)
var/datum/team/cult/cult_team = cultist.get_team()
- var/effect_coef = 1 - (cult_team.cult_risen ? 0.4 : 0) - (cult_team.cult_ascendent ? 0.5 : 0)
+ var/effect_coef = 1
+ if(cult_team.cult_ascendent)
+ effect_coef = 0.1
+ else if(cult_team.cult_risen)
+ effect_coef = 0.4
user.visible_message(
span_warning("[user] holds up [user.p_their()] hand, which explodes in a flash of red light!"),
span_cult_italic("You attempt to stun [target] with the spell!"),
visible_message_flags = ALWAYS_SHOW_SELF_MESSAGE,
)
user.mob_light(range = 1.1, power = 2, color = LIGHT_COLOR_BLOOD_MAGIC, duration = 0.2 SECONDS)
+ // Heretics are momentarily disoriented by the stunning aura. Enough for both parties to go 'oh shit' but only a mild combat ability.
+ // Heretics have an identical effect on their grasp. The cultist's worse spell preparation is offset by their extra gear and teammates.
if(IS_HERETIC(target))
- to_chat(user, span_warning("Some force greater than you intervenes! [target] is protected by the Forgotten Gods!"))
- to_chat(target, span_warning("You are protected by your faith to the Forgotten Gods."))
+ target.AdjustKnockdown(0.5 SECONDS)
+ target.adjust_confusion_up_to(1.5 SECONDS, 3 SECONDS)
+ target.adjust_dizzy_up_to(1.5 SECONDS, 3 SECONDS)
+ ADD_TRAIT(target, TRAIT_NO_SIDE_KICK, REF(src)) // We don't want this to be a good stunning tool, just minor disorientation
+ addtimer(TRAIT_CALLBACK_REMOVE(target, TRAIT_NO_SIDE_KICK, REF(src)), 1 SECONDS)
+
var/old_color = target.color
- target.color = rgb(0, 128, 0)
- animate(target, color = old_color, time = 1 SECONDS, easing = EASE_IN)
+ target.color = COLOR_HERETIC_GREEN
+ animate(target, color = old_color, time = 4 SECONDS, easing = EASE_IN)
+ target.mob_light(range = 1.5, power = 2.5, color = COLOR_HERETIC_GREEN, duration = 0.5 SECONDS)
+ playsound(target, 'sound/magic/magic_block_mind.ogg', 150, TRUE) // insanely quiet
+
+ to_chat(user, span_warning("An eldritch force intervenes as you touch [target], absorbing most of the effects!"))
+ to_chat(target, span_warning("As [user] touches you with vile magicks, the Mansus absorbs most of the effects!"))
+ target.balloon_alert_to_viewers("absorbed!")
else if(target.can_block_magic())
to_chat(user, span_warning("The spell had no effect!"))
else
diff --git a/code/modules/antagonists/cult/cult_bastard_sword.dm b/code/modules/antagonists/cult/cult_bastard_sword.dm
deleted file mode 100644
index 0d70bd503fb7f..0000000000000
--- a/code/modules/antagonists/cult/cult_bastard_sword.dm
+++ /dev/null
@@ -1,98 +0,0 @@
-
-/// Cult Bastard Sword, earned by cultists when they manage to sacrifice a heretic.
-/obj/item/cult_bastard
- name = "bloody bastard sword"
- desc = "An enormous sword used by Nar'Sien cultists to rapidly harvest the souls of non-believers."
- w_class = WEIGHT_CLASS_HUGE
- block_chance = 50
- block_sound = 'sound/weapons/parry.ogg'
- throwforce = 20
- force = 35
- armour_penetration = 45
- throw_speed = 1
- throw_range = 3
- sharpness = SHARP_EDGED
- light_color = "#ff0000"
- attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends")
- attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend")
- icon = 'icons/obj/weapons/sword.dmi'
- icon_state = "cultbastard"
- inhand_icon_state = "cultbastard"
- hitsound = 'sound/weapons/bladeslice.ogg'
- lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
- righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
- inhand_x_dimension = 64
- inhand_y_dimension = 64
- actions_types = list()
- item_flags = SLOWS_WHILE_IN_HAND
- ///if we are using our attack_self ability
- var/spinning = FALSE
-
-/obj/item/cult_bastard/Initialize(mapload)
- . = ..()
- set_light(4)
- AddComponent(/datum/component/butchering, 50, 80)
- AddComponent(/datum/component/two_handed, require_twohands = TRUE)
- AddComponent(/datum/component/soul_stealer, soulstone_type = /obj/item/soulstone)
- AddComponent( \
- /datum/component/spin2win, \
- spin_cooldown_time = 25 SECONDS, \
- on_spin_callback = CALLBACK(src, PROC_REF(on_spin)), \
- on_unspin_callback = CALLBACK(src, PROC_REF(on_unspin)), \
- start_spin_message = span_danger("%USER begins swinging the sword around with inhuman strength!"), \
- end_spin_message = span_warning("%USER's inhuman strength dissipates and the sword's runes grow cold!") \
- )
-
-/obj/item/cult_bastard/proc/on_spin(mob/living/user, duration)
- var/oldcolor = user.color
- user.color = "#ff0000"
- user.add_stun_absorption(
- source = name,
- duration = duration,
- priority = 2,
- message = span_warning("%EFFECT_OWNER doesn't even flinch as the sword's power courses through [user.p_them()]!"),
- self_message = span_boldwarning("You shrug off the stun!"),
- examine_message = span_warning("%EFFECT_OWNER_THEYRE glowing with a blazing red aura!"),
- )
- user.spin(duration, 1)
- animate(user, color = oldcolor, time = duration, easing = EASE_IN)
- addtimer(CALLBACK(user, TYPE_PROC_REF(/atom, update_atom_colour)), duration)
- block_chance = 100
- slowdown += 1.5
- spinning = TRUE
-
-/obj/item/cult_bastard/proc/on_unspin(mob/living/user)
- block_chance = 50
- slowdown -= 1.5
- spinning = FALSE
-
-/obj/item/cult_bastard/can_be_pulled(user)
- return FALSE
-
-/obj/item/cult_bastard/pickup(mob/living/user)
- . = ..()
- if(!IS_CULTIST(user))
- if(!IS_HERETIC(user))
- to_chat(user, "\"I wouldn't advise that.\"")
- force = 5
- return
- else
- to_chat(user, span_cult_large("\"You cling to the Forgotten Gods, as if you're more than their pawn.\""))
- to_chat(user, span_userdanger("A horrible force yanks at your arm!"))
- user.emote("scream")
- user.apply_damage(30, BRUTE, pick(GLOB.arm_zones))
- user.dropItemToGround(src, TRUE)
- user.Paralyze(50)
- return
- force = initial(force)
-
-/obj/item/cult_bastard/IsReflect(def_zone)
- if(!spinning)
- return FALSE
- return TRUE
-
-/obj/item/cult_bastard/hit_reaction(mob/living/carbon/human/owner, atom/movable/hitby, attack_text = "the attack", final_block_chance = 0, damage = 0, attack_type = MELEE_ATTACK, damage_type = BRUTE)
- if(!prob(final_block_chance))
- return FALSE
- owner.visible_message(span_danger("[owner] parries [attack_text] with [src]!"))
- return TRUE
diff --git a/code/modules/antagonists/cult/cult_items.dm b/code/modules/antagonists/cult/cult_items.dm
index c0051aec87cd1..ef7292267d69f 100644
--- a/code/modules/antagonists/cult/cult_items.dm
+++ b/code/modules/antagonists/cult/cult_items.dm
@@ -76,6 +76,8 @@ Striking a noncultist, however, will tear their flesh."}
block_sound = 'sound/weapons/parry.ogg'
attack_verb_continuous = list("attacks", "slashes", "stabs", "slices", "tears", "lacerates", "rips", "dices", "rends")
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend")
+ /// If TRUE, it can be used at will by anyone, non-cultists included
+ var/free_use = FALSE
/obj/item/melee/cultblade/Initialize(mapload)
. = ..()
@@ -93,7 +95,7 @@ Striking a noncultist, however, will tear their flesh."}
return FALSE
/obj/item/melee/cultblade/attack(mob/living/target, mob/living/carbon/human/user)
- if(!IS_CULTIST(user))
+ if(!IS_CULTIST(user) && !free_use)
user.Paralyze(100)
user.dropItemToGround(src, TRUE)
user.visible_message(span_warning("A powerful force shoves [user] away from [target]!"), \
@@ -106,6 +108,174 @@ Striking a noncultist, however, will tear their flesh."}
return
..()
+#define WIELDER_SPELLS "wielder_spell"
+#define SWORD_SPELLS "sword_spell"
+#define SWORD_PREFIX "sword_prefix"
+
+/obj/item/melee/cultblade/haunted
+ name = "haunted longsword"
+ desc = "An eerie sword with a blade that is less 'black' than it is 'absolute nothingness'. It glows with furious, restrained green energy."
+ icon_state = "hauntedblade"
+ inhand_icon_state = "hauntedblade"
+ worn_icon_state = "hauntedblade"
+ force = 35
+ throwforce = 35
+ block_chance = 55
+ wound_bonus = -25
+ bare_wound_bonus = 30
+ free_use = TRUE
+ light_color = COLOR_HERETIC_GREEN
+ light_range = 4
+ /// holder for the actual action when created.
+ var/datum/action/cooldown/spell/path_wielder_action
+ var/mob/living/trapped_entity
+ /// The heretic path that the variable below uses to index abilities. Assigned when the heretic is ensouled.
+ var/heretic_path
+ /// Nested static list used to index abilities and names.
+ var/static/list/heretic_paths_to_haunted_sword_abilities = list(
+ // Ash
+ PATH_ASH = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/jaunt/ethereal_jaunt/ash),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/ash_beams),
+ SWORD_PREFIX = "ashen",
+ ),
+ // Flesh
+ PATH_FLESH = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/blood_siphon),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/cleave),
+ SWORD_PREFIX = "sanguine",
+ ),
+ // Void
+ PATH_VOID = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/void_phase),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/cone/staggered/cone_of_cold/void),
+ SWORD_PREFIX = "tenebrous",
+ ),
+ // Blade
+ PATH_BLADE = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/projectile/furious_steel/haunted),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/projectile/furious_steel/solo),
+ SWORD_PREFIX = "keen",
+ ),
+ // Rust
+ PATH_RUST = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/cone/staggered/entropic_plume),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/aoe/rust_conversion, /datum/action/cooldown/spell/pointed/rust_construction),
+ SWORD_PREFIX = "rusted",
+ ),
+ // Cosmic
+ PATH_COSMIC = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/conjure/cosmic_expansion),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/projectile/star_blast),
+ SWORD_PREFIX = "astral",
+ ),
+ // Lock
+ PATH_LOCK = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/burglar_finesse),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/apetra_vulnera),
+ SWORD_PREFIX = "incisive",
+ ),
+ // Moon
+ PATH_MOON = list(
+ WIELDER_SPELLS = list(/datum/action/cooldown/spell/pointed/projectile/moon_parade),
+ SWORD_SPELLS = list(/datum/action/cooldown/spell/pointed/moon_smile),
+ SWORD_PREFIX = "shimmering",
+ ),
+ // Starter
+ PATH_START = list(
+ WIELDER_SPELLS = null,
+ SWORD_SPELLS = null,
+ SWORD_PREFIX = "stillborn", // lol loser
+ ) ,
+ )
+
+/obj/item/melee/cultblade/haunted/Initialize(mapload, mob/soul_to_bind, mob/awakener, do_bind = TRUE)
+ . = ..()
+
+ AddElement(/datum/element/heretic_focus)
+ add_traits(list(TRAIT_CASTABLE_LOC, TRAIT_SPELLS_TRANSFER_TO_LOC), INNATE_TRAIT)
+ if(do_bind && !mapload)
+ bind_soul(soul_to_bind, awakener)
+
+/obj/item/melee/cultblade/haunted/proc/bind_soul(mob/soul_to_bind, mob/awakener)
+
+ var/datum/mind/trapped_mind = soul_to_bind?.mind
+
+ if(!trapped_mind)
+ return // Can't do anything further down the list
+
+ if(trapped_mind)
+ AddComponent(/datum/component/spirit_holding,\
+ soul_to_bind = trapped_mind,\
+ awakener = awakener,\
+ allow_renaming = FALSE,\
+ allow_channeling = FALSE,\
+ )
+
+ // Get the heretic's new body and antag datum.
+ trapped_entity = trapped_mind?.current
+ trapped_entity.key = trapped_mind?.key
+ var/datum/antagonist/heretic/heretic_holder = IS_HERETIC(trapped_entity)
+ if(!heretic_holder)
+ stack_trace("[soul_to_bind] in but not a heretic on the heretic soul blade.")
+
+ // Give the spirit a spell that lets them try to fly around.
+ var/datum/action/cooldown/spell/pointed/sword_fling/fling_act = \
+ new /datum/action/cooldown/spell/pointed/sword_fling(trapped_mind, to_fling = src)
+ fling_act.Grant(trapped_entity)
+
+ // Set the sword's path for spell selection.
+ heretic_path = heretic_holder.heretic_path
+
+ // Copy the objectives to keep for roundend, remove the datum as neither us nor the heretic need it anymore
+ var/list/copied_objectives = heretic_holder.objectives.Copy()
+ trapped_entity.mind.remove_antag_datum(/datum/antagonist/heretic)
+
+ // Add the fallen antag datum, give them a heads-up of what's happening.
+ var/datum/antagonist/soultrapped_heretic/bozo = new()
+ bozo.objectives |= copied_objectives
+ trapped_entity.mind.add_antag_datum(bozo)
+ to_chat(trapped_entity, span_userdanger("You've been sacrificed to the Enemy, and trapped inside a haunted blade! While you cannot escape, you may help the Cult, your current wielder, or even pester everyone with what few abilities you kept."))
+
+ // Assigning the spells to give to the wielder and spirit.
+ // Let them cast the given spell.
+ ADD_TRAIT(trapped_entity, TRAIT_ALLOW_HERETIC_CASTING, INNATE_TRAIT)
+
+ var/list/path_spells = heretic_paths_to_haunted_sword_abilities[heretic_path]
+
+ var/list/wielder_spells = path_spells[WIELDER_SPELLS]
+ var/list/sword_spells = path_spells[SWORD_SPELLS]
+
+ name = "[path_spells[SWORD_PREFIX]] [name]"
+
+
+ // Granting the path spells. The sword spirit gains it outright, while it's just instanced for wielders to be added on pickup.
+
+ if(sword_spells)
+ for(var/datum/action/cooldown/spell/sword_spell as anything in sword_spells)
+ sword_spell = new sword_spell(trapped_entity)
+ sword_spell?.Grant(trapped_entity)
+ sword_spell?.overlay_icon_state = "bg_cult_border" // for flavor, and also helps distinguish
+
+
+ if(wielder_spells)
+ for(var/datum/action/cooldown/spell/wielder_spell as anything in wielder_spells)
+ path_wielder_action = new wielder_spell(src)
+ wielder_spell?.overlay_icon_state = "bg_cult_border"
+
+/obj/item/melee/cultblade/haunted/equipped(mob/user, slot, initial)
+ . = ..()
+ if(slot & ITEM_SLOT_HANDS)
+ path_wielder_action?.Grant(user)
+
+/obj/item/melee/cultblade/haunted/dropped(mob/user, silent)
+ . = ..()
+ path_wielder_action?.Remove(user)
+
+#undef WIELDER_SPELLS
+#undef SWORD_SPELLS
+#undef SWORD_PREFIX
+
/obj/item/melee/cultblade/ghost
name = "eldritch sword"
force = 19 //can't break normal airlocks
@@ -120,7 +290,7 @@ Striking a noncultist, however, will tear their flesh."}
/obj/item/melee/cultblade/pickup(mob/living/user)
..()
- if(!IS_CULTIST(user))
+ if(!IS_CULTIST(user) && !free_use)
to_chat(user, span_cult_large("\"I wouldn't advise that.\""))
/datum/action/innate/dash/cult
@@ -563,6 +733,78 @@ Striking a noncultist, however, will tear their flesh."}
#undef MAX_SHUTTLE_CURSES
+#define GATEWAY_TURF_SCAN_RANGE 40
+
+/obj/item/proteon_orb
+ name = "summoning orb"
+ desc = "An eerie translucent orb that feels impossibly light. Legends say summoning orbs are created from corrupted scrying orbs. If you hold it close to your ears, you can hear the screams of the damned."
+ icon = 'icons/obj/antags/cult/items.dmi'
+ icon_state = "summoning_orb"
+ light_range = 3
+ light_color = COLOR_CULT_RED
+
+/obj/item/proteon_orb/examine(mob/user)
+ . = ..()
+ if(!IS_CULTIST(user) && isliving(user))
+ var/mob/living/living_user = user
+ living_user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 5)
+ . += span_danger("It hurts just to look at it. Better keep away.")
+ else
+ . += span_cult("It can be used to create a gateway to Nar'Sie's domain, which will summon weak, sentient constructs over time.")
+
+/obj/item/proteon_orb/attack_self(mob/living/user)
+
+ var/list/turfs_to_scan = detect_room(get_turf(user), max_size = GATEWAY_TURF_SCAN_RANGE)
+
+ if(!IS_CULTIST(user))
+ to_chat(user, span_cult_large("\"You want to enter my domain? Go ahead.\""))
+ turfs_to_scan = null // narsie wants to have some fun and the veil wont stop her
+
+ for(var/turf/hole_candidate as anything in turfs_to_scan)
+ if(locate(/obj/structure/spawner/sentient/proteon_spawner) in hole_candidate)
+ to_chat(user, span_cult_bold("There's a gateway too close nearby. The veil is not yet weak enough to allow such close rips in its fabric."))
+ return
+ to_chat(user, span_cult_bold_italic("You focus on [src] and direct it into the ground. It rumbles..."))
+
+ var/turf/open/hole_spot = get_turf(user)
+ if(!istype(hole_spot) || isgroundlessturf(hole_spot))
+ to_chat(user, span_notice("This is not a suitable spot."))
+ return
+
+ INVOKE_ASYNC(hole_spot, TYPE_PROC_REF(/turf/open, quake_gateway), user)
+ qdel(src)
+
+/**
+ * Bespoke proc that happens when a proteon orb is activated, creating a gateway.
+ * If activated by a non-cultist, they get an unusual game over.
+*/
+/turf/open/proc/quake_gateway(mob/living/user)
+ Shake(2, 2, 5 SECONDS)
+ narsie_act(TRUE, TRUE, 100)
+ var/fucked = FALSE
+ if(!IS_CULTIST(user))
+ fucked = TRUE
+ ADD_TRAIT(user, TRAIT_NO_TRANSFORM, REF(src)) // keep em in place
+ user.add_atom_colour(COLOR_CULT_RED, TEMPORARY_COLOUR_PRIORITY)
+ user.visible_message(span_cult_bold("Dark tendrils appear from the ground and root [user] in place!"))
+ sleep(5 SECONDS) // can we still use these or. i mean its async
+ new /obj/structure/spawner/sentient/proteon_spawner(src)
+ visible_message(span_cult_bold("A mysterious hole appears out of nowhere!"))
+ if(!fucked || QDELETED(user))
+ return
+ if(get_turf(user) != src) // they get away. for now
+ REMOVE_TRAIT(user, TRAIT_NO_TRANSFORM, REF(src))
+ return
+ user.visible_message(span_cult_bold("[user] is pulled into the portal through an infinitesmally minuscule hole, shredding [user.p_their()] body!"))
+ sleep(5 SECONDS)
+ user.visible_message(span_cult_italic("An unusually large construct appears through the portal!"))
+ user.gib() // total destruction
+ var/mob/living/basic/construct/proteon/hostile/remnant = new(get_step_rand(src))
+ remnant.name = "[user]" // no, they do not become it
+ remnant.transform *= 1.5
+
+#undef GATEWAY_TURF_SCAN_RANGE
+
/obj/item/cult_shift
name = "veil shifter"
desc = "This relic instantly teleports you, and anything you're pulling, forward by a moderate distance."
diff --git a/code/modules/antagonists/cult/cult_other.dm b/code/modules/antagonists/cult/cult_other.dm
index 82b342b87ef50..9435baedba11a 100644
--- a/code/modules/antagonists/cult/cult_other.dm
+++ b/code/modules/antagonists/cult/cult_other.dm
@@ -16,8 +16,15 @@
/proc/is_convertable_to_cult(mob/living/target, datum/team/cult/specific_cult)
if(!istype(target))
return FALSE
- if(isnull(target.mind) || !GET_CLIENT(target))
+ if(isnull(target.mind))
return FALSE
+
+// disables client checks if testing for easier debugging
+#ifndef TESTING
+ if(!GET_CLIENT(target))
+ return FALSE
+#endif
+
if(target.mind.unconvertable)
return FALSE
if(ishuman(target) && target.mind.holy_role)
diff --git a/code/modules/antagonists/cult/cult_structure_altar.dm b/code/modules/antagonists/cult/cult_structure_altar.dm
index 9347acb33210f..e38591c0c0705 100644
--- a/code/modules/antagonists/cult/cult_structure_altar.dm
+++ b/code/modules/antagonists/cult/cult_structure_altar.dm
@@ -2,6 +2,7 @@
#define ELDRITCH_WHETSTONE "Eldritch Whetstone"
#define CONSTRUCT_SHELL "Construct Shell"
#define UNHOLY_WATER "Flask of Unholy Water"
+#define PROTEON_ORB "Portal Summoning Orb"
// Cult altar. Gives out consumable items.
/obj/structure/destructible/cult/item_dispenser/altar
@@ -10,6 +11,7 @@
cult_examine_tip = "Can be used to create eldritch whetstones, construct shells, and flasks of unholy water."
icon_state = "talismanaltar"
break_message = "The altar shatters, leaving only the wailing of the damned!"
+ mansus_conversion_path = /obj/effect/heretic_rune
/obj/structure/destructible/cult/item_dispenser/altar/setup_options()
var/static/list/altar_items = list(
@@ -27,7 +29,20 @@
),
)
+ var/extra_item = extra_options()
+
options = altar_items
+ if(!isnull(extra_item))
+ options += extra_item
+
+/obj/structure/destructible/cult/item_dispenser/altar/extra_options()
+ if(!cult_team?.unlocked_heretic_items[PROTEON_ORB_UNLOCKED])
+ return
+ return list(PROTEON_ORB = list(
+ PREVIEW_IMAGE = image(icon = 'icons/obj/antags/cult/items.dmi', icon_state = "summoning_orb"),
+ OUTPUT_ITEMS = list(/obj/item/proteon_orb),
+ ),
+ )
/obj/structure/destructible/cult/item_dispenser/altar/succcess_message(mob/living/user, obj/item/spawned_item)
to_chat(user, span_cult_italic("You kneel before [src] and your faith is rewarded with [spawned_item]!"))
@@ -35,3 +50,4 @@
#undef ELDRITCH_WHETSTONE
#undef CONSTRUCT_SHELL
#undef UNHOLY_WATER
+#undef PROTEON_ORB
diff --git a/code/modules/antagonists/cult/cult_structure_archives.dm b/code/modules/antagonists/cult/cult_structure_archives.dm
index a961739663391..d3a96dd1f77aa 100644
--- a/code/modules/antagonists/cult/cult_structure_archives.dm
+++ b/code/modules/antagonists/cult/cult_structure_archives.dm
@@ -2,6 +2,7 @@
#define CULT_BLINDFOLD "Zealot's Blindfold"
#define CURSE_ORB "Shuttle Curse"
#define VEIL_WALKER "Veil Walker Set"
+#define CRIMSON_FOCUS "Crimson Focus"
// Cult archives. Gives out utility items.
/obj/structure/destructible/cult/item_dispenser/archives
@@ -12,6 +13,7 @@
light_range = 1.5
light_color = LIGHT_COLOR_FIRE
break_message = "The books and tomes of the archives burn into ash as the desk shatters!"
+ mansus_conversion_path = /obj/item/codex_cicatrix
/obj/structure/destructible/cult/item_dispenser/archives/setup_options()
var/static/list/archive_items = list(
@@ -29,7 +31,20 @@
),
)
+ var/extra_item = extra_options()
+
options = archive_items
+ if(!isnull(extra_item))
+ options += extra_item
+
+/obj/structure/destructible/cult/item_dispenser/archives/extra_options()
+ if(!cult_team?.unlocked_heretic_items[CRIMSON_FOCUS_UNLOCKED])
+ return
+ return list(CRIMSON_FOCUS = list(
+ PREVIEW_IMAGE = image(icon = 'icons/obj/clothing/neck.dmi', icon_state = "crimson_focus"),
+ OUTPUT_ITEMS = list(/obj/item/clothing/neck/heretic_focus/crimson_focus),
+ ),
+ )
/obj/structure/destructible/cult/item_dispenser/archives/succcess_message(mob/living/user, obj/item/spawned_item)
to_chat(user, span_cult_italic("You summon [spawned_item] from [src]!"))
@@ -41,3 +56,4 @@
#undef CULT_BLINDFOLD
#undef CURSE_ORB
#undef VEIL_WALKER
+#undef CRIMSON_FOCUS
diff --git a/code/modules/antagonists/cult/cult_structure_forge.dm b/code/modules/antagonists/cult/cult_structure_forge.dm
index 912db7d37e9b8..12d15b9296ef4 100644
--- a/code/modules/antagonists/cult/cult_structure_forge.dm
+++ b/code/modules/antagonists/cult/cult_structure_forge.dm
@@ -2,6 +2,7 @@
#define NARSIE_ARMOR "Nar'Sien Hardened Armor"
#define FLAGELLANT_ARMOR "Flagellant's Robe"
#define ELDRITCH_SWORD "Eldritch Longsword"
+#define CURSED_BLADE "Cursed Ritual Blade"
// Cult forge. Gives out combat weapons.
/obj/structure/destructible/cult/item_dispenser/forge
@@ -12,6 +13,7 @@
light_range = 2
light_color = LIGHT_COLOR_LAVA
break_message = "The forge breaks apart into shards with a howling scream!"
+ mansus_conversion_path = /obj/structure/destructible/eldritch_crucible
/obj/structure/destructible/cult/item_dispenser/forge/setup_options()
var/static/list/forge_items = list(
@@ -29,7 +31,21 @@
),
)
+ var/extra_item = extra_options()
+
options = forge_items
+ if(!isnull(extra_item))
+ options += extra_item
+
+/obj/structure/destructible/cult/item_dispenser/forge/extra_options()
+ if(!cult_team?.unlocked_heretic_items[CURSED_BLADE_UNLOCKED])
+ return
+ return list(CURSED_BLADE = list(
+ PREVIEW_IMAGE = image(icon = 'icons/obj/weapons/khopesh.dmi', icon_state = "cursed_blade"),
+ OUTPUT_ITEMS = list(/obj/item/melee/sickly_blade/cursed),
+ ),
+ )
+
/obj/structure/destructible/cult/item_dispenser/forge/succcess_message(mob/living/user, obj/item/spawned_item)
to_chat(user, span_cult_italic("You work [src] as dark knowledge guides your hands, creating [spawned_item]!"))
@@ -42,3 +58,4 @@
#undef NARSIE_ARMOR
#undef FLAGELLANT_ARMOR
#undef ELDRITCH_SWORD
+#undef CURSED_BLADE
diff --git a/code/modules/antagonists/cult/cult_structures.dm b/code/modules/antagonists/cult/cult_structures.dm
index 932c3ac03c1f6..5067dcf979904 100644
--- a/code/modules/antagonists/cult/cult_structures.dm
+++ b/code/modules/antagonists/cult/cult_structures.dm
@@ -12,16 +12,43 @@
var/cult_examine_tip
/// The cooldown for when items can be dispensed.
COOLDOWN_DECLARE(use_cooldown)
+ /// Assigned cult team, set when cultistism is checked.
+ var/datum/team/cult/cult_team
+
+/obj/structure/destructible/cult/Destroy()
+ cult_team = null
+ return ..()
+
+/obj/structure/destructible/cult/Initialize(mapload)
+ . = ..()
+ RegisterSignal(src, COMSIG_ATOM_CONSTRUCTED, PROC_REF(on_constructed))
+
+/obj/structure/destructible/cult/proc/on_constructed(datum/source, mob/builder)
+ SIGNAL_HANDLER
+ var/datum/antagonist/cult/cultist = builder.mind?.has_antag_datum(/datum/antagonist/cult, TRUE)
+ cult_team = cultist?.get_team()
+
+/// Tries to find a cultist. If it succeeds, it also takes advantage of the moment to define the structure's cult team if it's not set yet.
+/obj/structure/destructible/cult/proc/is_cultist_check(mob/fool)
+
+ if(!IS_CULTIST(fool))
+ return FALSE
+
+ if(isnull(cult_team))
+ var/datum/antagonist/cult/cultist = fool.mind?.has_antag_datum(/datum/antagonist/cult, TRUE)
+ cult_team = cultist?.get_team()
+
+ return TRUE
/obj/structure/destructible/cult/examine_status(mob/user)
- if(IS_CULTIST(user) || isobserver(user))
+ if(is_cultist_check(user) || isobserver(user))
return span_cult("It's at [round(atom_integrity * 100 / max_integrity)]% stability.")
return ..()
/obj/structure/destructible/cult/examine(mob/user)
. = ..()
. += span_notice("[src] is [anchored ? "secured to":"unsecured from"] the floor.")
- if(IS_CULTIST(user) || isobserver(user))
+ if(is_cultist_check(user) || isobserver(user))
if(cult_examine_tip)
. += span_cult(cult_examine_tip)
if(!COOLDOWN_FINISHED(src, use_cooldown_duration))
@@ -65,16 +92,25 @@
/obj/structure/destructible/cult/item_dispenser
/// An associated list of options this structure can make. See setup_options() for format.
var/list/options
+ /// The dispenser will create this item and then delete itself if it is rust converted.
+ var/obj/mansus_conversion_path = /obj/item/skub
/obj/structure/destructible/cult/item_dispenser/Initialize(mapload)
. = ..()
setup_options()
+/obj/structure/destructible/cult/item_dispenser/rust_heretic_act()
+ visible_message(span_notice("[src] crumbles to dust. In its midst, you spot \a [initial(mansus_conversion_path.name)]."))
+ var/turf/turfy = get_turf(src)
+ new mansus_conversion_path(turfy)
+ turfy.rust_heretic_act()
+ return ..()
+
/obj/structure/destructible/cult/item_dispenser/attack_hand(mob/living/user, list/modifiers)
. = ..()
if(.)
return
- if(!isliving(user) || !IS_CULTIST(user))
+ if(!isliving(user) || !is_cultist_check(user))
to_chat(user, span_warning("You're pretty sure you know exactly what this is used for and you can't seem to touch it."))
return
if(!anchored)
@@ -84,6 +120,8 @@
to_chat(user, span_cult_italic("The magic in [src] is too weak, it will be ready to use again in [DisplayTimeText(COOLDOWN_TIMELEFT(src, use_cooldown))]."))
return
+ setup_options()
+
var/list/spawned_items = get_items_to_spawn(user)
if(!length(spawned_items))
return
@@ -109,6 +147,18 @@
/obj/structure/destructible/cult/item_dispenser/proc/setup_options()
return
+/*
+ * Extra options, currently used for items unlocked after sacrificing a heretic.
+ *
+ * The list of options is a associated list of format:
+ * item_name = list(
+ * preview = image(),
+ * output = list(paths),
+ * )
+ */
+/obj/structure/destructible/cult/item_dispenser/proc/extra_options()
+ return
+
/*
* Get all items that this cult building will spawn when interacted with.
* Opens a radial menu for the user and shows them the list of options, which they can choose from.
@@ -150,7 +200,7 @@
* Returns TRUE if the user is a living mob that is a cultist and is not incapacitated.
*/
/obj/structure/destructible/cult/item_dispenser/proc/check_menu(mob/user)
- return isliving(user) && IS_CULTIST(user) && !user.incapacitated()
+ return isliving(user) && is_cultist_check(user) && !user.incapacitated()
// Spooky looking door used in gateways. Or something.
/obj/effect/gateway
diff --git a/code/modules/antagonists/cult/datums/cult_team.dm b/code/modules/antagonists/cult/datums/cult_team.dm
index c47cc2145b5dc..09d4a25a321c4 100644
--- a/code/modules/antagonists/cult/datums/cult_team.dm
+++ b/code/modules/antagonists/cult/datums/cult_team.dm
@@ -16,9 +16,16 @@
var/reckoning_complete = FALSE
///Has the cult risen, and gotten red eyes?
var/cult_risen = FALSE
- ///Has the cult asceneded, and gotten halos?
+ ///Has the cult ascended, and gotten halos?
var/cult_ascendent = FALSE
+ /// List that keeps track of which items have been unlocked after a heretic was sacked.
+ var/list/unlocked_heretic_items = list(
+ CURSED_BLADE_UNLOCKED = FALSE,
+ CRIMSON_FOCUS_UNLOCKED = FALSE,
+ PROTEON_ORB_UNLOCKED = FALSE,
+ )
+
///Has narsie been summoned yet?
var/narsie_summoned = FALSE
///How large were we at max size.
diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm
index 926981bb096bb..d8ce241caf3c8 100644
--- a/code/modules/antagonists/cult/runes.dm
+++ b/code/modules/antagonists/cult/runes.dm
@@ -326,16 +326,12 @@ structure_check() searches for nearby cultist structures required for the invoca
return TRUE
/obj/effect/rune/convert/proc/do_sacrifice(mob/living/sacrificial, list/invokers, datum/team/cult/cult_team)
- var/big_sac = FALSE
+ var/target_sac = FALSE
if((((ishuman(sacrificial) || iscyborg(sacrificial)) && sacrificial.stat != DEAD) || cult_team.is_sacrifice_target(sacrificial.mind)) && length(invokers) < 3)
for(var/invoker in invokers)
to_chat(invoker, span_cult_italic("[sacrificial] is too greatly linked to the world! You need three acolytes!"))
return FALSE
- var/signal_result = SEND_SIGNAL(sacrificial, COMSIG_LIVING_CULT_SACRIFICED, invokers, cult_team)
- if(signal_result & STOP_SACRIFICE)
- return FALSE
-
if(sacrificial.mind)
LAZYADD(GLOB.sacrificed, WEAKREF(sacrificial.mind))
for(var/datum/objective/sacrifice/sac_objective in cult_team.objectives)
@@ -343,15 +339,23 @@ structure_check() searches for nearby cultist structures required for the invoca
sac_objective.sacced = TRUE
sac_objective.clear_sacrifice()
sac_objective.update_explanation_text()
- big_sac = TRUE
+ target_sac = TRUE
else
LAZYADD(GLOB.sacrificed, WEAKREF(sacrificial))
new /obj/effect/temp_visual/cult/sac(loc)
- if(!(signal_result & SILENCE_SACRIFICE_MESSAGE))
+ var/signal_result = SEND_SIGNAL(sacrificial, COMSIG_LIVING_CULT_SACRIFICED, invokers, cult_team)
+
+ var/do_message = TRUE
+ if(signal_result & SILENCE_SACRIFICE_MESSAGE)
+ do_message = FALSE
+ if((signal_result & SILENCE_NONTARGET_SACRIFICE_MESSAGE) && !(target_sac))
+ do_message = FALSE
+
+ if(do_message)
for(var/invoker in invokers)
- if(big_sac)
+ if(target_sac)
to_chat(invoker, span_cult_large("\"Yes! This is the one I desire! You have done well.\""))
continue
if(ishuman(sacrificial) || iscyborg(sacrificial))
@@ -359,6 +363,10 @@ structure_check() searches for nearby cultist structures required for the invoca
else
to_chat(invoker, span_cult_large("\"I accept this meager sacrifice.\""))
+ // post-message
+ if(signal_result & STOP_SACRIFICE)
+ return FALSE
+
if(iscyborg(sacrificial))
var/construct_class = show_radial_menu(invokers[1], sacrificial, GLOB.construct_radial_images, require_near = TRUE, tooltips = TRUE)
if(QDELETED(sacrificial) || !construct_class)
@@ -370,17 +378,20 @@ structure_check() searches for nearby cultist structures required for the invoca
sacriborg.mmi = null
qdel(sacrificial)
return TRUE
-
- var/obj/item/soulstone/stone = new(loc)
- if(sacrificial.mind && !HAS_TRAIT(sacrificial, TRAIT_SUICIDED))
- stone.capture_soul(sacrificial, invokers[1], forced = TRUE)
-
- if(sacrificial)
+ if(sacrificial && (signal_result & DUST_SACRIFICE)) // No soulstone when dusted
+ playsound(sacrificial, 'sound/magic/teleport_diss.ogg', 100, TRUE)
+ sacrificial.investigate_log("has been sacrificially dusted by the cult.", INVESTIGATE_DEATHS)
+ sacrificial.dust(TRUE, FALSE, TRUE)
+ else if (sacrificial)
+ var/obj/item/soulstone/stone = new(loc)
+ if(sacrificial.mind && !HAS_TRAIT(sacrificial, TRAIT_SUICIDED))
+ stone.capture_soul(sacrificial, invokers[1], forced = TRUE)
playsound(sacrificial, 'sound/magic/disintegrate.ogg', 100, TRUE)
sacrificial.investigate_log("has been sacrificially gibbed by the cult.", INVESTIGATE_DEATHS)
sacrificial.gib(DROP_ALL_REMAINS)
try_spawn_sword() // after sharding and gibbing, which potentially dropped a null rod
+
return TRUE
/// Tries to convert a null rod over the rune to a cult sword
@@ -396,12 +407,12 @@ structure_check() searches for nearby cultist structures required for the invoca
rod.visible_message(span_cult_italic(displayed_message))
switch(num_slain)
- if(0, 1)
+ if(0)
animate_spawn_sword(rod, /obj/item/melee/cultblade/dagger)
- if(2)
+ if(1)
animate_spawn_sword(rod, /obj/item/melee/cultblade)
else
- animate_spawn_sword(rod, /obj/item/cult_bastard)
+ animate_spawn_sword(rod, /obj/item/melee/cultblade/halberd)
return TRUE
return FALSE
diff --git a/code/modules/antagonists/cult/sword_fling.dm b/code/modules/antagonists/cult/sword_fling.dm
new file mode 100644
index 0000000000000..766f97917de60
--- /dev/null
+++ b/code/modules/antagonists/cult/sword_fling.dm
@@ -0,0 +1,93 @@
+
+/datum/action/cooldown/spell/pointed/sword_fling
+ name = "Sword Fling"
+ desc = "Try to fling yourself around."
+ ranged_mousepointer = 'icons/effects/mouse_pointers/cult_target.dmi'
+ background_icon_state = "bg_heretic"
+ overlay_icon_state = "bg_cult_border"
+
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
+ button_icon_state = "sword_fling"
+
+ school = SCHOOL_EVOCATION
+ cooldown_time = 4 SECONDS
+ invocation_type = INVOCATION_NONE
+ spell_requirements = NONE
+
+ cast_range = 6
+ active_msg = "You ready yourself to attempt to leap!"
+ var/obj/item/flinged_sword
+
+/datum/action/cooldown/spell/pointed/sword_fling/New(Target, to_fling)
+ . = ..()
+ flinged_sword = to_fling
+
+/datum/action/cooldown/spell/pointed/sword_fling/Destroy()
+ flinged_sword = null
+ . = ..()
+
+/datum/action/cooldown/spell/pointed/sword_fling/is_valid_target(atom/cast_on)
+ return isatom(cast_on)
+
+/datum/action/cooldown/spell/pointed/sword_fling/cast(turf/cast_on)
+ . = ..()
+ var/atom/sword_loc = flinged_sword.loc
+ if(ismob(sword_loc))
+ var/mob/loccer = sword_loc
+ var/resist_chance = 25
+ var/fail_text = "You struggle, but [loccer] keeps [loccer.p_their()] grip on you!"
+ var/particle_to_spawn = null
+ if(IS_CULTIST_OR_CULTIST_MOB(loccer))
+ resist_chance = 10 // your mastahs
+ fail_text = "You struggle, but [loccer]'s grip is unnaturally hard to resist!"
+ particle_to_spawn = /obj/effect/temp_visual/cult/sparks
+ if(IS_HERETIC_OR_MONSTER(loccer) || IS_LUNATIC(loccer))
+ resist_chance = 15
+ fail_text = "You struggle, but [loccer] deftly handles the grip movement."
+ particle_to_spawn = /obj/effect/temp_visual/eldritch_sparks
+ if(loccer.mind?.holy_role) // IS_PRIEST()
+ resist_chance = 12
+ fail_text = "You struggle, but [loccer]'s holy grip holds tight against your thrashing."
+ particle_to_spawn = /obj/effect/temp_visual/blessed
+ if(IS_WIZARD(loccer))
+ resist_chance = 5 // magic master
+ fail_text = "You struggle, but [loccer]'s handle on magic easily neutralizes your movement."
+ particle_to_spawn = /obj/effect/particle_effect/sparks/electricity
+
+ new particle_to_spawn(get_turf(loccer))
+
+ if(prob(resist_chance))
+ flinged_sword.forceMove(get_turf(loccer))
+ flinged_sword.visible_message(span_alert("\the [flinged_sword] yanks itself out of [loccer]'s grip!"))
+ // flung by later code
+ else
+ to_chat(owner, span_warning(fail_text))
+ return
+
+ if(isitem(sword_loc))
+ flinged_sword.forceMove(get_turf(sword_loc))
+ flinged_sword.visible_message(span_alert("\the [flinged_sword] yanks itself out of [sword_loc]!"))
+ // flung by later code
+
+ if(iscloset(sword_loc))
+ var/obj/structure/closet/sword_closet = sword_loc
+ if(!(sword_closet.open(owner, force = prob(5), special_effects = TRUE)))
+ sword_closet.container_resist_act(owner, loc_required = FALSE)
+ flinged_sword.visible_message(span_alert("\the [flinged_sword] yanks itself out of [sword_closet]!"))
+
+ // no general struct/machinery check. imagine if someone put the sword in a vendor
+
+ if(isturf(sword_loc))
+ new /obj/effect/temp_visual/sword_sparks(sword_loc)
+ flinged_sword.throw_at(cast_on, cast_range, flinged_sword.throw_speed, owner)
+ flinged_sword.visible_message(\
+ span_warning("\the [flinged_sword] lunges at \the [cast_on]!"))
+
+/obj/effect/temp_visual/eldritch_sparks
+ icon_state = "purplesparkles"
+
+/obj/effect/temp_visual/sword_sparks
+ icon_state = "mech_toxin" // only used in one place and it looks kinda good
+
+/obj/effect/temp_visual/blessed
+ icon_state = "blessed"
diff --git a/code/modules/antagonists/fugitive/fugitive_outfits.dm b/code/modules/antagonists/fugitive/fugitive_outfits.dm
index ed256acae03e7..e1530ba16eddd 100644
--- a/code/modules/antagonists/fugitive/fugitive_outfits.dm
+++ b/code/modules/antagonists/fugitive/fugitive_outfits.dm
@@ -75,7 +75,7 @@
back = /obj/item/storage/backpack/satchel/leather
shoes = /obj/item/clothing/shoes/laceup
glasses = /obj/item/clothing/glasses/monocle
- mask = /obj/item/clothing/mask/cigarette/pipe
+ mask = /obj/item/cigarette/pipe
ears = /obj/item/radio/headset
backpack_contents = list(
diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm
index 2c31529ed3386..3411384b7b8fe 100644
--- a/code/modules/antagonists/heretic/heretic_antag.dm
+++ b/code/modules/antagonists/heretic/heretic_antag.dm
@@ -85,6 +85,15 @@
PATH_MOON = COLOR_BLUE_LIGHT,
)
+ /// List that keeps track of which items have been gifted to the heretic after a cultist was sacrificed. Used to alter drop chances to reduce dupes.
+ var/list/unlocked_heretic_items = list(
+ /obj/item/melee/sickly_blade/cursed = 0,
+ /obj/item/clothing/neck/heretic_focus/crimson_focus = 0,
+ /mob/living/basic/construct/harvester/heretic = 0,
+ )
+ /// Simpler version of above used to limit amount of loot that can be hoarded
+ var/rewards_given = 0
+
/datum/antagonist/heretic/Destroy()
LAZYNULL(sac_targets)
return ..()
@@ -230,6 +239,8 @@
if (!issilicon(our_mob))
GLOB.reality_smash_track.add_tracked_mind(owner)
+ ADD_TRAIT(our_mob, TRAIT_MANSUS_TOUCHED, REF(src))
+ RegisterSignal(our_mob, COMSIG_LIVING_CULT_SACRIFICED, PROC_REF(on_cult_sacrificed))
RegisterSignals(our_mob, list(COMSIG_MOB_BEFORE_SPELL_CAST, COMSIG_MOB_SPELL_ACTIVATED), PROC_REF(on_spell_cast))
RegisterSignal(our_mob, COMSIG_USER_ITEM_INTERACTION, PROC_REF(on_item_use))
RegisterSignal(our_mob, COMSIG_MOB_LOGIN, PROC_REF(fix_influence_network))
@@ -243,12 +254,14 @@
if (owner in GLOB.reality_smash_track.tracked_heretics)
GLOB.reality_smash_track.remove_tracked_mind(owner)
+ REMOVE_TRAIT(our_mob, TRAIT_MANSUS_TOUCHED, REF(src))
UnregisterSignal(our_mob, list(
COMSIG_MOB_BEFORE_SPELL_CAST,
COMSIG_MOB_SPELL_ACTIVATED,
COMSIG_USER_ITEM_INTERACTION,
COMSIG_MOB_LOGIN,
COMSIG_LIVING_POST_FULLY_HEAL,
+ COMSIG_LIVING_CULT_SACRIFICED,
))
/datum/antagonist/heretic/on_body_transfer(mob/living/old_body, mob/living/new_body)
@@ -395,6 +408,118 @@
var/datum/heretic_knowledge/living_heart/heart_knowledge = get_knowledge(/datum/heretic_knowledge/living_heart)
heart_knowledge.on_research(source, src)
+/// Signal proc for [COMSIG_LIVING_CULT_SACRIFICED] to reward cultists for sacrificing a heretic
+/datum/antagonist/heretic/proc/on_cult_sacrificed(mob/living/source, list/invokers)
+ SIGNAL_HANDLER
+
+ for(var/mob/dead/observer/ghost in GLOB.dead_mob_list) // uhh let's find the guy to shove him back in
+ if((ghost.mind?.current == source) && ghost.client) // is it the same guy and do they have the same client
+ ghost.reenter_corpse() // shove them in! it doesnt do it automatically
+
+ // Drop all items and splatter them around messily.
+ var/list/dustee_items = source.unequip_everything()
+ for(var/obj/item/loot as anything in dustee_items)
+ loot.throw_at(get_step_rand(source), 2, 4, pick(invokers), TRUE)
+
+ // Create the blade, give it the heretic and a randomly-chosen master for the soul sword component
+ var/obj/item/melee/cultblade/haunted/haunted_blade = new(get_turf(source), source, pick(invokers))
+
+ // Cool effect for the rune as well as the item
+ var/obj/effect/rune/convert/conversion_rune = locate() in get_turf(source)
+ if(conversion_rune)
+ conversion_rune.gender_reveal(
+ outline_color = COLOR_HERETIC_GREEN,
+ ray_color = null,
+ do_float = FALSE,
+ do_layer = FALSE,
+ )
+
+ haunted_blade.gender_reveal(outline_color = null, ray_color = COLOR_HERETIC_GREEN)
+
+ for(var/mob/living/culto as anything in invokers)
+ to_chat(culto, span_cult_large("\"A follower of the forgotten gods! You must be rewarded for such a valuable sacrifice.\""))
+
+ // Locate a cultist team (Is there a better way??)
+ var/mob/living/random_cultist = pick(invokers)
+ var/datum/antagonist/cult/antag = random_cultist.mind.has_antag_datum(/datum/antagonist/cult)
+ ASSERT(antag)
+ var/datum/team/cult/cult_team = antag.get_team()
+
+ // Unlock one of 3 special items!
+ var/list/possible_unlocks
+ for(var/i in cult_team.unlocked_heretic_items)
+ if(cult_team.unlocked_heretic_items[i])
+ continue
+ LAZYADD(possible_unlocks, i)
+ if(length(possible_unlocks))
+ var/result = pick(possible_unlocks)
+ cult_team.unlocked_heretic_items[result] = TRUE
+
+ for(var/datum/mind/mind as anything in cult_team.members)
+ if(mind.current)
+ SEND_SOUND(mind.current, 'sound/magic/clockwork/narsie_attack.ogg')
+ to_chat(mind.current, span_cult_large(span_warning("Arcane and forbidden knowledge floods your forges and archives. The cult has learned how to create the ")) + span_cult_large(span_hypnophrase("[result]!")))
+
+ return SILENCE_SACRIFICE_MESSAGE|DUST_SACRIFICE
+
+/**
+ * Creates an animation of the item slowly lifting up from the floor with a colored outline, then slowly drifting back down.
+ * Arguments:
+ * * outline_color: Default is between pink and light blue, is the color of the outline filter.
+ * * ray_color: Null by default. If not set, just copies outline. Used for the ray filter.
+ * * anim_time: Total time of the animation. Split into two different calls.
+ * * do_float: Lets you disable the sprite floating up and down.
+ * * do_layer: Lets you disable the layering increase.
+ */
+/obj/proc/gender_reveal(
+ outline_color = null,
+ ray_color = null,
+ anim_time = 10 SECONDS,
+ do_float = TRUE,
+ do_layer = TRUE,
+)
+
+ var/og_layer
+ if(do_layer)
+ // Layering above to stand out!
+ og_layer = layer
+ layer = ABOVE_MOB_LAYER
+
+ // Slowly floats up, then slowly goes down.
+ if(do_float)
+ animate(src, pixel_y = 12, time = anim_time * 0.5, easing = QUAD_EASING | EASE_OUT)
+ animate(pixel_y = 0, time = anim_time * 0.5, easing = QUAD_EASING | EASE_IN)
+
+ // Adding a cool outline effect
+ if(outline_color)
+ add_filter("gender_reveal_outline", 3, list("type" = "outline", "color" = outline_color, "size" = 0.5))
+ // Animating it!
+ var/gay_filter = get_filter("gender_reveal_outline")
+ animate(gay_filter, alpha = 110, time = 1.5 SECONDS, loop = -1)
+ animate(alpha = 40, time = 2.5 SECONDS)
+
+ // Adding a cool ray effect
+ if(ray_color)
+ add_filter(name = "gender_reveal_ray", priority = 1, params = list(
+ type = "rays",
+ size = 45,
+ color = ray_color,
+ density = 6
+ ))
+ // Animating it!
+ var/ray_filter = get_filter("gender_reveal_ray")
+ // I understand nothing but copypaste saves lives
+ animate(ray_filter, offset = 100, time = 30 SECONDS, loop = -1, flags = ANIMATION_PARALLEL)
+
+ addtimer(CALLBACK(src, PROC_REF(remove_gender_reveal_fx), og_layer), anim_time)
+
+/**
+ * Removes the non-animate effects from above proc
+ */
+/obj/proc/remove_gender_reveal_fx(og_layer)
+ remove_filter(list("gender_reveal_outline", "gender_reveal_ray"))
+ layer = og_layer
+
/**
* Create our objectives for our heretic.
*/
diff --git a/code/modules/antagonists/heretic/heretic_knowledge.dm b/code/modules/antagonists/heretic/heretic_knowledge.dm
index 5369e5fee8d91..6758b0774046b 100644
--- a/code/modules/antagonists/heretic/heretic_knowledge.dm
+++ b/code/modules/antagonists/heretic/heretic_knowledge.dm
@@ -38,6 +38,8 @@
var/priority = 0
/// What path is this on. If set to "null", assumed to be unreachable (or abstract).
var/route
+ ///Determines what kind of monster ghosts will ignore from here on out. Defaults to POLL_IGNORE_HERETIC_MONSTER, but we define other types of monsters for more granularity.
+ var/poll_ignore_define = POLL_IGNORE_HERETIC_MONSTER
/datum/heretic_knowledge/New()
if(!mutually_exclusive)
@@ -523,11 +525,23 @@
abstract_parent_type = /datum/heretic_knowledge/summon
/// Typepath of a mob to summon when we finish the recipe.
var/mob/living/mob_to_summon
- ///Determines what kind of monster ghosts will ignore from here on out. Defaults to POLL_IGNORE_HERETIC_MONSTER, but we define other types of monsters for more granularity.
- var/poll_ignore_define = POLL_IGNORE_HERETIC_MONSTER
/datum/heretic_knowledge/summon/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
- var/mob/living/summoned = new mob_to_summon(loc)
+ summon_ritual_mob(user, loc, mob_to_summon)
+
+/**
+ * Creates the ritual mob and grabs a ghost for it
+ *
+ * * user - the mob doing the summoning
+ * * loc - where the summon is happening
+ * * mob_to_summon - either a mob instance or a mob typepath
+ */
+/datum/heretic_knowledge/proc/summon_ritual_mob(mob/living/user, turf/loc, mob/living/mob_to_summon)
+ var/mob/living/summoned
+ if(isliving(mob_to_summon))
+ summoned = mob_to_summon
+ else
+ summoned = new mob_to_summon(loc)
summoned.ai_controller?.set_ai_status(AI_STATUS_OFF)
// Fade in the summon while the ghost poll is ongoing.
// Also don't let them mess with the summon while waiting
@@ -557,6 +571,7 @@
var/datum/antagonist/heretic_monster/heretic_monster = summoned.mind.add_antag_datum(/datum/antagonist/heretic_monster)
heretic_monster.set_owner(user.mind)
+ summoned.RegisterSignal(user, COMSIG_LIVING_DEATH, TYPE_PROC_REF(/mob/living/, on_master_death))
var/datum/objective/heretic_summon/summon_objective = locate() in user.mind.get_all_objectives()
summon_objective?.num_summoned++
diff --git a/code/modules/antagonists/heretic/heretic_monsters.dm b/code/modules/antagonists/heretic/heretic_monsters.dm
index 31b18b6a83353..fcdea51287980 100644
--- a/code/modules/antagonists/heretic/heretic_monsters.dm
+++ b/code/modules/antagonists/heretic/heretic_monsters.dm
@@ -38,3 +38,7 @@
owner.announce_objectives()
to_chat(owner, span_boldnotice("You are a [ishuman(owner.current) ? "shambling corpse returned":"horrible creation brought"] to this plane through the Gates of the Mansus."))
to_chat(owner, span_notice("Your master is [master]. Assist them to all ends."))
+
+ if(istype(owner.current, /mob/living/basic/construct/harvester/heretic))
+ var/mob/living/basic/construct/harvester/heretic/shitcode = owner.current
+ shitcode.master = master
diff --git a/code/modules/antagonists/heretic/items/heretic_blades.dm b/code/modules/antagonists/heretic/items/heretic_blades.dm
index 675f5f87b0abf..ddfec8db20cf7 100644
--- a/code/modules/antagonists/heretic/items/heretic_blades.dm
+++ b/code/modules/antagonists/heretic/items/heretic_blades.dm
@@ -24,23 +24,37 @@
attack_verb_simple = list("attack", "slash", "stab", "slice", "tear", "lacerate", "rip", "dice", "rend")
var/after_use_message = ""
+/obj/item/melee/sickly_blade/examine(mob/user)
+ . = ..()
+ if(!check_usability(user))
+ return
+
+ . += span_notice("You can shatter the blade to teleport to a random, (mostly) safe location by activating it in-hand.")
+
+/// Checks if the passed mob can use this blade without being stunned
+/obj/item/melee/sickly_blade/proc/check_usability(mob/living/user)
+ return IS_HERETIC_OR_MONSTER(user)
+
/obj/item/melee/sickly_blade/pre_attack(atom/A, mob/living/user, params)
. = ..()
if(.)
return .
- if(!IS_HERETIC_OR_MONSTER(user))
+ if(!check_usability(user))
to_chat(user, span_danger("You feel a pulse of alien intellect lash out at your mind!"))
- user.AdjustParalyzed(5 SECONDS)
+ var/mob/living/carbon/human/human_user = user
+ human_user.AdjustParalyzed(5 SECONDS)
return TRUE
- return .
-/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, click_parameters)
- if(isliving(target))
- SEND_SIGNAL(user, COMSIG_HERETIC_BLADE_ATTACK, target, src)
+ return .
/obj/item/melee/sickly_blade/attack_self(mob/user)
- var/turf/safe_turf = find_safe_turf(zlevel = z, extended_safety_checks = TRUE)
- if(IS_HERETIC_OR_MONSTER(user))
+ seek_safety(user)
+ return ..()
+
+/// Attempts to teleport the passed mob to somewhere safe on the station, if they can use the blade.
+/obj/item/melee/sickly_blade/proc/seek_safety(mob/user)
+ var/turf/safe_turf = find_safe_turf(zlevels = z, extended_safety_checks = TRUE)
+ if(check_usability(user))
if(do_teleport(user, safe_turf, channel = TELEPORT_CHANNEL_MAGIC))
to_chat(user, span_warning("As you shatter [src], you feel a gust of energy flow through your body. [after_use_message]"))
else
@@ -50,18 +64,15 @@
playsound(src, SFX_SHATTER, 70, TRUE) //copied from the code for smashing a glass sheet onto the ground to turn it into a shard
qdel(src)
+/obj/item/melee/sickly_blade/afterattack(atom/target, mob/user, click_parameters)
+ if(isliving(target))
+ SEND_SIGNAL(user, COMSIG_HERETIC_BLADE_ATTACK, target, src)
+
/obj/item/melee/sickly_blade/ranged_interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers)
if(isliving(interacting_with))
SEND_SIGNAL(user, COMSIG_HERETIC_RANGED_BLADE_ATTACK, interacting_with, src)
return ITEM_INTERACT_BLOCKING
-/obj/item/melee/sickly_blade/examine(mob/user)
- . = ..()
- if(!IS_HERETIC_OR_MONSTER(user))
- return
-
- . += span_notice("You can shatter the blade to teleport to a random, (mostly) safe location by activating it in-hand.")
-
// Path of Rust's blade
/obj/item/melee/sickly_blade/rust
name = "\improper rusted blade"
@@ -154,3 +165,76 @@
icon_state = "moon_blade"
inhand_icon_state = "moon_blade"
after_use_message = "The Moon hears your call..."
+
+// Path of Nar'Sie's blade
+// What!? This blade is given to cultists as an altar item when they sacrifice a heretic.
+// It is also given to the heretic themself if they sacrifice a cultist.
+/obj/item/melee/sickly_blade/cursed
+ name = "\improper cursed blade"
+ desc = "A dark blade, cursed to bleed forever. In constant struggle between the eldritch and the dark, it is forced to accept any wielder as its master. \
+ Its eye's cornea drips blood endlessly into the ground, yet its piercing gaze remains on you."
+ force = 25
+ throwforce = 15
+ block_chance = 35
+ wound_bonus = 25
+ bare_wound_bonus = 15
+ armour_penetration = 35
+ icon_state = "cursed_blade"
+ inhand_icon_state = "cursed_blade"
+
+/obj/item/melee/sickly_blade/cursed/Initialize(mapload)
+ . = ..()
+
+ var/examine_text = {"Allows the scribing of blood runes of the cult of Nar'Sie.
+ The combination of eldritch power and Nar'Sie's might allows for vastly increased rune drawing speed,
+ alongside the vicious strength of the blade being more powerful than usual.\n
+ It can also be shattered in-hand by cultists (via right-click), teleporting them to relative safety."}
+
+ AddComponent(/datum/component/cult_ritual_item, span_cult(examine_text), turfs_that_boost_us = /turf) // Always fast to draw!
+
+/obj/item/melee/sickly_blade/cursed/attack_self_secondary(mob/user)
+ seek_safety(user, TRUE)
+
+/obj/item/melee/sickly_blade/cursed/seek_safety(mob/user, secondary_attack = FALSE)
+ if(IS_CULTIST(user) && !secondary_attack)
+ return FALSE
+ return ..()
+
+/obj/item/melee/sickly_blade/cursed/check_usability(mob/living/user)
+ if(IS_HERETIC_OR_MONSTER(user) || IS_CULTIST(user))
+ return TRUE
+ if(prob(15))
+ to_chat(user, span_cult_large(pick("\"An untouched mind? Amusing.\"", "\" I suppose it isn't worth the effort to stop you.\"", "\"Go ahead. I don't care.\"", "\"You'll be mine soon enough.\"")))
+ var/obj/item/bodypart/affecting = user.get_active_hand()
+ if(!affecting)
+ return
+ affecting.receive_damage(burn = 5)
+ playsound(src, SFX_SEAR, 25, TRUE)
+ to_chat(user, span_danger("Your hand sizzles.")) // Nar nar might not care but their essence still doesn't like you
+ else if(prob(15))
+ to_chat(user, span_big(span_hypnophrase("LW'NAFH'NAHOR UH'ENAH'YMG EPGOKA AH NAFL MGEMPGAH'EHYE")))
+ to_chat(user, span_danger("Horrible, unintelligible utterances flood your mind!"))
+ user.adjustOrganLoss(ORGAN_SLOT_BRAIN, 15) // This can kill you if you ignore it
+ return TRUE
+
+/obj/item/melee/sickly_blade/cursed/equipped(mob/user, slot)
+ . = ..()
+ if(IS_HERETIC_OR_MONSTER(user))
+ after_use_message = "The Mansus hears your call..."
+ else if(IS_CULTIST(user))
+ after_use_message = "Nar'Sie hears your call..."
+ else
+ after_use_message = null
+
+/obj/item/melee/sickly_blade/cursed/interact_with_atom(atom/target, mob/living/user, list/modifiers)
+ . = ..()
+
+ var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
+ if(!heretic_datum)
+ return NONE
+
+ // Can only carve runes with it if off combat mode.
+ if(isopenturf(target) && !user.combat_mode)
+ heretic_datum.try_draw_rune(user, target, drawing_time = 14 SECONDS) // Faster than pen, slower than cicatrix
+ return ITEM_INTERACT_BLOCKING
+ return NONE
diff --git a/code/modules/antagonists/heretic/items/heretic_necks.dm b/code/modules/antagonists/heretic/items/heretic_necks.dm
index e24c17abdeeba..3f140dc99df1d 100644
--- a/code/modules/antagonists/heretic/items/heretic_necks.dm
+++ b/code/modules/antagonists/heretic/items/heretic_necks.dm
@@ -9,6 +9,101 @@
. = ..()
AddElement(/datum/element/heretic_focus)
+/obj/item/clothing/neck/heretic_focus/crimson_focus
+ name = "Crimson Focus"
+ desc = "A blood-red focusing glass that provides a link to the world beyond, and worse. Its eye is constantly twitching and gazing in all directions. It almost seems to be silently screaming..."
+ icon_state = "crimson_focus"
+ /// The aura healing component. Used to delete it when taken off.
+ var/datum/component/component
+ /// If active or not, used to add and remove its cult and heretic buffs.
+ var/active = FALSE
+
+/obj/item/clothing/neck/heretic_focus/crimson_focus/equipped(mob/living/user, slot)
+ . = ..()
+ if(!(slot & ITEM_SLOT_NECK))
+ return
+
+ var/team_color = COLOR_ADMIN_PINK
+ if(IS_CULTIST(user))
+ var/datum/action/innate/cult/blood_magic/magic_holder = locate() in user.actions
+ team_color = COLOR_CULT_RED
+ magic_holder.magic_enhanced = TRUE
+ else if(IS_HERETIC_OR_MONSTER(user) && !active)
+ for(var/datum/action/cooldown/spell/spell_action in user.actions)
+ spell_action.cooldown_time *= 0.5
+ active = TRUE
+ team_color = COLOR_GREEN
+ else
+ team_color = pick(COLOR_CULT_RED, COLOR_GREEN)
+
+ user.add_traits(list(TRAIT_MANSUS_TOUCHED, TRAIT_BLOODY_MESS), REF(src))
+ to_chat(user, span_alert("Your heart takes on a strange yet soothing irregular rhythm, and your blood feels significantly less viscous than it used to be. You're not sure if that's a good thing."))
+ component = user.AddComponent( \
+ /datum/component/aura_healing, \
+ range = 3, \
+ brute_heal = 1, \
+ burn_heal = 1, \
+ blood_heal = 2, \
+ suffocation_heal = 5, \
+ simple_heal = 0.6, \
+ requires_visibility = FALSE, \
+ limit_to_trait = TRAIT_MANSUS_TOUCHED, \
+ healing_color = team_color, \
+ )
+
+/obj/item/clothing/neck/heretic_focus/crimson_focus/dropped(mob/living/user)
+ . = ..()
+
+ if(!istype(user))
+ return
+
+ if(HAS_TRAIT_FROM(user, TRAIT_MANSUS_TOUCHED, REF(src)))
+ to_chat(user, span_notice("Your heart and blood return to their regular old rhythm and flow."))
+
+ if(IS_HERETIC_OR_MONSTER(user) && active)
+ for(var/datum/action/cooldown/spell/spell_action in user.actions)
+ spell_action.cooldown_time *= 2
+ active = FALSE
+ QDEL_NULL(component)
+ user.remove_traits(list(TRAIT_MANSUS_TOUCHED, TRAIT_BLOODY_MESS), REF(src))
+
+ // If boosted enable is set, to prevent false dropped() calls from repeatedly nuking the max spells.
+ var/datum/action/innate/cult/blood_magic/magic_holder = locate() in user.actions
+ // Remove the last spell if over new limit, as we will reduce our max spell amount. Done beforehand as it causes a index out of bounds runtime otherwise.
+ if(magic_holder?.magic_enhanced)
+ QDEL_NULL(magic_holder.spells[ENHANCED_BLOODCHARGE])
+ magic_holder?.magic_enhanced = FALSE
+
+
+/obj/item/clothing/neck/heretic_focus/crimson_focus/attack_self(mob/living/user, modifiers)
+ . = ..()
+ to_chat(user, span_danger("You start tightly squeezing [src]..."))
+ if(!do_after(user, 1.25 SECONDS, src))
+ return
+ to_chat(user, span_danger("[src] explodes into a shower of gore and blood, drenching your arm. You can feel the blood seeping into your skin. You inmediately feel better, but soon, the feeling turns hollow as your veins itch."))
+ new /obj/effect/gibspawner/generic(get_turf(src))
+ var/heal_amt = user.adjustBruteLoss(-50)
+ user.adjustFireLoss( -(50 - abs(heal_amt)) ) // no double dipping
+
+ // I want it to poison the user but I also think it'd be neat if they got their juice as well. But that cancels most of the damage out. So I dunno.
+ user.reagents?.add_reagent(/datum/reagent/fuel/unholywater, rand(6, 10))
+ user.reagents?.add_reagent(/datum/reagent/eldritch, rand(6, 10))
+ qdel(src)
+
+/obj/item/clothing/neck/heretic_focus/crimson_focus/examine(mob/user)
+ . = ..()
+
+ var/magic_dude
+ if(IS_CULTIST(user))
+ . += span_cult_bold("This focus will allow you to store one extra spell and halve the empowering time, alongside providing a small regenerative effect.")
+ magic_dude = TRUE
+ if(IS_HERETIC_OR_MONSTER(user))
+ . += span_notice("This focus will halve your spell cooldowns, alongside granting a small regenerative effect to any nearby heretics or monsters, including you.")
+ magic_dude = TRUE
+
+ if(magic_dude)
+ . += span_red("You can also squeeze it to recover a large amount of health quickly, at a cost...")
+
/obj/item/clothing/neck/eldritch_amulet
name = "Warm Eldritch Medallion"
desc = "A strange medallion. Peering through the crystalline surface, the world around you melts away. You see your own beating heart, and the pulsing of a thousand others."
diff --git a/code/modules/antagonists/heretic/knowledge/rust_lore.dm b/code/modules/antagonists/heretic/knowledge/rust_lore.dm
index fe553c8b8c779..5a10b55d1c8f4 100644
--- a/code/modules/antagonists/heretic/knowledge/rust_lore.dm
+++ b/code/modules/antagonists/heretic/knowledge/rust_lore.dm
@@ -73,7 +73,7 @@
SIGNAL_HANDLER
// Rusting an airlock causes it to lose power, mostly to prevent the airlock from shocking you.
- // This is a bit of a hack, but fixing this would require the enture wire cut/pulse system to be reworked.
+ // This is a bit of a hack, but fixing this would require the entire wire cut/pulse system to be reworked.
if(istype(target, /obj/machinery/door/airlock))
var/obj/machinery/door/airlock/airlock = target
airlock.loseMainPower()
@@ -95,56 +95,10 @@
route = PATH_RUST
/datum/heretic_knowledge/rust_regen/on_gain(mob/user, datum/antagonist/heretic/our_heretic)
- RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
- RegisterSignal(user, COMSIG_LIVING_LIFE, PROC_REF(on_life))
+ user.AddElement(/datum/element/leeching_walk)
/datum/heretic_knowledge/rust_regen/on_lose(mob/user, datum/antagonist/heretic/our_heretic)
- UnregisterSignal(user, list(COMSIG_MOVABLE_MOVED, COMSIG_LIVING_LIFE))
-
-/*
- * Signal proc for [COMSIG_MOVABLE_MOVED].
- *
- * Checks if we should have baton resistance on the new turf.
- */
-/datum/heretic_knowledge/rust_regen/proc/on_move(mob/source, atom/old_loc, dir, forced, list/old_locs)
- SIGNAL_HANDLER
-
- var/turf/mover_turf = get_turf(source)
- if(HAS_TRAIT(mover_turf, TRAIT_RUSTY))
- ADD_TRAIT(source, TRAIT_BATON_RESISTANCE, type)
- return
-
- REMOVE_TRAIT(source, TRAIT_BATON_RESISTANCE, type)
-
-/**
- * Signal proc for [COMSIG_LIVING_LIFE].
- *
- * Gradually heals the heretic ([source]) on rust,
- * including baton knockdown and stamina damage.
- */
-/datum/heretic_knowledge/rust_regen/proc/on_life(mob/living/source, seconds_per_tick, times_fired)
- SIGNAL_HANDLER
-
- var/turf/our_turf = get_turf(source)
- if(!HAS_TRAIT(our_turf, TRAIT_RUSTY))
- return
-
- // Heals all damage + Stamina
- var/need_mob_update = FALSE
- need_mob_update += source.adjustBruteLoss(-3, updating_health = FALSE)
- need_mob_update += source.adjustFireLoss(-3, updating_health = FALSE)
- need_mob_update += source.adjustToxLoss(-3, updating_health = FALSE, forced = TRUE) // Slimes are people too
- need_mob_update += source.adjustOxyLoss(-1.5, updating_health = FALSE)
- need_mob_update += source.adjustStaminaLoss(-10, updating_stamina = FALSE)
- if(need_mob_update)
- source.updatehealth()
- // Reduces duration of stuns/etc
- source.AdjustAllImmobility(-0.5 SECONDS)
- // Heals blood loss
- if(source.blood_volume < BLOOD_VOLUME_NORMAL)
- source.blood_volume += 2.5 * seconds_per_tick
- // Slowly regulates your body temp
- source.adjust_bodytemperature((source.get_body_temp_normal() - source.bodytemperature)/5)
+ user.RemoveElement(/datum/element/leeching_walk)
/datum/heretic_knowledge/mark/rust_mark
name = "Mark of Rust"
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
index 1d2be465b3026..b35d34839dabc 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_knowledge.dm
@@ -80,8 +80,11 @@
// If we have targets, we can check to see if we can do a sacrifice
// Let's remove any humans in our atoms list that aren't a sac target
for(var/mob/living/carbon/human/sacrifice in atoms)
- // If the mob's not in soft crit or worse, or isn't one of the sacrifices, remove it from the list
- if(sacrifice.stat < SOFT_CRIT || !(sacrifice in heretic_datum.sac_targets))
+ // If the mob's not in soft crit or worse, remove from list
+ if(sacrifice.stat < SOFT_CRIT)
+ atoms -= sacrifice
+ // Otherwise if it's neither a target nor a cultist, remove it
+ else if(!(sacrifice in heretic_datum.sac_targets) && !IS_CULTIST(sacrifice))
atoms -= sacrifice
// Finally, return TRUE if we have a target in the list
@@ -94,7 +97,9 @@
/datum/heretic_knowledge/hunt_and_sacrifice/on_finished_recipe(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
- if(!LAZYLEN(heretic_datum.sac_targets))
+ // Force it to work if the sacrifice is a cultist, even if there's no targets.
+ var/mob/living/carbon/human/sac = selected_atoms[1]
+ if(!LAZYLEN(heretic_datum.sac_targets) && !IS_CULTIST(sac))
if(obtain_targets(user, heretic_datum = heretic_datum))
return TRUE
else
@@ -183,34 +188,128 @@
* * selected_atoms - a list of all atoms chosen. Should be (at least) one human.
* * loc - the turf the sacrifice is occuring on
*/
-/datum/heretic_knowledge/hunt_and_sacrifice/proc/sacrifice_process(mob/living/user, list/selected_atoms)
+/datum/heretic_knowledge/hunt_and_sacrifice/proc/sacrifice_process(mob/living/user, list/selected_atoms, turf/loc)
var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
var/mob/living/carbon/human/sacrifice = locate() in selected_atoms
if(!sacrifice)
CRASH("[type] sacrifice_process didn't have a human in the atoms list. How'd it make it so far?")
- if(!(sacrifice in heretic_datum.sac_targets))
- CRASH("[type] sacrifice_process managed to get a non-target human. This is incorrect.")
+ if(!(sacrifice in heretic_datum.sac_targets) && !IS_CULTIST(sacrifice))
+ CRASH("[type] sacrifice_process managed to get a non-target, non-cult human. This is incorrect.")
if(sacrifice.mind)
LAZYADD(target_blacklist, sacrifice.mind)
heretic_datum.remove_sacrifice_target(sacrifice)
+
var/feedback = "Your patrons accept your offer"
var/sac_job_flag = sacrifice.mind?.assigned_role?.job_flags | sacrifice.last_mind?.assigned_role?.job_flags
- if(sac_job_flag & JOB_HEAD_OF_STAFF)
- heretic_datum.knowledge_points++
+ var/datum/antagonist/cult/cultist_datum = IS_CULTIST(sacrifice)
+ // Heads give 3 points, cultists give 1 point (and a special reward), normal sacrifices give 2 points.
+ heretic_datum.total_sacrifices++
+ if((sac_job_flag & JOB_HEAD_OF_STAFF))
+ heretic_datum.knowledge_points += 3
heretic_datum.high_value_sacrifices++
feedback += " graciously"
+ else if(cultist_datum)
+ heretic_datum.knowledge_points += 1
+ grant_reward(user, sacrifice, loc)
+ // easier to read
+ var/rewards_given = heretic_datum.rewards_given
+ // Chance for it to send a warning to cultists, higher with each reward. Stops after 5 because they probably got the hint by then.
+ if(prob(min(15 * rewards_given)) && (rewards_given <= 5))
+ for(var/datum/mind/mind as anything in cultist_datum.cult_team.members)
+ if(mind.current)
+ SEND_SOUND(mind.current, 'sound/magic/clockwork/narsie_attack.ogg')
+ var/message = span_narsie("A vile heretic has ") + \
+ span_cult_large(span_hypnophrase("sacrificed")) + \
+ span_narsie(" one of our own. Destroy and sacrifice the infidel before it claims more!")
+ to_chat(mind.current, message)
+ // he(retic) gets a warn too
+ var/message = span_cult_bold("You feel that your action has attracted") + \
+ span_cult_bold_italic(" attention.")
+ to_chat(user, message)
+ return
+ else
+ heretic_datum.knowledge_points += 2
to_chat(user, span_hypnophrase("[feedback]."))
- heretic_datum.total_sacrifices++
- heretic_datum.knowledge_points += 2
+ if(!begin_sacrifice(sacrifice))
+ disembowel_target(sacrifice)
+ return
sacrifice.apply_status_effect(/datum/status_effect/heretic_curse, user)
- if(!begin_sacrifice(sacrifice))
- disembowel_target(sacrifice)
+
+/datum/heretic_knowledge/hunt_and_sacrifice/proc/grant_reward(mob/living/user, mob/living/sacrifice, turf/loc)
+
+ // Visible and audible encouragement!
+ to_chat(user, span_big(span_hypnophrase("A servant of the Sanguine Apostate!")))
+ to_chat(user, span_hierophant("Your patrons are rapturous!"))
+ playsound(sacrifice, 'sound/magic/disintegrate.ogg', 75, TRUE)
+
+ // Drop all items and splatter them around messily.
+ var/list/dustee_items = sacrifice.unequip_everything()
+ for(var/obj/item/loot as anything in dustee_items)
+ loot.throw_at(get_step_rand(sacrifice), 2, 4, user, TRUE)
+
+ // The loser is DUSTED.
+ sacrifice.dust(TRUE, TRUE)
+
+ // Increase reward counter
+ var/datum/antagonist/heretic/antag = IS_HERETIC(user)
+ antag.rewards_given++
+
+ // We limit the amount so the heretic doesn't just turn into a frickin' god (early)
+ to_chat(user, span_hierophant("You feel the rotten energies of the infidel warp and twist, mixing with that of your own..."))
+ if(prob(8 * antag.rewards_given))
+ to_chat(user, span_hierophant("Faint, dark red sparks flit around the dust, then fade. It looks like your patrons weren't able to fashion something out of it."))
+ return
+
+ // Cool effect for the rune as well as the item
+ var/obj/effect/heretic_rune/rune = locate() in range(2, user)
+ if(rune)
+ rune.gender_reveal(
+ outline_color = COLOR_CULT_RED,
+ ray_color = null,
+ do_float = FALSE,
+ do_layer = FALSE,
+ )
+
+ addtimer(CALLBACK(src, PROC_REF(deposit_reward), user, loc, null, rune), 5 SECONDS)
+
+
+/datum/heretic_knowledge/hunt_and_sacrifice/proc/deposit_reward(mob/user, turf/loc, loop = 0, obj/rune)
+ if(loop > 5) // Max limit for retrying a reward
+ return
+ // Remove the rays, we don't need them anymore.
+ rune?.remove_filter("reward_outline")
+ playsound(loc, 'sound/magic/repulse.ogg', 75, TRUE)
+ var/datum/antagonist/heretic/heretic_datum = IS_HERETIC(user)
+ ASSERT(heretic_datum)
+ // This list will be almost identical to unlocked_heretic_items, with the same keys, the difference being the values will be 1 to 5.
+ var/list/rewards = heretic_datum.unlocked_heretic_items.Copy()
+ // We will make it increasingly less likely to get a reward if you've already got it
+ for(var/possible_reward in heretic_datum.unlocked_heretic_items)
+ var/amount_already_awarded = heretic_datum.unlocked_heretic_items[possible_reward]
+ rewards[possible_reward] = min(5 - (amount_already_awarded * 2), 1)
+
+ var/atom/reward = pick_weight(rewards)
+ reward = new reward(loc)
+
+ if(isliving(reward))
+ if(summon_ritual_mob(user, loc, reward) == FALSE)
+ qdel(reward)
+ deposit_reward(user, loc, loop++, rune) // If no ghosts, try again until limit is hit
+ return
+
+ else if(isitem(reward))
+ var/obj/item/item_reward = reward
+ item_reward.gender_reveal(outline_color = null, ray_color = COLOR_CULT_RED)
+
+ ASSERT(reward)
+
+ return reward
/**
* This proc is called from [proc/sacrifice_process] after the heretic successfully sacrifices [sac_target].)
diff --git a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
index e8c14d16abeca..2a6d1e8058d3d 100644
--- a/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
+++ b/code/modules/antagonists/heretic/knowledge/side_blade_rust.dm
@@ -20,7 +20,7 @@
/datum/heretic_knowledge/crucible
name = "Mawed Crucible"
desc = "Allows you to transmute a portable water tank and a table to create a Mawed Crucible. \
- The Mawed Crubile can brew powerful potions for combat and utility, but must be fed bodyparts and organs between uses."
+ The Mawed Crucible can brew powerful potions for combat and utility, but must be fed bodyparts and organs between uses."
gain_text = "This is pure agony. I wasn't able to summon the figure of the Aristocrat, \
but with the Priest's attention I stumbled upon a different recipe..."
next_knowledge = list(
@@ -43,7 +43,7 @@
These shots function as normal, albeit weak high caliber mutitions when fired from \
close range or at inanimate objects. You can aim the rifle at distant foes, \
causing the shot to deal massively increased damage and hone in on them."
- gain_text = "I met an old man in an anique shop who wielded a very unusual weapon. \
+ gain_text = "I met an old man in an antique shop who wielded a very unusual weapon. \
I could not purchase it at the time, but they showed me how they made it ages ago."
next_knowledge = list(
/datum/heretic_knowledge/duel_stance,
diff --git a/code/modules/antagonists/heretic/magic/aggressive_spread.dm b/code/modules/antagonists/heretic/magic/aggressive_spread.dm
index fedc30193ed48..dfb4a94847406 100644
--- a/code/modules/antagonists/heretic/magic/aggressive_spread.dm
+++ b/code/modules/antagonists/heretic/magic/aggressive_spread.dm
@@ -17,7 +17,16 @@
aoe_radius = 2
/datum/action/cooldown/spell/aoe/rust_conversion/get_things_to_cast_on(atom/center)
- return RANGE_TURFS(aoe_radius, center)
+
+ var/list/things_to_convert = RANGE_TURFS(aoe_radius, center)
+
+ // Also converts things right next to you.
+ for(var/atom/movable/nearby_movable in view(1, center))
+ if(nearby_movable == owner || !isstructure(nearby_movable) )
+ continue
+ things_to_convert += nearby_movable
+
+ return things_to_convert
/datum/action/cooldown/spell/aoe/rust_conversion/cast_on_thing_in_aoe(turf/victim, mob/living/caster)
// We have less chance of rusting stuff that's further
@@ -27,9 +36,11 @@
if(prob(chance_of_not_rusting))
return
- caster.do_rust_heretic_act(victim)
+ if(ismob(caster))
+ caster.do_rust_heretic_act(victim)
+ else
+ victim.rust_heretic_act()
-/datum/action/cooldown/spell/aoe/rust_conversion/small
- name = "Rust Conversion"
- desc = "Spreads rust onto nearby surfaces."
- aoe_radius = 2
+/datum/action/cooldown/spell/aoe/rust_conversion/construct
+ name = "Construct Spread"
+ cooldown_time = 15 SECONDS
diff --git a/code/modules/antagonists/heretic/magic/ash_ascension.dm b/code/modules/antagonists/heretic/magic/ash_ascension.dm
index 0d8ca8da4f1c6..8b564198a61eb 100644
--- a/code/modules/antagonists/heretic/magic/ash_ascension.dm
+++ b/code/modules/antagonists/heretic/magic/ash_ascension.dm
@@ -129,16 +129,17 @@
INVOKE_ASYNC(src, PROC_REF(fire_line), owner, line_target(offset, flame_line_length, target, owner))
/datum/action/cooldown/spell/pointed/ash_beams/proc/line_target(offset, range, atom/at, atom/user)
+ var/turf/user_loc = get_turf(user)
if(!at)
return
- var/angle = ATAN2(at.x - user.x, at.y - user.y) + offset
+ var/angle = ATAN2(at.x - user_loc.x, at.y - user_loc.y) + offset
var/turf/T = get_turf(user)
for(var/i in 1 to range)
- var/turf/check = locate(user.x + cos(angle) * i, user.y + sin(angle) * i, user.z)
+ var/turf/check = locate(user_loc.x + cos(angle) * i, user_loc.y + sin(angle) * i, user_loc.z)
if(!check)
break
T = check
- return (get_line(user, T) - get_turf(user))
+ return (get_line(user_loc, T) - user_loc)
/datum/action/cooldown/spell/pointed/ash_beams/proc/fire_line(atom/source, list/turfs)
var/list/hit_list = list()
diff --git a/code/modules/antagonists/heretic/magic/burglar_finesse.dm b/code/modules/antagonists/heretic/magic/burglar_finesse.dm
index 7bb6960354ec7..a90acb8495f14 100644
--- a/code/modules/antagonists/heretic/magic/burglar_finesse.dm
+++ b/code/modules/antagonists/heretic/magic/burglar_finesse.dm
@@ -26,7 +26,7 @@
return FALSE
var/obj/storage_item = locate(/obj/item/storage/backpack) in cast_on.contents
-
+
if(isnull(storage_item))
return FALSE
diff --git a/code/modules/antagonists/heretic/magic/fire_blast.dm b/code/modules/antagonists/heretic/magic/fire_blast.dm
index f76a1f18d1757..4c17ca5ffc0de 100644
--- a/code/modules/antagonists/heretic/magic/fire_blast.dm
+++ b/code/modules/antagonists/heretic/magic/fire_blast.dm
@@ -23,8 +23,8 @@
var/beam_duration = 2 SECONDS
/datum/action/cooldown/spell/charged/beam/fire_blast/cast(atom/cast_on)
- if(isliving(cast_on))
- var/mob/living/caster = cast_on
+ var/mob/living/caster = get_caster_from_target(cast_on)
+ if(istype(caster))
// Caster becomes fireblasted, but in a good way - heals damage over time
caster.apply_status_effect(/datum/status_effect/fire_blasted, beam_duration, -2)
return ..()
diff --git a/code/modules/antagonists/heretic/magic/furious_steel.dm b/code/modules/antagonists/heretic/magic/furious_steel.dm
index 15648a9b4d34d..0ab882a9289e1 100644
--- a/code/modules/antagonists/heretic/magic/furious_steel.dm
+++ b/code/modules/antagonists/heretic/magic/furious_steel.dm
@@ -67,7 +67,7 @@
QDEL_NULL(blade_effect)
var/mob/living/living_user = on_who
- blade_effect = living_user.apply_status_effect(/datum/status_effect/protective_blades, null, projectile_amount, 25, 0.66 SECONDS)
+ blade_effect = living_user.apply_status_effect(/datum/status_effect/protective_blades, null, projectile_amount, 25, 0.66 SECONDS, projectile_type)
RegisterSignal(blade_effect, COMSIG_QDELETING, PROC_REF(on_status_effect_deleted))
/datum/action/cooldown/spell/pointed/projectile/furious_steel/on_deactivation(mob/on_who, refund_cooldown = TRUE)
@@ -106,10 +106,12 @@
sharpness = SHARP_EDGED
wound_bonus = 15
pass_flags = PASSTABLE | PASSFLAPS
+ /// Color applied as an outline filter on init
+ var/outline_color = "#f8f8ff"
/obj/projectile/floating_blade/Initialize(mapload)
. = ..()
- add_filter("dio_knife", 2, list("type" = "outline", "color" = "#f8f8ff", "size" = 1))
+ add_filter("dio_knife", 2, list("type" = "outline", "color" = outline_color, "size" = 1))
/obj/projectile/floating_blade/prehit_pierce(atom/hit)
if(isliving(hit) && isliving(firer))
@@ -128,3 +130,40 @@
return PROJECTILE_DELETE_WITHOUT_HITTING
return ..()
+
+/obj/projectile/floating_blade/haunted
+ name = "ritual blade"
+ icon = 'icons/obj/weapons/khopesh.dmi'
+ icon_state = "render"
+ damage = 35
+ wound_bonus = 25
+ outline_color = "#D7CBCA"
+
+/datum/action/cooldown/spell/pointed/projectile/furious_steel/solo
+ name = "Lesser Furious Steel"
+ cooldown_time = 20 SECONDS
+ projectile_amount = 1
+ active_msg = "You summon forth a blade of furious silver."
+ deactive_msg = "You conceal the blade of furious silver."
+
+/datum/action/cooldown/spell/pointed/projectile/furious_steel/haunted
+ name = "Cursed Steel"
+ desc = "Summon two cursed blades which orbit you. \
+ While orbiting you, these blades will protect you from from attacks, but will be consumed on use. \
+ Additionally, you can click to fire the blades at a target, dealing damage and causing bleeding."
+ background_icon_state = "bg_heretic" // kept intentionally
+ overlay_icon_state = "bg_cult_border"
+ button_icon = 'icons/mob/actions/actions_ecult.dmi'
+ button_icon_state = "cursed_steel"
+ sound = 'sound/weapons/guillotine.ogg'
+
+ cooldown_time = 40 SECONDS
+ invocation = "IA!"
+ invocation_type = INVOCATION_SHOUT
+
+ spell_requirements = NONE
+
+ active_msg = "You summon forth two cursed blades."
+ deactive_msg = "You conceal the cursed blades."
+ projectile_amount = 2
+ projectile_type = /obj/projectile/floating_blade/haunted
diff --git a/code/modules/antagonists/heretic/magic/mansus_grasp.dm b/code/modules/antagonists/heretic/magic/mansus_grasp.dm
index 4ba6aceb20093..e3fbb364f6b1f 100644
--- a/code/modules/antagonists/heretic/magic/mansus_grasp.dm
+++ b/code/modules/antagonists/heretic/magic/mansus_grasp.dm
@@ -38,11 +38,34 @@
var/mob/living/living_hit = victim
living_hit.apply_damage(10, BRUTE, wound_bonus = CANT_WOUND)
- if(iscarbon(victim))
- var/mob/living/carbon/carbon_hit = victim
- carbon_hit.adjust_timed_status_effect(4 SECONDS, /datum/status_effect/speech/slurring/heretic)
- carbon_hit.AdjustKnockdown(5 SECONDS)
- carbon_hit.adjustStaminaLoss(80)
+ if(!iscarbon(victim))
+ return TRUE
+
+ var/mob/living/carbon/carbon_hit = victim
+
+ // Cultists are momentarily disoriented by the stunning aura. Enough for both parties to go 'oh shit' but only a mild combat ability.
+ // Cultists have an identical effect on their stun hand. The heretic's faster spell charge time is made up for by their lack of teammates.
+ if(IS_CULTIST(carbon_hit))
+ carbon_hit.AdjustKnockdown(0.5 SECONDS)
+ carbon_hit.adjust_confusion_up_to(1.5 SECONDS, 3 SECONDS)
+ carbon_hit.adjust_dizzy_up_to(1.5 SECONDS, 3 SECONDS)
+ ADD_TRAIT(carbon_hit, TRAIT_NO_SIDE_KICK, REF(src)) // We don't want this to be a good stunning tool, just minor disorientation
+ addtimer(TRAIT_CALLBACK_REMOVE(carbon_hit, TRAIT_NO_SIDE_KICK, REF(src)), 1 SECONDS)
+
+ var/old_color = carbon_hit.color
+ carbon_hit.color = COLOR_CULT_RED
+ animate(carbon_hit, color = old_color, time = 4 SECONDS, easing = EASE_IN)
+ carbon_hit.mob_light(range = 1.5, power = 2.5, color = COLOR_CULT_RED, duration = 0.5 SECONDS)
+ playsound(carbon_hit, 'sound/magic/curse.ogg', 50, TRUE)
+
+ to_chat(caster, span_warning("An unholy force intervenes as you grasp [carbon_hit], absorbing most of the effects!"))
+ to_chat(carbon_hit, span_warning("As [caster] grasps you with eldritch forces, your blood magic absorbs most of the effects!"))
+ carbon_hit.balloon_alert_to_viewers("absorbed!")
+ return TRUE
+
+ carbon_hit.adjust_timed_status_effect(4 SECONDS, /datum/status_effect/speech/slurring/heretic)
+ carbon_hit.AdjustKnockdown(5 SECONDS)
+ carbon_hit.adjustStaminaLoss(80)
return TRUE
diff --git a/code/modules/antagonists/heretic/magic/rust_construction.dm b/code/modules/antagonists/heretic/magic/rust_construction.dm
index 130e3e06be23b..f8d6a2ff2be44 100644
--- a/code/modules/antagonists/heretic/magic/rust_construction.dm
+++ b/code/modules/antagonists/heretic/magic/rust_construction.dm
@@ -8,7 +8,7 @@
check_flags = AB_CHECK_INCAPACITATED|AB_CHECK_CONSCIOUS|AB_CHECK_HANDS_BLOCKED
school = SCHOOL_FORBIDDEN
- cooldown_time = 5 SECONDS
+ cooldown_time = 8 SECONDS
invocation = "Someone raises a wall of rust."
invocation_self_message = "You raise a wall of rust."
@@ -16,15 +16,19 @@
spell_requirements = NONE
cast_range = 4
- aim_assist = FALSE
/// How long does the filter last on walls we make?
var/filter_duration = 2 MINUTES
+/**
+ * Overrides 'aim assist' because we always want to hit just the turf we clicked on.
+ */
+/datum/action/cooldown/spell/pointed/rust_construction/aim_assist(mob/living/caller, atom/target)
+ return get_turf(target)
+
/datum/action/cooldown/spell/pointed/rust_construction/is_valid_target(atom/cast_on)
- if(!isfloorturf(cast_on))
- if(isturf(cast_on) && owner)
- cast_on.balloon_alert(owner, "not a floor!")
+ if(!isturf(cast_on))
+ cast_on.balloon_alert(owner, "not a wall or floor!")
return FALSE
if(!HAS_TRAIT(cast_on, TRAIT_RUSTY))
@@ -43,9 +47,22 @@
invocation = span_danger("[owner] drags [owner.p_their()] hand[living_owner.usable_hands == 1 ? "":"s"] upwards as a wall of rust rises out of [cast_on]!")
invocation_self_message = span_notice("You drag [living_owner.usable_hands == 1 ? "a hand":"your hands"] upwards as a wall of rust rises out of [cast_on].")
-/datum/action/cooldown/spell/pointed/rust_construction/cast(turf/open/cast_on)
+/datum/action/cooldown/spell/pointed/rust_construction/cast(turf/cast_on)
. = ..()
var/rises_message = "rises out of [cast_on]"
+
+ // If we casted at a wall we'll try to rust it. In the case of an enchanted wall it'll deconstruct it
+ if(isclosedturf(cast_on))
+ cast_on.visible_message(span_warning("\The [cast_on] quakes as the rust causes it to crumble!"))
+ var/mob/living/living_owner = owner
+ living_owner?.do_rust_heretic_act(cast_on)
+ // ref transfers to floor
+ cast_on.Shake(shake_interval = 0.1 SECONDS, duration = 0.5 SECONDS)
+ // which we need to re-rust
+ living_owner?.do_rust_heretic_act(cast_on)
+ playsound(cast_on, 'sound/effects/bang.ogg', 50, vary = TRUE)
+ return
+
var/turf/closed/wall/new_wall = cast_on.place_on_top(/turf/closed/wall)
if(!istype(new_wall))
return
@@ -53,7 +70,8 @@
playsound(new_wall, 'sound/effects/constructform.ogg', 50, TRUE)
new_wall.rust_heretic_act()
new_wall.name = "\improper enchanted [new_wall.name]"
- new_wall.hardness = 10
+ new_wall.AddComponent(/datum/component/torn_wall)
+ new_wall.hardness = 60
new_wall.sheet_amount = 0
new_wall.girder_type = null
@@ -61,8 +79,8 @@
// but I guess a fading filter will have to do for now as walls have 0 depth (currently)
// damn though with 3/4ths walls this'll look sick just imagine it
new_wall.add_filter("rust_wall", 2, list("type" = "outline", "color" = "#85be299c", "size" = 2))
- addtimer(CALLBACK(src, PROC_REF(fade_wall_filter), new_wall), filter_duration * (1/20))
- addtimer(CALLBACK(src,PROC_REF(remove_wall_filter), new_wall), filter_duration)
+ addtimer(CALLBACK(src, PROC_REF(fade_wall_filter), new_wall), filter_duration * 0.5)
+ addtimer(CALLBACK(src, PROC_REF(remove_wall_filter), new_wall), filter_duration)
var/message_shown = FALSE
for(var/mob/living/living_mob in cast_on)
@@ -108,7 +126,7 @@
if(!rust_filter)
return
- animate(rust_filter, alpha = 0, time = filter_duration * (19/20))
+ animate(rust_filter, alpha = 0, time = filter_duration * (9/20))
/datum/action/cooldown/spell/pointed/rust_construction/proc/remove_wall_filter(turf/closed/wall)
if(QDELETED(wall))
diff --git a/code/modules/antagonists/heretic/magic/rust_wave.dm b/code/modules/antagonists/heretic/magic/rust_wave.dm
index 65c5592b34e8b..0282a32b2b687 100644
--- a/code/modules/antagonists/heretic/magic/rust_wave.dm
+++ b/code/modules/antagonists/heretic/magic/rust_wave.dm
@@ -25,7 +25,10 @@
new /obj/effect/temp_visual/dir_setting/entropic(get_step(cast_on, cast_on.dir), cast_on.dir)
/datum/action/cooldown/spell/cone/staggered/entropic_plume/do_turf_cone_effect(turf/target_turf, mob/living/caster, level)
- caster.do_rust_heretic_act(target_turf)
+ if(ismob(caster))
+ caster.do_rust_heretic_act(target_turf)
+ else
+ target_turf.rust_heretic_act()
/datum/action/cooldown/spell/cone/staggered/entropic_plume/do_mob_cone_effect(mob/living/victim, atom/caster, level)
if(victim.can_block_magic(antimagic_flags) || IS_HERETIC_OR_MONSTER(victim) || victim == caster)
diff --git a/code/modules/antagonists/heretic/soultrapped_heretic.dm b/code/modules/antagonists/heretic/soultrapped_heretic.dm
new file mode 100644
index 0000000000000..ffd92e09496cb
--- /dev/null
+++ b/code/modules/antagonists/heretic/soultrapped_heretic.dm
@@ -0,0 +1,24 @@
+///a heretic that got soultrapped by cultists. does nothing, other than signify they suck
+/datum/antagonist/soultrapped_heretic
+ name = "\improper Soultrapped Heretic"
+ roundend_category = "Heretics"
+ antagpanel_category = "Heretic"
+ job_rank = ROLE_HERETIC
+ antag_moodlet = /datum/mood_event/soultrapped_heretic
+ antag_hud_name = "heretic"
+
+// Will never show up because they're shades inside a sword
+/datum/mood_event/soultrapped_heretic
+ description = "They trapped me! I can't escape!"
+ mood_change = -20
+
+// always failure obj
+/datum/objective/heretic_trapped
+ name = "soultrapped failure"
+ explanation_text = "Help the cult. Kill the cult. Help the crew. Kill the crew. Help your wielder. Kill your wielder. Kill everyone. Rattle your chains."
+
+/datum/antagonist/soultrapped_heretic/on_gain()
+ ..()
+ var/datum/objective/epic_fail = new /datum/objective/heretic_trapped()
+ epic_fail.completed = FALSE
+ objectives += epic_fail
diff --git a/code/modules/antagonists/heretic/status_effects/buffs.dm b/code/modules/antagonists/heretic/status_effects/buffs.dm
index d2058a5b4f19e..35a6ab9268784 100644
--- a/code/modules/antagonists/heretic/status_effects/buffs.dm
+++ b/code/modules/antagonists/heretic/status_effects/buffs.dm
@@ -118,6 +118,8 @@
var/time_between_initial_blades = 0.25 SECONDS
/// If TRUE, we self-delete our status effect after all the blades are deleted.
var/delete_on_blades_gone = TRUE
+ /// What blade type to create
+ var/blade_type = /obj/effect/floating_blade
/// A list of blade effects orbiting / protecting our owner
var/list/obj/effect/floating_blade/blades = list()
@@ -127,12 +129,14 @@
max_num_blades = 4,
blade_orbit_radius = 20,
time_between_initial_blades = 0.25 SECONDS,
+ blade_type = /obj/effect/floating_blade,
)
src.duration = new_duration
src.max_num_blades = max_num_blades
src.blade_orbit_radius = blade_orbit_radius
src.time_between_initial_blades = time_between_initial_blades
+ src.blade_type = blade_type
return ..()
/datum/status_effect/protective_blades/on_apply()
@@ -157,7 +161,7 @@
if(QDELETED(src) || QDELETED(owner))
return
- var/obj/effect/floating_blade/blade = new(get_turf(owner))
+ var/obj/effect/floating_blade/blade = new blade_type(get_turf(owner))
blades += blade
blade.orbit(owner, blade_orbit_radius)
RegisterSignal(blade, COMSIG_QDELETING, PROC_REF(remove_blade))
diff --git a/code/modules/antagonists/heretic/structures/mawed_crucible.dm b/code/modules/antagonists/heretic/structures/mawed_crucible.dm
index 8e5410f0f6751..2135ffa134ca5 100644
--- a/code/modules/antagonists/heretic/structures/mawed_crucible.dm
+++ b/code/modules/antagonists/heretic/structures/mawed_crucible.dm
@@ -57,6 +57,10 @@
return span_notice("It's at [round(atom_integrity * 100 / max_integrity)]% stability.")
return ..()
+// no breaky herety thingy
+/obj/structure/destructible/eldritch_crucible/rust_heretic_act()
+ return
+
/obj/structure/destructible/eldritch_crucible/attacked_by(obj/item/weapon, mob/living/user)
if(!iscarbon(user))
return ..()
diff --git a/code/modules/antagonists/heretic/transmutation_rune.dm b/code/modules/antagonists/heretic/transmutation_rune.dm
index 619e7d252957b..5e6ad0fb1cf7f 100644
--- a/code/modules/antagonists/heretic/transmutation_rune.dm
+++ b/code/modules/antagonists/heretic/transmutation_rune.dm
@@ -1,8 +1,9 @@
/// The heretic's rune, which they use to complete transmutation rituals.
/obj/effect/heretic_rune
name = "transmutation rune"
- desc = "A flowing circle of shapes and runes is etched into the floor, filled with a thick black tar-like fluid."
- icon_state = ""
+ desc = "A flowing circle of shapes and runes is etched into the floor, filled with a thick black tar-like fluid. This one looks pretty small."
+ icon = 'icons/obj/antags/cult/rune.dmi'
+ icon_state = "main1"
anchored = TRUE
interaction_flags_atom = INTERACT_ATOM_ATTACK_HAND
resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF
diff --git a/code/modules/antagonists/nukeop/outfits.dm b/code/modules/antagonists/nukeop/outfits.dm
index e8ae07ffdde83..5cd89e6c842a9 100644
--- a/code/modules/antagonists/nukeop/outfits.dm
+++ b/code/modules/antagonists/nukeop/outfits.dm
@@ -136,7 +136,7 @@
suit = /obj/item/clothing/suit/jacket/oversized
gloves = /obj/item/clothing/gloves/fingerless
glasses = /obj/item/clothing/glasses/sunglasses
- mask = /obj/item/clothing/mask/cigarette/cigar
+ mask = /obj/item/cigarette/cigar
faction = "Cybersun Industries"
/datum/outfit/syndicate/reinforcement/donk
diff --git a/code/modules/antagonists/pirate/pirate_outfits.dm b/code/modules/antagonists/pirate/pirate_outfits.dm
index 15a3d4fe2dcb2..aef7f1d9d4b92 100644
--- a/code/modules/antagonists/pirate/pirate_outfits.dm
+++ b/code/modules/antagonists/pirate/pirate_outfits.dm
@@ -72,7 +72,7 @@
id_trim = /datum/id_trim/pirate/captain/silverscale
head = /obj/item/clothing/head/costume/crown
- mask = /obj/item/clothing/mask/cigarette/cigar/havana
+ mask = /obj/item/cigarette/cigar/havana
l_pocket = /obj/item/lighter
/datum/outfit/pirate/interdyne
diff --git a/code/modules/antagonists/traitor/contractor/contract_teammate.dm b/code/modules/antagonists/traitor/contractor/contract_teammate.dm
index 54fc958c1f89f..965d99e89ac6a 100644
--- a/code/modules/antagonists/traitor/contractor/contract_teammate.dm
+++ b/code/modules/antagonists/traitor/contractor/contract_teammate.dm
@@ -24,7 +24,7 @@
suit = /obj/item/clothing/suit/chameleon
back = /obj/item/storage/backpack
belt = /obj/item/modular_computer/pda/chameleon
- mask = /obj/item/clothing/mask/cigarette/syndicate
+ mask = /obj/item/cigarette/syndicate
shoes = /obj/item/clothing/shoes/chameleon/noslip
ears = /obj/item/radio/headset/chameleon
id = /obj/item/card/id/advanced/chameleon
@@ -41,5 +41,5 @@
/datum/outfit/contractor_partner/post_equip(mob/living/carbon/human/H, visualsOnly)
. = ..()
- var/obj/item/clothing/mask/cigarette/syndicate/cig = H.get_item_by_slot(ITEM_SLOT_MASK)
+ var/obj/item/cigarette/syndicate/cig = H.get_item_by_slot(ITEM_SLOT_MASK)
cig.light()
diff --git a/code/modules/antagonists/wizard/equipment/soulstone.dm b/code/modules/antagonists/wizard/equipment/soulstone.dm
index 3094af509dadb..925f368fe3b54 100644
--- a/code/modules/antagonists/wizard/equipment/soulstone.dm
+++ b/code/modules/antagonists/wizard/equipment/soulstone.dm
@@ -260,16 +260,17 @@
icon = 'icons/mob/shells.dmi'
icon_state = "construct_cult"
desc = "A wicked machine used by those skilled in magical arts. It is inactive."
-
-/obj/structure/constructshell/examine(mob/user)
- . = ..()
- if(IS_CULTIST(user) || HAS_MIND_TRAIT(user, TRAIT_MAGICALLY_GIFTED) || user.stat == DEAD)
- . += {"A construct shell, used to house bound souls from a soulstone.\n
+ var/extra_desc = {"A construct shell, used to house bound souls from a soulstone.\n
Placing a soulstone with a soul into this shell allows you to produce your choice of the following:\n
An Artificer, which can produce more shells and soulstones, as well as fortifications.\n
A Wraith, which does high damage and can jaunt through walls, though it is quite fragile.\n
A Juggernaut, which is very hard to kill and can produce temporary walls, but is slow."}
+/obj/structure/constructshell/examine(mob/user)
+ . = ..()
+ if(IS_CULTIST(user) || HAS_MIND_TRAIT(user, TRAIT_MAGICALLY_GIFTED) || user.stat == DEAD)
+ . += extra_desc
+
/obj/structure/constructshell/attackby(obj/item/O, mob/user, params)
if(istype(O, /obj/item/soulstone))
var/obj/item/soulstone/SS = O
@@ -494,6 +495,11 @@
make_new_construct(/mob/living/basic/construct/artificer/angelic, target, creator, cultoverride, loc_override)
if(THEME_CULT)
make_new_construct(/mob/living/basic/construct/artificer/noncult, target, creator, cultoverride, loc_override)
+ if(CONSTRUCT_HARVESTER)
+ if(IS_HERETIC_OR_MONSTER(creator))
+ make_new_construct(/mob/living/basic/construct/harvester/heretic, target, creator, cultoverride, loc_override)
+ else
+ make_new_construct(/mob/living/basic/construct/harvester, target, creator, cultoverride, loc_override)
/proc/make_new_construct(mob/living/basic/construct/ctype, mob/target, mob/stoner = null, cultoverride = FALSE, loc_override = null)
if(QDELETED(target))
@@ -523,7 +529,7 @@
newstruct.clear_alert("bloodsense")
sense_alert = newstruct.throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
if(sense_alert)
- sense_alert.Cviewer = newstruct
+ sense_alert.construct_owner = newstruct
newstruct.cancel_camera()
/obj/item/soulstone/anybody
diff --git a/code/modules/atmospherics/machinery/portable/canister.dm b/code/modules/atmospherics/machinery/portable/canister.dm
index 0b1e7c2768ae9..c3dae6241620d 100644
--- a/code/modules/atmospherics/machinery/portable/canister.dm
+++ b/code/modules/atmospherics/machinery/portable/canister.dm
@@ -461,18 +461,24 @@
user.investigate_log("started a transfer into [holding].", INVESTIGATE_ATMOS)
/obj/machinery/portable_atmospherics/canister/process(seconds_per_tick)
+ if(!shielding_powered)
+ return
+
var/our_pressure = air_contents.return_pressure()
var/our_temperature = air_contents.return_temperature()
+ var/energy_factor = round(log(10, max(our_pressure - pressure_limit, 1)) + log(10, max(our_temperature - temp_limit, 1)))
+ var/energy_consumed = energy_factor * 250 * seconds_per_tick
- if(shielding_powered)
- var/energy_factor = round(log(10, max(our_pressure - pressure_limit, 1)) + log(10, max(our_temperature - temp_limit, 1)))
- var/energy_consumed = energy_factor * 250 * seconds_per_tick
- if(powered(AREA_USAGE_EQUIP, ignore_use_power = TRUE))
- use_energy(energy_consumed, channel = AREA_USAGE_EQUIP)
- else if(!internal_cell?.use(energy_consumed * 0.025))
- shielding_powered = FALSE
- SSair.start_processing_machine(src)
- investigate_log("shielding turned off due to power loss")
+ if(!energy_consumed)
+ return
+
+ if(powered(AREA_USAGE_EQUIP, ignore_use_power = TRUE))
+ use_energy(energy_consumed, channel = AREA_USAGE_EQUIP)
+ else if(!internal_cell?.use(energy_consumed * 0.025))
+ shielding_powered = FALSE
+ SSair.start_processing_machine(src)
+ investigate_log("shielding turned off due to power loss")
+ update_appearance()
///return the icon_state component for the canister's indicator light based on its current pressure reading
/obj/machinery/portable_atmospherics/canister/proc/get_pressure_state()
diff --git a/code/modules/clothing/chameleon/chameleon_action_subtypes.dm b/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
index 275b2c6e0fc2a..bd15bb908f227 100644
--- a/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
+++ b/code/modules/clothing/chameleon/chameleon_action_subtypes.dm
@@ -64,6 +64,11 @@
. = ..()
chameleon_blacklist |= typecacheof(/obj/item/clothing/mask/changeling, only_root_path = TRUE)
+/datum/action/item_action/chameleon/change/mask/initialize_disguises()
+ . = ..()
+ add_chameleon_items(/obj/item/cigarette)
+ add_chameleon_items(/obj/item/vape)
+
/datum/action/item_action/chameleon/change/hat
chameleon_type = /obj/item/clothing/head
chameleon_name = "Hat"
diff --git a/code/modules/clothing/masks/gasmask.dm b/code/modules/clothing/masks/gasmask.dm
index ef90fcf97e10a..36fe591a63edb 100644
--- a/code/modules/clothing/masks/gasmask.dm
+++ b/code/modules/clothing/masks/gasmask.dm
@@ -27,7 +27,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
///Does the mask have an FOV?
var/has_fov = TRUE
///Cigarette in the mask
- var/obj/item/clothing/mask/cigarette/cig
+ var/obj/item/cigarette/cig
voice_filter = "lowpass=f=750,volume=2"
/datum/armor/mask_gas
@@ -84,7 +84,7 @@ GLOBAL_LIST_INIT(clown_mask_options, list(
/obj/item/clothing/mask/gas/attackby(obj/item/tool, mob/user)
var/valid_wearer = ismob(loc)
var/mob/wearer = loc
- if(istype(tool, /obj/item/clothing/mask/cigarette))
+ if(istype(tool, /obj/item/cigarette))
if(flags_cover & MASKCOVERSMOUTH)
balloon_alert(user, "mask's mouth is covered!")
return ..()
diff --git a/code/modules/clothing/outfits/standard.dm b/code/modules/clothing/outfits/standard.dm
index 6c088760f07db..422cb34fa090d 100644
--- a/code/modules/clothing/outfits/standard.dm
+++ b/code/modules/clothing/outfits/standard.dm
@@ -11,7 +11,7 @@
glasses = /obj/item/clothing/glasses/thermal/eyepatch
gloves = /obj/item/clothing/gloves/tackler/combat/insulated
head = /obj/item/clothing/head/helmet/space/beret
- mask = /obj/item/clothing/mask/cigarette/cigar/havana
+ mask = /obj/item/cigarette/cigar/havana
shoes = /obj/item/clothing/shoes/combat/swat
r_pocket = /obj/item/lighter
@@ -245,7 +245,7 @@
glasses = /obj/item/clothing/glasses/sunglasses
gloves = /obj/item/clothing/gloves/tackler/combat/insulated
head = /obj/item/clothing/head/hats/centhat
- mask = /obj/item/clothing/mask/cigarette/cigar/cohiba
+ mask = /obj/item/cigarette/cigar/cohiba
shoes = /obj/item/clothing/shoes/combat/swat
l_pocket = /obj/item/ammo_box/a357
r_pocket = /obj/item/lighter
diff --git a/code/modules/clothing/suits/jobs.dm b/code/modules/clothing/suits/jobs.dm
index bc091aaeb6651..f333ec53917a9 100644
--- a/code/modules/clothing/suits/jobs.dm
+++ b/code/modules/clothing/suits/jobs.dm
@@ -61,7 +61,7 @@
body_parts_covered = CHEST|GROIN|ARMS
allowed = list(
/obj/item/assembly/flash/handheld,
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
/obj/item/disk,
/obj/item/lighter,
/obj/item/melee,
diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm
index b4c6af04304eb..a24663b3ba439 100644
--- a/code/modules/deathmatch/deathmatch_loadouts.dm
+++ b/code/modules/deathmatch/deathmatch_loadouts.dm
@@ -371,7 +371,7 @@
display_name = "Cowboy"
desc = "Yeehaw partner"
- r_hand = /obj/item/clothing/mask/cigarette/cigar
+ r_hand = /obj/item/cigarette/cigar
l_hand = /obj/item/melee/curator_whip
l_pocket = /obj/item/lighter
accessory = /obj/item/clothing/accessory/vest_sheriff
@@ -405,7 +405,7 @@
suit = /obj/item/clothing/suit/wizrobe/red
head = /obj/item/clothing/head/wizard/red
- mask = /obj/item/clothing/mask/cigarette
+ mask = /obj/item/cigarette
granted_spells = list(
/datum/action/cooldown/spell/pointed/projectile/fireball,
/datum/action/cooldown/spell/smoke,
diff --git a/code/modules/events/wizard/curseditems.dm b/code/modules/events/wizard/curseditems.dm
index 683b36304a367..ab305bbff99bf 100644
--- a/code/modules/events/wizard/curseditems.dm
+++ b/code/modules/events/wizard/curseditems.dm
@@ -38,7 +38,7 @@
switch(item_set)
if(BIG_FAT_DOOBIE)
- loadout += /obj/item/clothing/mask/cigarette/rollie/trippy
+ loadout += /obj/item/cigarette/rollie/trippy
ruins_spaceworthiness = TRUE
if(BOXING)
loadout += /obj/item/clothing/mask/luchador
diff --git a/code/modules/hydroponics/grown/corn.dm b/code/modules/hydroponics/grown/corn.dm
index 8eab962d75118..d5f9f94e1b2df 100644
--- a/code/modules/hydroponics/grown/corn.dm
+++ b/code/modules/hydroponics/grown/corn.dm
@@ -50,7 +50,7 @@
/obj/item/grown/corncob/attackby(obj/item/grown/W, mob/user, params)
if(W.get_sharpness())
to_chat(user, span_notice("You use [W] to fashion a pipe out of the corn cob!"))
- new /obj/item/clothing/mask/cigarette/pipe/cobpipe (user.loc)
+ new /obj/item/cigarette/pipe/cobpipe (user.loc)
qdel(src)
else
return ..()
diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm
index 13e358bdcd528..5b82c9adb7116 100644
--- a/code/modules/jobs/job_types/captain.dm
+++ b/code/modules/jobs/job_types/captain.dm
@@ -35,7 +35,7 @@
family_heirlooms = list(/obj/item/reagent_containers/cup/glass/flask/gold, /obj/item/toy/captainsaid/collector)
mail_goodies = list(
- /obj/item/clothing/mask/cigarette/cigar/havana = 20,
+ /obj/item/cigarette/cigar/havana = 20,
/obj/item/storage/fancy/cigarettes/cigars/havana = 15,
/obj/item/reagent_containers/cup/glass/bottle/champagne = 5,
/obj/item/reagent_containers/cup/glass/bottle/champagne/cursed = 5,
diff --git a/code/modules/jobs/job_types/detective.dm b/code/modules/jobs/job_types/detective.dm
index b6984e24b4220..0ed502b2529bf 100644
--- a/code/modules/jobs/job_types/detective.dm
+++ b/code/modules/jobs/job_types/detective.dm
@@ -61,7 +61,7 @@
ears = /obj/item/radio/headset/headset_sec/alt
gloves = /obj/item/clothing/gloves/color/black
head = /obj/item/clothing/head/fedora/det_hat
- mask = /obj/item/clothing/mask/cigarette
+ mask = /obj/item/cigarette
neck = /obj/item/clothing/neck/tie/detective
shoes = /obj/item/clothing/shoes/sneakers/brown
l_pocket = /obj/item/toy/crayon/white
@@ -76,12 +76,12 @@
/datum/outfit/job/detective/pre_equip(mob/living/carbon/human/human, visualsOnly = FALSE)
. = ..()
if (human.age < AGE_MINOR)
- mask = /obj/item/clothing/mask/cigarette/candy
+ mask = /obj/item/cigarette/candy
head = /obj/item/clothing/head/fedora/det_hat/minor
/datum/outfit/job/detective/post_equip(mob/living/carbon/human/H, visualsOnly = FALSE)
..()
- var/obj/item/clothing/mask/cigarette/cig = H.wear_mask
+ var/obj/item/cigarette/cig = H.wear_mask
if(istype(cig)) //Some species specfic changes can mess this up (plasmamen)
cig.light("")
diff --git a/code/modules/jobs/job_types/station_trait/veteran_advisor.dm b/code/modules/jobs/job_types/station_trait/veteran_advisor.dm
index 87ad65c2c7a71..6fcb8d94707f5 100644
--- a/code/modules/jobs/job_types/station_trait/veteran_advisor.dm
+++ b/code/modules/jobs/job_types/station_trait/veteran_advisor.dm
@@ -63,7 +63,7 @@
uniform = /obj/item/clothing/under/rank/security/officer/formal
head = /obj/item/clothing/head/soft/veteran
- mask = /obj/item/clothing/mask/cigarette/cigar
+ mask = /obj/item/cigarette/cigar
suit = /obj/item/clothing/suit/jacket/trenchcoat
belt = /obj/item/storage/belt/holster/detective/full/ert //M1911 pistol
ears = /obj/item/radio/headset/heads/hos/advisor
diff --git a/code/modules/library/bibles.dm b/code/modules/library/bibles.dm
index 8c2ad28feadf8..39abe7baa509b 100644
--- a/code/modules/library/bibles.dm
+++ b/code/modules/library/bibles.dm
@@ -310,25 +310,12 @@ GLOBAL_LIST_INIT(bibleitemstates, list(
if(.)
return .
- if(istype(bible_smacked, /obj/item/cult_bastard) && !IS_CULTIST(user))
- var/obj/item/cult_bastard/sword = bible_smacked
- bible_smacked.balloon_alert(user, "exorcising...")
+ if(istype(bible_smacked, /obj/item/melee/cultblade/haunted) && !IS_CULTIST(user))
+ var/obj/item/melee/cultblade/haunted/sword = bible_smacked
+ sword.balloon_alert(user, "exorcising...")
playsound(src,'sound/hallucinations/veryfar_noise.ogg',40,TRUE)
if(do_after(user, 4 SECONDS, target = sword))
playsound(src,'sound/effects/pray_chaplain.ogg',60,TRUE)
- for(var/obj/item/soulstone/stone in sword.contents)
- stone.required_role = null
- for(var/mob/living/basic/shade/shade in stone)
- var/datum/antagonist/cult/cultist = shade.mind.has_antag_datum(/datum/antagonist/cult)
- if(cultist)
- cultist.silent = TRUE
- cultist.on_removal()
- SSblackbox.record_feedback("tally", "cult_shade_purified", 1)
- shade.theme = THEME_HOLY
- shade.name = "Purified [shade.real_name]"
- shade.update_appearance(UPDATE_ICON_STATE)
- stone.release_shades(user)
- qdel(stone)
new /obj/item/nullrod/claymore(get_turf(sword))
user.visible_message(span_notice("[user] exorcises [sword]!"))
qdel(sword)
diff --git a/code/modules/mafia/outfits.dm b/code/modules/mafia/outfits.dm
index 5c6450adb90d2..3b805bd92f9c0 100644
--- a/code/modules/mafia/outfits.dm
+++ b/code/modules/mafia/outfits.dm
@@ -64,7 +64,7 @@
suit = /obj/item/clothing/suit/jacket/det_suit
gloves = /obj/item/clothing/gloves/color/black
head = /obj/item/clothing/head/fedora/det_hat
- mask = /obj/item/clothing/mask/cigarette
+ mask = /obj/item/cigarette
/datum/outfit/mafia/psychologist
name = "Mafia Psychologist"
diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm
index 3bb1fb48e599a..4aecd64aa1699 100644
--- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm
+++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm
@@ -209,7 +209,7 @@
new /obj/item/clothing/glasses/science(src)
if(7)
new /obj/item/clothing/glasses/sunglasses/big(src)
- new /obj/item/clothing/mask/cigarette/rollie(src)
+ new /obj/item/cigarette/rollie(src)
else
//empty grave
return
@@ -289,7 +289,7 @@
deconstruct(TRUE)
return TRUE
-/obj/structure/closet/crate/grave/container_resist_act(mob/living/user)
+/obj/structure/closet/crate/grave/container_resist_act(mob/living/user, loc_required = TRUE)
if(opened)
return
// The player is trying to dig themselves out of an early grave
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index f30074326fdf8..e59b04e6c7efa 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -563,17 +563,17 @@
if(!mapload)
log_mapping("[src] spawned outside of mapload!")
return INITIALIZE_HINT_QDEL
- check_validity()
- return INITIALIZE_HINT_QDEL
+ return INITIALIZE_HINT_LATELOAD
-/obj/effect/mapping_helpers/turn_off_lights_with_lightswitch/proc/check_validity()
+/obj/effect/mapping_helpers/turn_off_lights_with_lightswitch/LateInitialize()
var/area/needed_area = get_area(src)
if(!needed_area.lightswitch)
stack_trace("[src] at [AREACOORD(src)] [(needed_area.type)] tried to turn lights off but they are already off!")
var/obj/machinery/light_switch/light_switch = locate(/obj/machinery/light_switch) in needed_area
if(!light_switch)
- stack_trace("Trying to turn off lights with lightswitch in area without lightswitches. In [(needed_area.type)] to be precise.")
- needed_area.lightswitch = FALSE
+ CRASH("Trying to turn off lights with lightswitch in area without lightswitches. In [(needed_area.type)] to be precise.")
+ light_switch.set_lights(FALSE)
+ qdel(src)
//needs to do its thing before spawn_rivers() is called
INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_lava)
diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm
index fa15060d282a9..40cb967d3a0ab 100644
--- a/code/modules/mining/abandoned_crates.dm
+++ b/code/modules/mining/abandoned_crates.dm
@@ -141,7 +141,7 @@
new /obj/item/lighter(src)
new /obj/item/reagent_containers/cup/glass/bottle/absinthe/premium(src)
for(var/i in 1 to 3)
- new /obj/item/clothing/mask/cigarette/rollie(src)
+ new /obj/item/cigarette/rollie(src)
if(6 to 10)
new /obj/item/melee/skateboard/pro(src)
if(11 to 15)
diff --git a/code/modules/mob/inventory.dm b/code/modules/mob/inventory.dm
index 50ab6e82faa4d..7a63d0fc8e622 100644
--- a/code/modules/mob/inventory.dm
+++ b/code/modules/mob/inventory.dm
@@ -290,8 +290,12 @@
/mob/proc/is_holding_items()
return !!locate(/obj/item) in held_items
+/**
+ * Returns a list of all dropped held items.
+ * If none were dropped, returns an empty list.
+ */
/mob/proc/drop_all_held_items()
- . = FALSE
+ . = list()
for(var/obj/item/I in held_items)
. |= dropItemToGround(I)
@@ -319,24 +323,25 @@
/**
* Used to drop an item (if it exists) to the ground.
- * * Will pass as TRUE is successfully dropped, or if there is no item to drop.
- * * Will pass FALSE if the item can not be dropped due to TRAIT_NODROP via doUnEquip()
+ * * Will return null if the item wasn't dropped.
+ * * If it was, returns the item.
* If the item can be dropped, it will be forceMove()'d to the ground and the turf's Entered() will be called.
*/
/mob/proc/dropItemToGround(obj/item/I, force = FALSE, silent = FALSE, invdrop = TRUE)
if (isnull(I))
- return TRUE
+ return
SEND_SIGNAL(src, COMSIG_MOB_DROPPING_ITEM)
- . = doUnEquip(I, force, drop_location(), FALSE, invdrop = invdrop, silent = silent)
+ var/try_uneqip = doUnEquip(I, force, drop_location(), FALSE, invdrop = invdrop, silent = silent)
- if(!. || !I) //ensure the item exists and that it was dropped properly.
+ if(!try_uneqip || !I) //ensure the item exists and that it was dropped properly.
return
if(!(I.item_flags & NO_PIXEL_RANDOM_DROP))
I.pixel_x = I.base_pixel_x + rand(-6, 6)
I.pixel_y = I.base_pixel_y + rand(-6, 6)
I.do_drop_animation(src)
+ return I
//for when the item will be immediately placed in a loc other than the ground
/mob/proc/transferItemToLoc(obj/item/I, newloc = null, force = FALSE, silent = TRUE)
@@ -416,13 +421,23 @@
items += worn_under.attached_accessories
return items
+/**
+ * Returns the items that were succesfully unequipped.
+ */
/mob/living/proc/unequip_everything()
var/list/items = list()
items |= get_equipped_items(INCLUDE_POCKETS)
+ // In case something isn't actually unequipped somehow
+ var/list/dropped_items = list()
for(var/I in items)
- dropItemToGround(I)
- drop_all_held_items()
-
+ var/return_val = dropItemToGround(I)
+ if(!isitem(return_val))
+ continue
+ dropped_items |= return_val
+ var/return_val = drop_all_held_items()
+ if(islist(return_val))
+ dropped_items |= return_val
+ return dropped_items
/mob/living/carbon/proc/check_obscured_slots(transparent_protection)
var/obscured = NONE
diff --git a/code/modules/mob/living/basic/bots/firebot/firebot.dm b/code/modules/mob/living/basic/bots/firebot/firebot.dm
index 140948b81c02e..31fa969fa5983 100644
--- a/code/modules/mob/living/basic/bots/firebot/firebot.dm
+++ b/code/modules/mob/living/basic/bots/firebot/firebot.dm
@@ -8,7 +8,7 @@
light_color = "#8cffc9"
light_power = 0.8
- req_access = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION)
+ req_one_access = list(ACCESS_ROBOTICS, ACCESS_CONSTRUCTION)
radio_key = /obj/item/encryptionkey/headset_eng
radio_channel = RADIO_CHANNEL_ENGINEERING
bot_type = FIRE_BOT
diff --git a/code/modules/mob/living/basic/cult/constructs/_construct.dm b/code/modules/mob/living/basic/cult/constructs/_construct.dm
index 2583b3a88a6b8..79e6e7487721b 100644
--- a/code/modules/mob/living/basic/cult/constructs/_construct.dm
+++ b/code/modules/mob/living/basic/cult/constructs/_construct.dm
@@ -51,10 +51,12 @@
THEME_CULT = list(/obj/item/ectoplasm/construct),
THEME_HOLY = list(/obj/item/ectoplasm/angelic),
THEME_WIZARD = list(/obj/item/ectoplasm/mystic),
+ THEME_HERETIC = list(/obj/item/ectoplasm/construct),
)
/mob/living/basic/construct/Initialize(mapload)
. = ..()
+ throw_alert("bloodsense", /atom/movable/screen/alert/bloodsense)
AddElement(/datum/element/simple_flying)
var/list/remains = string_list(remains_by_theme[theme])
if(length(remains))
diff --git a/code/modules/mob/living/basic/cult/constructs/harvester.dm b/code/modules/mob/living/basic/cult/constructs/harvester.dm
index da8dad827b05c..6d41bb43f26a1 100644
--- a/code/modules/mob/living/basic/cult/constructs/harvester.dm
+++ b/code/modules/mob/living/basic/cult/constructs/harvester.dm
@@ -26,13 +26,16 @@
/mob/living/basic/construct/harvester/Initialize(mapload)
. = ..()
- AddElement(\
- /datum/element/amputating_limbs,\
+ grant_abilities()
+
+/mob/living/basic/construct/harvester/proc/grant_abilities()
+ AddElement(/datum/element/wall_walker, /turf/closed/wall/mineral/cult)
+ AddComponent(\
+ /datum/component/amputating_limbs,\
surgery_time = 0,\
surgery_verb = "slicing",\
minimum_stat = CONSCIOUS,\
)
- AddElement(/datum/element/wall_walker, /turf/closed/wall/mineral/cult)
var/datum/action/innate/seek_prey/seek = new(src)
seek.Grant(src)
seek.Activate()
@@ -59,7 +62,7 @@
overlay_icon_state = "bg_demon_border"
buttontooltipstyle = "cult"
- button_icon = "icons/mob/actions/actions_cult.dmi"
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
button_icon_state = "cult_mark"
/// Where is nar nar? Are we even looking?
var/tracking = FALSE
@@ -93,7 +96,6 @@
the_construct.seeking = TRUE
to_chat(the_construct, span_cult_italic("You are now tracking your master."))
-
/datum/action/innate/seek_prey
name = "Seek the Harvest"
desc = "None can hide from Nar'Sie, activate to track a survivor attempting to flee the red harvest!"
@@ -126,3 +128,115 @@
desc = "Activate to track Nar'Sie!"
button_icon_state = "sintouch"
the_construct.seeking = TRUE
+
+/mob/living/basic/construct/harvester/heretic
+ name = "Rusted Harvester"
+ real_name = "Rusted Harvester"
+ desc = "A long, thin, decrepit construct originally built to herald Nar'Sie's rise, corrupted and rusted by the forces of the Mansus to spread its will instead."
+ icon_state = "harvester"
+ icon_living = "harvester"
+ construct_spells = list(
+ /datum/action/cooldown/spell/aoe/rust_conversion,
+ /datum/action/cooldown/spell/pointed/rust_construction,
+ )
+ can_repair = FALSE
+ slowed_by_drag = FALSE
+ faction = list(FACTION_HERETIC)
+ maxHealth = 35
+ health = 35
+ melee_damage_lower = 20
+ melee_damage_upper = 25
+ // Dim green
+ lighting_cutoff_red = 10
+ lighting_cutoff_green = 20
+ lighting_cutoff_blue = 5
+ playstyle_string = "You are a Rusted Harvester, built to serve the Sanguine Apostate, twisted to work the will of the Mansus. You are fragile and weak, but you rend cultists (only) apart on each attack. Follow your Master's orders!"
+ theme = THEME_HERETIC
+
+/mob/living/basic/construct/harvester/heretic/Initialize(mapload)
+ . = ..()
+ ADD_TRAIT(src, TRAIT_MANSUS_TOUCHED, REF(src))
+ add_filter("rusted_harvester", 3, list("type" = "outline", "color" = COLOR_GREEN, "size" = 2, "alpha" = 40))
+
+
+/**
+ * Somewhat janky proc called when a heretic monster's master dies
+ * Used to kill any living Rusted Harvester
+ */
+/mob/living/proc/on_master_death()
+ return
+
+/mob/living/basic/construct/harvester/heretic/attack_animal(mob/living/simple_animal/user, list/modifiers)
+ // They're pretty fragile so this is probably necessary to prevent bullshit deaths.
+ if(user == src)
+ return
+ return ..()
+
+/mob/living/basic/construct/harvester/heretic/on_master_death()
+ to_chat(src, span_userdanger("Your link to the mansus suddenly snaps as your master perishes! Without its support, your body crumbles..."))
+ visible_message(span_alert("[src] suddenly crumbles to dust!"))
+ death()
+
+/mob/living/basic/construct/harvester/heretic/grant_abilities()
+ AddElement(/datum/element/wall_walker, or_trait = TRAIT_RUSTY)
+ AddElement(/datum/element/leeching_walk)
+ AddComponent(\
+ /datum/component/amputating_limbs,\
+ surgery_time = 1.5 SECONDS,\
+ surgery_verb = "slicing",\
+ minimum_stat = CONSCIOUS,\
+ pre_hit_callback = CALLBACK(src, PROC_REF(is_cultist_handler)),\
+ )
+ AddComponent(/datum/component/damage_aura,\
+ range = 3,\
+ brute_damage = 0.5,\
+ burn_damage = 0.5,\
+ toxin_damage = 0.5,\
+ stamina_damage = 4,\
+ simple_damage = 1.5,\
+ immune_factions = list(FACTION_HERETIC),\
+ damage_message = span_boldwarning("Your body wilts and withers as it comes near [src]'s aura."),\
+ message_probability = 7,\
+ current_owner = src,\
+ )
+ var/datum/action/innate/seek_master/heretic/seek = new(src)
+ seek.Grant(src)
+ seek.Activate()
+
+// These aren't friends they're assholes
+// Don't let them be near you!
+/mob/living/basic/construct/harvester/heretic/Life(seconds_per_tick, times_fired)
+ . = ..()
+ if(!SPT_PROB(7, seconds_per_tick))
+ return
+
+ var/turf/adjacent = get_step(src, pick(GLOB.alldirs))
+ // 90% chance to be directional, otherwise what we're on top of
+ var/turf/open/land = (isopenturf(adjacent) && prob(90)) ? adjacent : get_turf(src)
+ do_rust_heretic_act(land)
+
+ if(prob(7))
+ to_chat(src, span_notice("Eldritch energies emanate from your body."))
+
+/mob/living/basic/construct/harvester/heretic/proc/is_cultist_handler(mob/victim)
+ return IS_CULTIST(victim)
+
+/datum/action/innate/seek_master/heretic
+ name = "Seek your Master"
+ desc = "Use your direct link to the Mansus to sense where your master is located via the arrow on the top-right of your HUD."
+ button_icon = 'icons/mob/actions/actions_cult.dmi'
+ background_icon_state = "bg_heretic"
+ overlay_icon_state = "bg_heretic_border"
+ tracking = TRUE
+
+/datum/action/innate/seek_master/heretic/New(Target)
+ . = ..()
+ the_construct = Target
+ the_construct.seeking = TRUE
+ var/datum/antagonist/heretic_monster/antag = IS_HERETIC_MONSTER(the_construct)
+ if(antag)
+ the_construct.master = antag.master
+
+// no real reason for most of this weird oldcode
+/datum/action/innate/seek_master/Activate()
+ return
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 ce363af236465..d1b1aebf9eb00 100644
--- a/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm
+++ b/code/modules/mob/living/basic/farm_animals/gorilla/gorilla.dm
@@ -60,8 +60,8 @@
AddElement(/datum/element/dextrous)
AddElement(/datum/element/footstep, FOOTSTEP_MOB_BAREFOOT)
AddElement(/datum/element/basic_eating, heal_amt = 10, food_types = gorilla_food)
- AddElement(
- /datum/element/amputating_limbs, \
+ AddComponent(
+ /datum/component/amputating_limbs, \
surgery_time = 0 SECONDS, \
surgery_verb = "punches",\
)
diff --git a/code/modules/mob/living/basic/farm_animals/sheep.dm b/code/modules/mob/living/basic/farm_animals/sheep.dm
index 2fdaeda657d5c..5617da83a53a5 100644
--- a/code/modules/mob/living/basic/farm_animals/sheep.dm
+++ b/code/modules/mob/living/basic/farm_animals/sheep.dm
@@ -59,7 +59,7 @@
if(cult_converted)
for(var/mob/living/cultist as anything in invokers)
to_chat(cultist, span_cult_italic("[src] has already been sacrificed!"))
- return STOP_SACRIFICE
+ return STOP_SACRIFICE|SILENCE_SACRIFICE_MESSAGE
for(var/mob/living/cultist as anything in invokers)
to_chat(cultist, span_cult_italic("This feels a bit too cliché, don't you think?"))
diff --git a/code/modules/mob/living/basic/heretic/flesh_worm.dm b/code/modules/mob/living/basic/heretic/flesh_worm.dm
index 3c60a9b653c32..92b910c717fae 100644
--- a/code/modules/mob/living/basic/heretic/flesh_worm.dm
+++ b/code/modules/mob/living/basic/heretic/flesh_worm.dm
@@ -35,8 +35,8 @@
/mob/living/basic/heretic_summon/armsy/Initialize(mapload, spawn_bodyparts = TRUE, worm_length = 6)
. = ..()
AddElement(/datum/element/wall_smasher, ENVIRONMENT_SMASH_RWALLS)
- AddElement(\
- /datum/element/amputating_limbs,\
+ AddComponent(\
+ /datum/component/amputating_limbs,\
surgery_time = 0 SECONDS,\
surgery_verb = "tears",\
minimum_stat = CONSCIOUS,\
diff --git a/code/modules/mob/living/basic/heretic/rust_walker.dm b/code/modules/mob/living/basic/heretic/rust_walker.dm
index 24b77d4d0b8e0..230747efa5a3b 100644
--- a/code/modules/mob/living/basic/heretic/rust_walker.dm
+++ b/code/modules/mob/living/basic/heretic/rust_walker.dm
@@ -19,7 +19,7 @@
AddElement(/datum/element/footstep, FOOTSTEP_MOB_RUST)
var/static/list/grantable_spells = list(
- /datum/action/cooldown/spell/aoe/rust_conversion/small = BB_GENERIC_ACTION,
+ /datum/action/cooldown/spell/aoe/rust_conversion = BB_GENERIC_ACTION,
/datum/action/cooldown/spell/basic_projectile/rust_wave/short = BB_TARGETED_ACTION,
)
grant_actions_by_list(grantable_spells)
diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
index ccab4d3c0317e..ad10e30acecd7 100644
--- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
+++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm
@@ -43,8 +43,8 @@
AddElement(/datum/element/mob_grabber)
AddElement(/datum/element/footstep, FOOTSTEP_MOB_CLAW)
AddElement(/datum/element/basic_eating, food_types = target_foods)
- AddElement(\
- /datum/element/amputating_limbs,\
+ AddComponent(\
+ /datum/component/amputating_limbs,\
surgery_verb = "begins snipping",\
target_zones = GLOB.arm_zones,\
)
diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm
index 20164d27b425a..d6dc119de58a3 100644
--- a/code/modules/mob/living/carbon/carbon_defense.dm
+++ b/code/modules/mob/living/carbon/carbon_defense.dm
@@ -698,5 +698,7 @@
. |= SHOVE_CAN_STAGGER
if(IsKnockdown() && !IsParalyzed())
. |= SHOVE_CAN_KICK_SIDE
+ if(HAS_TRAIT(src, TRAIT_NO_SIDE_KICK)) // added as an extra check, just in case
+ . &= ~SHOVE_CAN_KICK_SIDE
#undef SHAKE_ANIMATION_OFFSET
diff --git a/code/modules/mob/living/carbon/human/species_types/snail.dm b/code/modules/mob/living/carbon/human/species_types/snail.dm
index 053953e2a835f..741e40bed6b33 100644
--- a/code/modules/mob/living/carbon/human/species_types/snail.dm
+++ b/code/modules/mob/living/carbon/human/species_types/snail.dm
@@ -89,8 +89,7 @@
. = ..()
var/obj/item/storage/backpack/bag = new_snailperson.get_item_by_slot(ITEM_SLOT_BACK)
if(!istype(bag, /obj/item/storage/backpack/snail))
- if(new_snailperson.dropItemToGround(bag)) //returns TRUE even if its null
- new_snailperson.equip_to_slot_or_del(new /obj/item/storage/backpack/snail(new_snailperson), ITEM_SLOT_BACK)
+ new_snailperson.equip_to_slot_or_del(new /obj/item/storage/backpack/snail(new_snailperson), ITEM_SLOT_BACK)
new_snailperson.AddElement(/datum/element/lube_walking, require_resting = TRUE)
new_snailperson.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/snail, multiplicative_slowdown = snail_speed_mod)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
index 8fc667df5a876..464636cbb204d 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/wendigo.dm
@@ -187,11 +187,14 @@ Difficulty: Hard
if(!true_spawn)
return ..()
+ create_portal()
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/wendigo/proc/create_portal()
var/obj/effect/portal/permanent/one_way/exit = new /obj/effect/portal/permanent/one_way(starting)
exit.id = "wendigo arena exit"
exit.add_atom_colour(COLOR_RED_LIGHT, ADMIN_COLOUR_PRIORITY)
exit.set_light(20, 1, COLOR_SOFT_RED)
- return ..()
/obj/projectile/colossus/wendigo_shockwave
name = "wendigo shockwave"
@@ -265,4 +268,7 @@ Difficulty: Hard
w_class = WEIGHT_CLASS_TINY
throwforce = 0
+/mob/living/simple_animal/hostile/megafauna/wendigo/noportal/create_portal()
+ return
+
#undef WENDIGO_ENRAGED
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index d186661d87fae..5d46f3c0dc06a 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -67,6 +67,7 @@
transformation_timer = addtimer(CALLBACK(src, PROC_REF(finish_humanize), species), TRANSFORMATION_DURATION, TIMER_UNIQUE)
+
/mob/living/carbon/proc/finish_humanize(species = /datum/species/human)
transformation_timer = null
to_chat(src, span_boldnotice("You are now a human."))
@@ -77,6 +78,12 @@
SEND_SIGNAL(src, COMSIG_MONKEY_HUMANIZE)
return src
+/mob/living/carbon/human/finish_humanize(species = /datum/species/human, instant = FALSE)
+ underwear = "Nude"
+ undershirt = "Nude"
+ socks = "Nude"
+ return ..()
+
/mob/proc/AIize(client/preference_source, move = TRUE)
var/list/turf/landmark_loc = list()
diff --git a/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm b/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
index 0940815f1fc56..0ed30e5a5215d 100644
--- a/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
+++ b/code/modules/mob_spawn/corpses/nanotrasen_corpses.dm
@@ -25,7 +25,7 @@
suit = /obj/item/clothing/suit/armor/bulletproof
ears = /obj/item/radio/headset/heads/captain
glasses = /obj/item/clothing/glasses/eyepatch
- mask = /obj/item/clothing/mask/cigarette/cigar/cohiba
+ mask = /obj/item/cigarette/cigar/cohiba
head = /obj/item/clothing/head/hats/centhat
gloves = /obj/item/clothing/gloves/tackler/combat
shoes = /obj/item/clothing/shoes/combat/swat
diff --git a/code/modules/mob_spawn/ghost_roles/space_roles.dm b/code/modules/mob_spawn/ghost_roles/space_roles.dm
index 764d20c9a76c1..79d028bdbcb27 100644
--- a/code/modules/mob_spawn/ghost_roles/space_roles.dm
+++ b/code/modules/mob_spawn/ghost_roles/space_roles.dm
@@ -181,6 +181,6 @@
ears = /obj/item/radio/headset/syndicate/alt/leader
glasses = /obj/item/clothing/glasses/thermal/eyepatch
head = /obj/item/clothing/head/hats/hos/cap/syndicate
- mask = /obj/item/clothing/mask/cigarette/cigar/havana
+ mask = /obj/item/cigarette/cigar/havana
l_pocket = /obj/item/melee/energy/sword/saber/red
r_pocket = /obj/item/melee/baton/telescopic
diff --git a/code/modules/modular_computers/computers/item/pda.dm b/code/modules/modular_computers/computers/item/pda.dm
index ca10b6c53ad84..2fb7863445de2 100644
--- a/code/modules/modular_computers/computers/item/pda.dm
+++ b/code/modules/modular_computers/computers/item/pda.dm
@@ -46,7 +46,7 @@
/obj/item/lipstick,
/obj/item/flashlight/pen,
/obj/item/reagent_containers/hypospray/medipen,
- /obj/item/clothing/mask/cigarette,
+ /obj/item/cigarette,
)
/obj/item/modular_computer/pda/Initialize(mapload)
diff --git a/code/modules/pai/pai.dm b/code/modules/pai/pai.dm
index 11334f12abc79..acde3c51a5c50 100644
--- a/code/modules/pai/pai.dm
+++ b/code/modules/pai/pai.dm
@@ -470,7 +470,7 @@
for(var/mob/living/cultist as anything in invokers)
to_chat(cultist, span_cult_italic("You don't think this is what Nar'Sie had in mind when She asked for blood sacrifices..."))
- return STOP_SACRIFICE
+ return STOP_SACRIFICE|SILENCE_SACRIFICE_MESSAGE
/// Updates the distance we can be from our pai card
/mob/living/silicon/pai/proc/increment_range(increment_amount)
diff --git a/code/modules/power/supermatter/supermatter.dm b/code/modules/power/supermatter/supermatter.dm
index 1c50f8312d4ae..76951670c9831 100644
--- a/code/modules/power/supermatter/supermatter.dm
+++ b/code/modules/power/supermatter/supermatter.dm
@@ -153,7 +153,10 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
///Stores the time of when the last zap occurred
var/last_power_zap = 0
- var/last_high_energy_zap = 0
+ ///Stores the tick of the machines subsystem of when the last zap occurred. Gives a passage of time in the perspective of SSmachines.
+ var/last_power_zap_perspective_machines = 0
+ ///Same as [last_power_zap_perspective_machines], but based around the high energy zaps found in handle_high_power().
+ var/last_high_energy_zap_perspective_machines = 0
///Do we show this crystal in the CIMS modular program
var/include_in_cims = TRUE
@@ -294,13 +297,11 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
// PART 3: POWER PROCESSING
internal_energy_factors = calculate_internal_energy()
zap_factors = calculate_zap_transmission_rate()
- if(internal_energy && (last_power_zap + (4 - internal_energy * 0.001) SECONDS) < world.time)
+ var/delta_time = (SSmachines.times_fired - last_power_zap_perspective_machines) * SSmachines.wait / (1 SECONDS)
+ if(delta_time && internal_energy && (last_power_zap + (4 - internal_energy * 0.001) SECONDS) < world.time)
playsound(src, 'sound/weapons/emitter2.ogg', 70, TRUE)
hue_angle_shift = clamp(903 * log(10, (internal_energy + 8000)) - 3590, -50, 240)
var/zap_color = color_matrix_rotate_hue(hue_angle_shift)
- //Scale the strength of the zap with the world's time elapsed between zaps in seconds.
- //Capped at 16 seconds to prevent a crazy burst of energy if atmos was halted for a long time.
- var/delta_time = min((world.time - last_power_zap) * 0.1, 16)
supermatter_zap(
zapstart = src,
range = 3,
@@ -311,6 +312,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
color = zap_color,
)
last_power_zap = world.time
+ last_power_zap_perspective_machines = SSmachines.times_fired
// PART 4: DAMAGE PROCESSING
temp_limit_factors = calculate_temp_limit()
@@ -714,6 +716,7 @@ GLOBAL_DATUM(main_supermatter_engine, /obj/machinery/power/supermatter_crystal)
activation_logged = TRUE // so we dont spam the log.
else if(!internal_energy)
last_power_zap = world.time
+ last_power_zap_perspective_machines = SSmachines.times_fired
return additive_power
/** Log when the supermatter is activated for the first time.
diff --git a/code/modules/power/supermatter/supermatter_extra_effects.dm b/code/modules/power/supermatter/supermatter_extra_effects.dm
index efd84c677fafa..35c96d298dd34 100644
--- a/code/modules/power/supermatter/supermatter_extra_effects.dm
+++ b/code/modules/power/supermatter/supermatter_extra_effects.dm
@@ -91,7 +91,7 @@
/obj/machinery/power/supermatter_crystal/proc/handle_high_power()
if(internal_energy <= POWER_PENALTY_THRESHOLD && damage <= danger_point) //If the power is above 5000 or if the damage is above 550
- last_high_energy_zap = world.time //Prevent oddly high initial zap due to high energy zaps not getting triggered via too low energy.
+ last_high_energy_zap_perspective_machines = SSmachines.times_fired //Prevent oddly high initial zap due to high energy zaps not getting triggered via too low energy.
return
var/range = 4
zap_cutoff = 1500
@@ -129,10 +129,10 @@
if(zap_count >= 1)
playsound(loc, 'sound/weapons/emitter2.ogg', 100, TRUE, extrarange = 10)
- var/delta_time = min((world.time - last_high_energy_zap) * 0.1, 16)
+ var/delta_time = (SSmachines.times_fired - last_high_energy_zap_perspective_machines) * SSmachines.wait / (1 SECONDS)
for(var/i in 1 to zap_count)
supermatter_zap(src, range, clamp(internal_energy * 3200, 6.4e6, 3.2e7) * delta_time, flags, zap_cutoff = src.zap_cutoff * delta_time, power_level = internal_energy, zap_icon = src.zap_icon)
- last_high_energy_zap = world.time
+ last_high_energy_zap_perspective_machines = SSmachines.times_fired
if(prob(5))
supermatter_anomaly_gen(src, FLUX_ANOMALY, rand(5, 10))
if(prob(5))
diff --git a/code/modules/projectiles/boxes_magazines/_box_magazine.dm b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
index 62f9185d2145c..207190d08f924 100644
--- a/code/modules/projectiles/boxes_magazines/_box_magazine.dm
+++ b/code/modules/projectiles/boxes_magazines/_box_magazine.dm
@@ -94,7 +94,7 @@
stack_trace("Tried loading unsupported ammocasing type [load_type] into ammo box [type].")
return
- for(var/i in max(1, stored_ammo.len) to max_ammo)
+ for(var/i in max(1, stored_ammo.len + 1) to max_ammo)
stored_ammo += new round_check(src)
update_appearance()
diff --git a/code/modules/projectiles/boxes_magazines/internal/revolver.dm b/code/modules/projectiles/boxes_magazines/internal/revolver.dm
index 7d881a11c4dca..e74a192d6900f 100644
--- a/code/modules/projectiles/boxes_magazines/internal/revolver.dm
+++ b/code/modules/projectiles/boxes_magazines/internal/revolver.dm
@@ -16,7 +16,10 @@
caliber = CALIBER_357
max_ammo = 6
multiload = FALSE
+ start_empty = TRUE
-/obj/item/ammo_box/magazine/internal/rus357/Initialize(mapload)
- stored_ammo += new ammo_type(src)
+/obj/item/ammo_box/magazine/internal/cylinder/rus357/Initialize(mapload)
. = ..()
+ for (var/i in 1 to max_ammo - 1)
+ stored_ammo += new /obj/item/ammo_casing/a357/spent(src)
+ stored_ammo += new /obj/item/ammo_casing/a357(src)
diff --git a/code/modules/projectiles/guns/magic/wand.dm b/code/modules/projectiles/guns/magic/wand.dm
index e8f41ef0b48ec..b2fe293eae8c2 100644
--- a/code/modules/projectiles/guns/magic/wand.dm
+++ b/code/modules/projectiles/guns/magic/wand.dm
@@ -277,3 +277,78 @@
charges--
user.AddComponent(/datum/component/shrink, -1) // small forever
return ..()
+
+// Wand of debugging
+
+#ifdef TESTING
+
+/obj/item/gun/magic/wand/antag
+ name = "wand of antag"
+ desc = "This wand uses the powers of bullshit to turn anyone it hits into an antag"
+ school = SCHOOL_FORBIDDEN
+ ammo_type = /obj/item/ammo_casing/magic/antag
+ icon_state = "revivewand"
+ base_icon_state = "revivewand"
+ color = COLOR_ADMIN_PINK
+ max_charges = 99999
+
+/obj/item/gun/magic/wand/antag/zap_self(mob/living/user)
+ . = ..()
+ var/obj/item/ammo_casing/magic/antag/casing = new ammo_type()
+ var/obj/projectile/magic/magic_proj = casing.projectile_type
+ magic_proj = new magic_proj(src)
+ magic_proj.on_hit(user)
+ QDEL_NULL(casing)
+
+/obj/item/ammo_casing/magic/antag
+ projectile_type = /obj/projectile/magic/antag
+ harmful = FALSE
+
+/obj/projectile/magic/antag
+ name = "bolt of antag"
+ icon_state = "ion"
+ var/antag = /datum/antagonist/traitor
+
+/obj/projectile/magic/antag/on_hit(atom/target, blocked, pierce_hit)
+ . = ..()
+
+ if(isliving(target))
+ var/mob/living/victim = target
+ if(isnull(victim.mind))
+ victim.mind_initialize()
+ if(victim.mind.has_antag_datum(antag))
+ victim.mind.remove_antag_datum(antag)
+ to_chat(world, "removed")
+ else
+ victim.mind.add_antag_datum(antag)
+ to_chat(world, "added")
+
+/obj/item/gun/magic/wand/antag/heretic
+ name = "wand of antag heretic"
+ desc = "This wand uses the powers of bullshit to turn anyone it hits into an antag heretic"
+ color = COLOR_GREEN
+ ammo_type = /obj/item/ammo_casing/magic/antag/heretic
+
+/obj/item/ammo_casing/magic/antag/heretic
+ projectile_type = /obj/projectile/magic/antag/heretic
+
+/obj/projectile/magic/antag/heretic
+ name = "bolt of antag heretic"
+ icon_state = "ion"
+ antag = /datum/antagonist/heretic
+
+/obj/item/gun/magic/wand/antag/cult
+ name = "wand of antag cultist"
+ desc = "This wand uses the powers of bullshit to turn anyone it hits into an antag cultist"
+ color = COLOR_CULT_RED
+ ammo_type = /obj/item/ammo_casing/magic/antag/cult
+
+/obj/item/ammo_casing/magic/antag/cult
+ projectile_type = /obj/projectile/magic/antag/cult
+
+/obj/projectile/magic/antag/cult
+ name = "bolt of antag cult"
+ icon_state = "ion"
+ antag = /datum/antagonist/cult
+
+#endif
diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm
index 720b513e026ab..c69de9bb2d9c1 100644
--- a/code/modules/research/machinery/_production.dm
+++ b/code/modules/research/machinery/_production.dm
@@ -21,8 +21,11 @@
var/stripe_color = null
///direction we output onto (if 0, on top of us)
var/drop_direction = 0
+ //looping sound for printing items
+ var/datum/looping_sound/lathe_print/print_sound
/obj/machinery/rnd/production/Initialize(mapload)
+ print_sound = new(src, FALSE)
materials = AddComponent(
/datum/component/remote_materials, \
mapload, \
@@ -48,6 +51,7 @@
update_icon(UPDATE_OVERLAYS)
/obj/machinery/rnd/production/Destroy()
+ QDEL_NULL(print_sound)
materials = null
cached_designs = null
return ..()
@@ -347,6 +351,7 @@
//start production
busy = TRUE
SStgui.update_uis(src)
+ print_sound.start()
if(production_animation)
icon_state = production_animation
var/turf/target_location
@@ -448,7 +453,7 @@
/// Called at the end of do_make_item's timer loop
/obj/machinery/rnd/production/proc/finalize_build()
PROTECTED_PROC(TRUE)
-
+ print_sound.stop()
busy = FALSE
SStgui.update_uis(src)
icon_state = initial(icon_state)
diff --git a/code/modules/shuttle/navigation_computer.dm b/code/modules/shuttle/navigation_computer.dm
index f8b460a783d0d..d3184cc96c62f 100644
--- a/code/modules/shuttle/navigation_computer.dm
+++ b/code/modules/shuttle/navigation_computer.dm
@@ -20,7 +20,9 @@
// Traits forbided for custom docking
var/list/locked_traits = list(ZTRAIT_RESERVED, ZTRAIT_CENTCOM, ZTRAIT_AWAY)
var/view_range = 0
+ ///x offset for where the camera eye will spawn. Starts from shuttle's docking port
var/x_offset = 0
+ ///y offset for where the camera eye will spawn. Starts from the shuttle's docking port
var/y_offset = 0
var/list/whitelist_turfs = list(/turf/open/space, /turf/open/floor/plating, /turf/open/lava, /turf/open/openspace)
var/see_hidden = FALSE
diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm
index fbe3e52e5030f..68a0a41a2e092 100644
--- a/code/modules/shuttle/shuttle.dm
+++ b/code/modules/shuttle/shuttle.dm
@@ -379,6 +379,7 @@
"whiteship_tram",
"whiteship_personalshuttle",
"whiteship_obelisk",
+ "whiteship_birdshot",
)
/// Helper proc that tests to ensure all whiteship templates can spawn at their docking port, and logs their sizes
diff --git a/code/modules/spells/spell.dm b/code/modules/spells/spell.dm
index dc30f36149bc6..f76ecb104e72b 100644
--- a/code/modules/spells/spell.dm
+++ b/code/modules/spells/spell.dm
@@ -246,7 +246,11 @@
return target // They're just standing around, proceed as normal
if(HAS_TRAIT(cast_loc, TRAIT_CASTABLE_LOC))
- return cast_loc // They're in an atom which allows casting, so redirect the caster to loc
+ if(HAS_TRAIT(cast_loc, TRAIT_SPELLS_TRANSFER_TO_LOC) && ismob(cast_loc.loc))
+ return cast_loc.loc
+ else
+ return cast_loc
+ // They're in an atom which allows casting, so redirect the caster to loc
return null
diff --git a/code/modules/spells/spell_types/pointed/_pointed.dm b/code/modules/spells/spell_types/pointed/_pointed.dm
index 04c3ed47944b9..edf3dab2179d4 100644
--- a/code/modules/spells/spell_types/pointed/_pointed.dm
+++ b/code/modules/spells/spell_types/pointed/_pointed.dm
@@ -16,7 +16,7 @@
var/deactive_msg
/// The casting range of our spell
var/cast_range = 7
- /// Variable dictating if the spell will use turf based aim assist
+ /// If aim asisst is used. Disable to disable
var/aim_assist = TRUE
/datum/action/cooldown/spell/pointed/New(Target)
@@ -65,17 +65,18 @@
return TRUE
/datum/action/cooldown/spell/pointed/InterceptClickOn(mob/living/caller, params, atom/target)
-
var/atom/aim_assist_target
- if(aim_assist && isturf(target))
- // Find any human in the list. We aren't picky, it's aim assist after all
- aim_assist_target = locate(/mob/living/carbon/human) in target
- if(!aim_assist_target)
- // If we didn't find a human, we settle for any living at all
- aim_assist_target = locate(/mob/living) in target
-
+ if(aim_assist)
+ aim_assist_target = aim_assist(caller, target)
return ..(caller, params, aim_assist_target || target)
+/datum/action/cooldown/spell/pointed/proc/aim_assist(mob/living/caller, atom/target)
+ if(!isturf(target))
+ return
+
+ // Find any human, or if that fails, any living target
+ return locate(/mob/living/carbon/human) in target || locate(/mob/living) in target
+
/datum/action/cooldown/spell/pointed/is_valid_target(atom/cast_on)
if(cast_on == owner)
to_chat(owner, span_warning("You cannot cast [src] on yourself!"))
diff --git a/code/modules/surgery/blood_filter.dm b/code/modules/surgery/blood_filter.dm
index 0193ee9c01a8d..d56e35ca9e73b 100644
--- a/code/modules/surgery/blood_filter.dm
+++ b/code/modules/surgery/blood_filter.dm
@@ -15,6 +15,13 @@
return ..()
/datum/surgery_step/filter_blood/initiate(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, try_to_fail = FALSE)
+ display_results(
+ user,
+ target,
+ span_notice("You begin filtering [target]'s blood..."),
+ span_notice("[user] uses [tool] to filter [target]'s blood."),
+ span_notice("[user] uses [tool] on [target]'s chest."),
+ )
if(!..())
return
while(has_filterable_chems(target, tool))
@@ -33,6 +40,8 @@
*/
/datum/surgery_step/filter_blood/proc/has_filterable_chems(mob/living/carbon/target, obj/item/blood_filter/bloodfilter)
if(!length(target.reagents?.reagent_list))
+ bloodfilter.audible_message(span_notice("The [bloodfilter] pings as it reports no chemicals detected in [target]'s blood."))
+ playsound(get_turf(target), 'sound/machines/ping.ogg', 75, TRUE, falloff_exponent = 12, falloff_distance = 1)
return FALSE
if(!length(bloodfilter.whitelist))
@@ -49,16 +58,9 @@
implements = list(/obj/item/blood_filter = 95)
repeatable = TRUE
time = 2.5 SECONDS
- success_sound = 'sound/machines/ping.ogg'
+ success_sound = 'sound/machines/fan_loop.ogg'
/datum/surgery_step/filter_blood/preop(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery)
- display_results(
- user,
- target,
- span_notice("You begin filtering [target]'s blood..."),
- span_notice("[user] uses [tool] to filter [target]'s blood."),
- span_notice("[user] uses [tool] on [target]'s chest."),
- )
display_pain(target, "You feel a throbbing pain in your chest!")
/datum/surgery_step/filter_blood/success(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery, default_display_results = FALSE)
@@ -70,9 +72,9 @@
display_results(
user,
target,
- span_notice("\The [tool] pings as it finishes filtering [target]'s blood."),
- span_notice("\The [tool] pings as it stops pumping [target]'s blood."),
- span_notice("\The [tool] pings as it stops pumping."),
+ span_notice("\The [tool] completes a cycle filtering [target]'s blood."),
+ span_notice("\The [tool] whirrs as it filters [target]'s blood."),
+ span_notice("\The [tool] whirrs as it pumps."),
)
if(locate(/obj/item/healthanalyzer) in user.held_items)
diff --git a/code/modules/surgery/bodyparts/helpers.dm b/code/modules/surgery/bodyparts/helpers.dm
index fb0647d0fb504..863cdd9cb61c2 100644
--- a/code/modules/surgery/bodyparts/helpers.dm
+++ b/code/modules/surgery/bodyparts/helpers.dm
@@ -48,6 +48,15 @@
which_hand = BODY_ZONE_PRECISE_R_HAND
return get_bodypart(check_zone(which_hand))
+/// Gets the inactive hand of the mob. Returns FALSE on non-carbons, otherwise returns the /obj/item/bodypart.
+/mob/proc/get_inactive_hand()
+ return null
+
+/mob/living/carbon/get_inactive_hand()
+ var/which_hand = BODY_ZONE_PRECISE_R_HAND
+ if(!(active_hand_index % RIGHT_HANDS))
+ which_hand = BODY_ZONE_PRECISE_L_HAND
+ return get_bodypart(check_zone(which_hand))
/mob/proc/has_left_hand(check_disabled = TRUE)
return TRUE
diff --git a/code/modules/surgery/organs/internal/heart/heart_anomalock.dm b/code/modules/surgery/organs/internal/heart/heart_anomalock.dm
index 3016d52912e35..e9da6197ed273 100644
--- a/code/modules/surgery/organs/internal/heart/heart_anomalock.dm
+++ b/code/modules/surgery/organs/internal/heart/heart_anomalock.dm
@@ -114,19 +114,20 @@
/obj/item/organ/internal/heart/cybernetic/anomalock/proc/get_held_mob()
return owner
-/obj/item/organ/internal/heart/cybernetic/anomalock/attackby(obj/item/item, mob/living/user, params)
- if(!istype(item.type, required_anomaly))
- return ..()
+/obj/item/organ/internal/heart/cybernetic/anomalock/item_interaction(mob/living/user, obj/item/tool, list/modifiers)
+ if(!istype(tool, required_anomaly))
+ return NONE
if(core)
balloon_alert(user, "core already in!")
- return
- if(!user.transferItemToLoc(item, src))
- return
- core = item
+ return ITEM_INTERACT_BLOCKING
+ if(!user.transferItemToLoc(tool, src))
+ return ITEM_INTERACT_BLOCKING
+ core = tool
balloon_alert(user, "core installed")
playsound(src, 'sound/machines/click.ogg', 30, TRUE)
add_organ_trait(TRAIT_SHOCKIMMUNE)
update_icon_state()
+ return ITEM_INTERACT_SUCCESS
/obj/item/organ/internal/heart/cybernetic/anomalock/screwdriver_act(mob/living/user, obj/item/tool)
. = ..()
diff --git a/code/modules/unit_tests/outfit_sanity.dm b/code/modules/unit_tests/outfit_sanity.dm
index 554d226ed2e72..36fc4570540f4 100644
--- a/code/modules/unit_tests/outfit_sanity.dm
+++ b/code/modules/unit_tests/outfit_sanity.dm
@@ -16,7 +16,7 @@
uniform = /obj/item/clothing/under/suit/tuxedo
glasses = /obj/item/clothing/glasses/sunglasses
- mask = /obj/item/clothing/mask/cigarette/cigar/havana
+ mask = /obj/item/cigarette/cigar/havana
shoes = /obj/item/clothing/shoes/laceup
l_hand = /obj/item/stack/spacecash/c1000
r_hand = /obj/item/stack/spacecash/c1000
@@ -25,19 +25,19 @@
/datum/outfit/duffel_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack/duffelbag
- backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
+ backpack_contents = list(/obj/item/cigarette/cigar/havana)
/// Satchels too
/datum/outfit/stachel_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack/satchel
- backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
+ backpack_contents = list(/obj/item/cigarette/cigar/havana)
/// And just in case we'll check backpacks
/datum/outfit/backpack_user
name = "Mr. Runtime"
back = /obj/item/storage/backpack
- backpack_contents = list(/obj/item/clothing/mask/cigarette/cigar/havana)
+ backpack_contents = list(/obj/item/cigarette/cigar/havana)
/datum/unit_test/outfit_sanity/Run()
var/datum/outfit/prototype_outfit = /datum/outfit
diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm
index 267e610c06661..2f4f7a4b70ae7 100644
--- a/code/modules/unit_tests/simple_animal_freeze.dm
+++ b/code/modules/unit_tests/simple_animal_freeze.dm
@@ -57,6 +57,7 @@
/mob/living/simple_animal/hostile/megafauna/legion/medium/right,
/mob/living/simple_animal/hostile/megafauna/legion/small,
/mob/living/simple_animal/hostile/megafauna/wendigo,
+ /mob/living/simple_animal/hostile/megafauna/wendigo/noportal,
/mob/living/simple_animal/hostile/mimic,
/mob/living/simple_animal/hostile/mimic/copy,
/mob/living/simple_animal/hostile/mimic/copy/machine,
diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm
index 47c116cbc6029..33edb9e47c777 100644
--- a/code/modules/vehicles/mecha/mech_fabricator.dm
+++ b/code/modules/vehicles/mecha/mech_fabricator.dm
@@ -49,12 +49,20 @@
/// All designs in the techweb that can be fabricated by this machine, since the last update.
var/list/datum/design/cached_designs
+ //looping sound for printing items
+ var/datum/looping_sound/lathe_print/print_sound
+
/obj/machinery/mecha_part_fabricator/Initialize(mapload)
+ print_sound = new(src, FALSE)
rmat = AddComponent(/datum/component/remote_materials, mapload && link_on_init)
cached_designs = list()
RefreshParts() //Recalculating local material sizes if the fab isn't linked
return ..()
+/obj/machinery/mecha_part_fabricator/Destroy()
+ QDEL_NULL(print_sound)
+ return ..()
+
/obj/machinery/mecha_part_fabricator/post_machine_initialize()
. = ..()
if(!CONFIG_GET(flag/no_default_techweb_link) && !stored_research)
@@ -163,7 +171,7 @@
/obj/machinery/mecha_part_fabricator/proc/on_start_printing()
add_overlay("fab-active")
update_use_power(ACTIVE_POWER_USE)
-
+ print_sound.start()
/**
* Intended to be called when the exofab has stopped working and is no longer printing items.
*
@@ -174,6 +182,7 @@
update_use_power(IDLE_POWER_USE)
desc = initial(desc)
process_queue = FALSE
+ print_sound.stop()
/**
* Attempts to build the next item in the build queue.
diff --git a/code/modules/vending/cigarette.dm b/code/modules/vending/cigarette.dm
index ddcfd9bb244d9..61379e5635468 100644
--- a/code/modules/vending/cigarette.dm
+++ b/code/modules/vending/cigarette.dm
@@ -17,7 +17,7 @@
/obj/item/storage/fancy/rollingpapers = 5,
)
contraband = list(
- /obj/item/clothing/mask/vape = 5,
+ /obj/item/vape = 5,
)
premium = list(
/obj/item/storage/fancy/cigarettes/cigpack_robustgold = 3,
@@ -66,7 +66,7 @@
)
premium = list(
/obj/item/storage/fancy/cigarettes/cigpack_mindbreaker = 5,
- /obj/item/clothing/mask/vape = 5,
+ /obj/item/vape = 5,
/obj/item/lighter = 3,
)
initial_language_holder = /datum/language_holder/beachbum
diff --git a/html/changelogs/AutoChangeLog-pr-84011.yml b/html/changelogs/AutoChangeLog-pr-84011.yml
new file mode 100644
index 0000000000000..12b730fefdcdf
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-84011.yml
@@ -0,0 +1,4 @@
+author: "Pickle-Coding"
+delete-after: True
+changes:
+ - code_imp: "Supermatter zap power generation takes perspective of the machines subsystem."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-84230.yml b/html/changelogs/AutoChangeLog-pr-84230.yml
new file mode 100644
index 0000000000000..165b6de5e2c7a
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-84230.yml
@@ -0,0 +1,4 @@
+author: "SmArtKar"
+delete-after: True
+changes:
+ - bugfix: "Vent-born wendigos no longer create one-way portals"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-84374.yml b/html/changelogs/AutoChangeLog-pr-84374.yml
new file mode 100644
index 0000000000000..5b4a368896c57
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-84374.yml
@@ -0,0 +1,4 @@
+author: "ShizCalev"
+delete-after: True
+changes:
+ - bugfix: "The power for all science burn chambers across all maps now works properly."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-84439.yml b/html/changelogs/AutoChangeLog-pr-84439.yml
new file mode 100644
index 0000000000000..fd4591d8f8792
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-84439.yml
@@ -0,0 +1,4 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - rscadd: "Humanizing a monkey removes undergarments such as socks"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-84448.yml b/html/changelogs/AutoChangeLog-pr-84448.yml
new file mode 100644
index 0000000000000..b579cc85ac2e3
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-84448.yml
@@ -0,0 +1,4 @@
+author: "thegrb93"
+delete-after: True
+changes:
+ - bugfix: "Game not refocusing after closing a TGUI"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-84449.yml b/html/changelogs/AutoChangeLog-pr-84449.yml
deleted file mode 100644
index c7608d665204f..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-84449.yml
+++ /dev/null
@@ -1,5 +0,0 @@
-author: "SmArtKar"
-delete-after: True
-changes:
- - bugfix: "Storage no longer deletes all of its viewers upon being deleted"
- - bugfix: "Storage UI now renders properly"
\ No newline at end of file
diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml
index 53e753d99ed9b..100647af4323c 100644
--- a/html/changelogs/archive/2024-06.yml
+++ b/html/changelogs/archive/2024-06.yml
@@ -1369,3 +1369,49 @@
- bugfix: Emergency firesuits no longer hide your gloves.
- qol: Punching bags are now a equal method of training to the fitness machinery.
- qol: Boxing grants more experience overall for participation.
+2024-06-30:
+ Exester509:
+ - spellcheck: Fixed two typos in the heretic lore
+ Ghommie:
+ - bugfix: cigarettes and vapes are no longer treated as clothing (eg. They no longer
+ get shredded and need to be repaired with... cloth).
+ GoblinBackwards:
+ - bugfix: Fixed gas canister shields turning themselves off in unpowered areas when
+ they weren't drawing any cell power.
+ LT3:
+ - code_imp: Blood filter only pings and says finished when it's actually finished
+ Sadboysuss:
+ - bugfix: fixed cyborgs and monkeys not being able to buckle to chairs
+ SmArtKar:
+ - bugfix: Storage no longer deletes all of its viewers upon being deleted
+ - bugfix: Storage UI now renders properly
+ - bugfix: Guns no longer can be overfilled by 1 bullet
+ - bugfix: Russian revolvers now spawn with only 1 live round as originally intended,
+ and click when firing a blank.
+ Xander3359:
+ - bugfix: Fix being unable to add a flux core to new the combat heart cybernetic
+ aaaa1023:
+ - bugfix: Fixed the camera offset for the navigation console on a handful of Whiteships.
+ - bugfix: Fixed the Pubby Whiteship drifting sideways through hyperspace when in
+ flight.
+ - bugfix: Fixed the Kilo Whiteship flying backwards through hyperspace when in flight.
+ - bugfix: The Birdshot Whiteship should actually be able to spawn now.
+ - spellcheck: fixed spelling of "aggressive" in the shuttle manipulator description
+ for the Birdshot Whiteship.
+ carlarctg:
+ - spellcheck: Syndicate jaws of life are now jaws of death!
+ - spellcheck: Made its desc. more descriptive, stating that its faster.
+ - rscadd: Heretics can now sacrifice Cultists for sweet loot.
+ - rscadd: Cultists can now sacrifice Heretics for sick trinkets.
+ - rscdel: Removed Bastard Blade from the game, code, and life
+ - balance: Aggressive Spread now rusts non-turfs next to you as well
+ - balance: Raise Construction cd raised to 7, now breaks rust walls as well, improved
+ autoaim making it actually usable midfight
+ - refactor: Auto-aim code now works on any atoms if configured
+ grungussuss , Kayozz:
+ - sound: exosuit fabricators, Autolathes and Techfabs will now produce sounds when
+ printing items
+ grungususs:
+ - bugfix: fixed the name of a request console in the medical sec outpost on metastation
+ mc-oofert:
+ - bugfix: both engineers and roboticists may now access the controls of a firebot
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 245cb0a486e7a..67b8ea51c1850 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/actions/actions_cult.dmi b/icons/mob/actions/actions_cult.dmi
index f73f5bb6367fa..7725ae691b4c6 100644
Binary files a/icons/mob/actions/actions_cult.dmi and b/icons/mob/actions/actions_cult.dmi differ
diff --git a/icons/mob/actions/actions_ecult.dmi b/icons/mob/actions/actions_ecult.dmi
index 67b6bf1fd2257..3ce72ae54ffe7 100644
Binary files a/icons/mob/actions/actions_ecult.dmi and b/icons/mob/actions/actions_ecult.dmi differ
diff --git a/icons/mob/clothing/belt.dmi b/icons/mob/clothing/belt.dmi
index 44ede20f2a5a1..a2d318adfb7d1 100644
Binary files a/icons/mob/clothing/belt.dmi and b/icons/mob/clothing/belt.dmi differ
diff --git a/icons/mob/clothing/neck.dmi b/icons/mob/clothing/neck.dmi
index a193fbd74a8e3..ed0bb34b46449 100644
Binary files a/icons/mob/clothing/neck.dmi and b/icons/mob/clothing/neck.dmi differ
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
index e0545c0d89395..d15a47206f984 100644
Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
index bf101ad0ea700..88ad954734bf5 100644
Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/mob/inhands/clothing/masks_lefthand.dmi b/icons/mob/inhands/clothing/masks_lefthand.dmi
index 64fcf4d70bd27..cac122916bdd2 100644
Binary files a/icons/mob/inhands/clothing/masks_lefthand.dmi and b/icons/mob/inhands/clothing/masks_lefthand.dmi differ
diff --git a/icons/mob/inhands/clothing/masks_righthand.dmi b/icons/mob/inhands/clothing/masks_righthand.dmi
index 99f45bd1b17c0..f68f2d905e627 100644
Binary files a/icons/mob/inhands/clothing/masks_righthand.dmi and b/icons/mob/inhands/clothing/masks_righthand.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 967968b339ba7..5515ad69c3486 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index beb3c84860d64..fdad955fd9a6f 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/nonhuman-player/cult.dmi b/icons/mob/nonhuman-player/cult.dmi
index 9241b138227c5..683ee9bd6fe32 100644
Binary files a/icons/mob/nonhuman-player/cult.dmi and b/icons/mob/nonhuman-player/cult.dmi differ
diff --git a/icons/obj/antags/cult/items.dmi b/icons/obj/antags/cult/items.dmi
index 9a3435dcd833e..fcd5f13c85bf5 100644
Binary files a/icons/obj/antags/cult/items.dmi and b/icons/obj/antags/cult/items.dmi differ
diff --git a/icons/obj/antags/cult/structures.dmi b/icons/obj/antags/cult/structures.dmi
index 373371f5a2f98..982742e876492 100644
Binary files a/icons/obj/antags/cult/structures.dmi and b/icons/obj/antags/cult/structures.dmi differ
diff --git a/icons/obj/cigarettes.dmi b/icons/obj/cigarettes.dmi
index 3612c747f50e2..1be85df6c156d 100644
Binary files a/icons/obj/cigarettes.dmi and b/icons/obj/cigarettes.dmi differ
diff --git a/icons/obj/clothing/masks.dmi b/icons/obj/clothing/masks.dmi
index 5cb090978ae7c..436785ce6e5e9 100644
Binary files a/icons/obj/clothing/masks.dmi and b/icons/obj/clothing/masks.dmi differ
diff --git a/icons/obj/clothing/neck.dmi b/icons/obj/clothing/neck.dmi
index e937d125ec2a4..e8726cfcb73a5 100644
Binary files a/icons/obj/clothing/neck.dmi and b/icons/obj/clothing/neck.dmi differ
diff --git a/icons/obj/weapons/khopesh.dmi b/icons/obj/weapons/khopesh.dmi
index 95774e7f6c733..3c4ba40b34ac1 100644
Binary files a/icons/obj/weapons/khopesh.dmi and b/icons/obj/weapons/khopesh.dmi differ
diff --git a/icons/obj/weapons/sword.dmi b/icons/obj/weapons/sword.dmi
index 9b5a989a0514d..d9a443cfc2699 100644
Binary files a/icons/obj/weapons/sword.dmi and b/icons/obj/weapons/sword.dmi differ
diff --git a/sound/machines/attributions.txt b/sound/machines/attributions.txt
new file mode 100644
index 0000000000000..b459be3d3e158
--- /dev/null
+++ b/sound/machines/attributions.txt
@@ -0,0 +1 @@
+sound/machines/lathe/lathe_print.ogg - made by kayozzx (discord) , license: CCbySA
diff --git a/sound/machines/lathe/lathe_print.ogg b/sound/machines/lathe/lathe_print.ogg
new file mode 100644
index 0000000000000..eace2da907558
Binary files /dev/null and b/sound/machines/lathe/lathe_print.ogg differ
diff --git a/tgstation.dme b/tgstation.dme
index 995f4025920a9..7cc15206ec9f2 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -1016,6 +1016,7 @@
#include "code\datums\components\ai_has_target_timer.dm"
#include "code\datums\components\ai_listen_to_weather.dm"
#include "code\datums\components\ai_retaliate_advanced.dm"
+#include "code\datums\components\amputating_limbs.dm"
#include "code\datums\components\anti_magic.dm"
#include "code\datums\components\appearance_on_aggro.dm"
#include "code\datums\components\aquarium_content.dm"
@@ -1372,7 +1373,6 @@
#include "code\datums\elements\ai_retaliate.dm"
#include "code\datums\elements\ai_swap_combat_mode.dm"
#include "code\datums\elements\ai_target_damagesource.dm"
-#include "code\datums\elements\amputating_limbs.dm"
#include "code\datums\elements\animal_variety.dm"
#include "code\datums\elements\art.dm"
#include "code\datums\elements\atmos_requirements.dm"
@@ -1458,6 +1458,7 @@
#include "code\datums\elements\kneejerk.dm"
#include "code\datums\elements\knockback.dm"
#include "code\datums\elements\lazy_fishing_spot.dm"
+#include "code\datums\elements\leeching_walk.dm"
#include "code\datums\elements\lifesteal.dm"
#include "code\datums\elements\light_blocking.dm"
#include "code\datums\elements\light_eaten.dm"
@@ -3050,7 +3051,6 @@
#include "code\modules\antagonists\clown_ops\clownop.dm"
#include "code\modules\antagonists\clown_ops\outfits.dm"
#include "code\modules\antagonists\cult\blood_magic.dm"
-#include "code\modules\antagonists\cult\cult_bastard_sword.dm"
#include "code\modules\antagonists\cult\cult_comms.dm"
#include "code\modules\antagonists\cult\cult_items.dm"
#include "code\modules\antagonists\cult\cult_objectives.dm"
@@ -3063,6 +3063,7 @@
#include "code\modules\antagonists\cult\cult_turf_overlay.dm"
#include "code\modules\antagonists\cult\rune_spawn_action.dm"
#include "code\modules\antagonists\cult\runes.dm"
+#include "code\modules\antagonists\cult\sword_fling.dm"
#include "code\modules\antagonists\cult\datums\constructs.dm"
#include "code\modules\antagonists\cult\datums\cult_team.dm"
#include "code\modules\antagonists\cult\datums\cultist.dm"
@@ -3085,6 +3086,7 @@
#include "code\modules\antagonists\heretic\knife_effect.dm"
#include "code\modules\antagonists\heretic\moon_lunatic.dm"
#include "code\modules\antagonists\heretic\rust_effect.dm"
+#include "code\modules\antagonists\heretic\soultrapped_heretic.dm"
#include "code\modules\antagonists\heretic\transmutation_rune.dm"
#include "code\modules\antagonists\heretic\items\corrupted_organs.dm"
#include "code\modules\antagonists\heretic\items\eldritch_flask.dm"
diff --git a/tgui/packages/tgui/layouts/Window.tsx b/tgui/packages/tgui/layouts/Window.tsx
index aa91370bfc31e..abf35d8a31142 100644
--- a/tgui/packages/tgui/layouts/Window.tsx
+++ b/tgui/packages/tgui/layouts/Window.tsx
@@ -53,30 +53,32 @@ export const Window = (props: Props) => {
const { debugLayout = false } = useDebug();
useEffect(() => {
- const updateGeometry = () => {
- const options = {
- ...config.window,
- size: DEFAULT_SIZE,
+ if (!suspended) {
+ const updateGeometry = () => {
+ const options = {
+ ...config.window,
+ size: DEFAULT_SIZE,
+ };
+
+ if (width && height) {
+ options.size = [width, height];
+ }
+ if (config.window?.key) {
+ setWindowKey(config.window.key);
+ }
+ recallWindowGeometry(options);
};
- if (width && height) {
- options.size = [width, height];
- }
- if (config.window?.key) {
- setWindowKey(config.window.key);
- }
- recallWindowGeometry(options);
- };
-
- Byond.winset(Byond.windowId, {
- 'can-close': Boolean(canClose),
- });
- logger.log('mounting');
- updateGeometry();
-
- return () => {
- logger.log('unmounting');
- };
+ Byond.winset(Byond.windowId, {
+ 'can-close': Boolean(canClose),
+ });
+ logger.log('mounting');
+ updateGeometry();
+
+ return () => {
+ logger.log('unmounting');
+ };
+ }
}, [width, height]);
const dispatch = globalStore.dispatch;
diff --git a/tools/UpdatePaths/Scripts/82942_cigs_vape_repath.txt b/tools/UpdatePaths/Scripts/82942_cigs_vape_repath.txt
new file mode 100644
index 0000000000000..22cf75332bfee
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/82942_cigs_vape_repath.txt
@@ -0,0 +1,2 @@
+/obj/item/clothing/mask/cigarette/@SUBTYPES : /obj/item/cigarette/@SUBTYPES{@OLD}
+/obj/item/clothing/mask/vape/@SUBTYPES : /obj/item/vape/@SUBTYPES{@OLD}
\ No newline at end of file