diff --git a/_maps/map_files/generic/centcomm.dmm b/_maps/map_files/generic/centcomm.dmm
index ae1be9f66b73..b9ddf7c0f50e 100644
--- a/_maps/map_files/generic/centcomm.dmm
+++ b/_maps/map_files/generic/centcomm.dmm
@@ -7674,6 +7674,10 @@
icon_state = "darkyellow"
},
/area/centcom/suppy)
+"Bv" = (
+/obj/structure/stone_tile/slab/cracked,
+/turf/simulated/floor/plating/lava/smooth/lava_land_surface,
+/area/ruin/space/bubblegum_arena)
"Bw" = (
/obj/structure/ninjatele{
pixel_x = -28
@@ -8682,6 +8686,10 @@
icon_state = "whiteblue"
},
/area/centcom/control)
+"Fk" = (
+/obj/structure/stone_tile/slab/burnt,
+/turf/simulated/floor/plating/lava/smooth/lava_land_surface,
+/area/ruin/space/bubblegum_arena)
"Fm" = (
/obj/structure/chair/sofa/corp{
dir = 4
@@ -9375,6 +9383,10 @@
/obj/structure/curtain/open/shower,
/turf/simulated/floor/plasteel/freezer,
/area/ghost_bar)
+"HF" = (
+/obj/effect/landmark/spawner/bubblegum_arena,
+/turf/simulated/floor/indestructible/necropolis,
+/area/ruin/space/bubblegum_arena)
"HH" = (
/obj/effect/decal/warning_stripes/north,
/turf/simulated/floor/wood,
@@ -9419,6 +9431,9 @@
/obj/item/gun/energy/immolator/multi,
/turf/simulated/floor/mineral/plastitanium/red,
/area/shuttle/gamma/space)
+"HN" = (
+/turf/simulated/floor/indestructible/necropolis,
+/area/ruin/space/bubblegum_arena)
"HO" = (
/obj/structure/chair/sofa/corp/right,
/turf/simulated/floor/transparent/glass,
@@ -10630,6 +10645,9 @@
/obj/effect/mapping_helpers/airlock/access/any/security/doors,
/turf/simulated/floor/plasteel,
/area/shuttle/escape)
+"LV" = (
+/turf/simulated/floor/plating/lava/smooth/lava_land_surface,
+/area/ruin/space/bubblegum_arena)
"LX" = (
/obj/structure/chair/sofa/corp/left{
dir = 8
@@ -12636,6 +12654,9 @@
icon_state = "vault"
},
/area/centcom/specops)
+"SL" = (
+/turf/simulated/wall/indestructible/necropolis,
+/area/ruin/space/bubblegum_arena)
"SN" = (
/obj/structure/reagent_dispensers/fueltank/chem{
pixel_x = -32
@@ -13426,6 +13447,12 @@
},
/turf/simulated/floor/transparent/glass,
/area/centcom/specops)
+"Wg" = (
+/obj/structure/stone_tile/surrounding/burnt,
+/obj/structure/stone_tile/center/burnt,
+/obj/effect/landmark/spawner/bubblegum,
+/turf/simulated/floor/plating/lava/smooth/lava_land_surface,
+/area/ruin/space/bubblegum_arena)
"Wh" = (
/turf/simulated/floor/plasteel{
dir = 8;
@@ -64493,39 +64520,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
aN
aN
aN
@@ -64750,39 +64777,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -65007,39 +65034,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+LV
+LV
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+LV
+LV
+LV
+HN
+SL
aN
aN
aN
@@ -65264,39 +65291,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -65521,39 +65548,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -65778,39 +65805,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -66035,39 +66062,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -66292,39 +66319,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -66549,39 +66576,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -66806,39 +66833,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -67063,39 +67090,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -67320,39 +67347,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -67577,39 +67604,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -67834,39 +67861,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -68091,39 +68118,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -68348,39 +68375,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Fk
+Fk
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -68605,39 +68632,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Bv
+Bv
+Fk
+Fk
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -68862,39 +68889,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Bv
+Bv
+Bv
+Wg
+Fk
+Fk
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -69119,39 +69146,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Bv
+Bv
+Bv
+Bv
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -69376,39 +69403,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Fk
+Fk
+Bv
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -69633,39 +69660,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+Fk
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -69890,39 +69917,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -70147,39 +70174,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -70404,39 +70431,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -70661,39 +70688,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -70918,39 +70945,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -71175,39 +71202,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -71432,39 +71459,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -71689,39 +71716,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -71946,39 +71973,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -72203,39 +72230,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HF
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+HN
+SL
aN
aN
aN
@@ -72460,39 +72487,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+LV
+LV
+LV
+LV
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+LV
+LV
+LV
+LV
+HN
+SL
aN
aN
aN
@@ -72717,39 +72744,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+HN
+SL
aN
aN
aN
@@ -72974,39 +73001,39 @@ aN
aN
aN
aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
-aN
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
+SL
aN
aN
aN
diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm
index 0b91efc8ca70..2f9617e72037 100644
--- a/code/__DEFINES/dcs/signals.dm
+++ b/code/__DEFINES/dcs/signals.dm
@@ -344,7 +344,7 @@
#define COMSIG_MOB_ITEM_ATTACK "mob_item_attack"
#define COMPONENT_ITEM_NO_ATTACK (1<<0)
///from base of /mob/living/proc/apply_damage(): (damage, damagetype, def_zone)
-#define COMSIG_MOB_APPLY_DAMGE "mob_apply_damage"
+#define COMSIG_MOB_APPLY_DAMAGE "mob_apply_damage"
///from base of obj/item/afterattack(): (atom/target, mob/user, proximity_flag, click_parameters)
#define COMSIG_MOB_ITEM_AFTERATTACK "mob_item_afterattack"
///from base of obj/item/attack_qdeleted(): (atom/target, mob/user, proxiumity_flag, click_parameters)
@@ -500,6 +500,8 @@
// /mob/living/simple_animal/hostile signals
#define COMSIG_HOSTILE_ATTACKINGTARGET "hostile_attackingtarget"
#define COMPONENT_HOSTILE_NO_ATTACK (1<<0)
+//Called when a /mob/living/simple_animal/hostile fines a new target: (atom/source, give_target)
+#define COMSIG_HOSTILE_FOUND_TARGET "comsig_hostile_found_target"
// /obj signals
diff --git a/code/__DEFINES/misc_defines.dm b/code/__DEFINES/misc_defines.dm
index 693598362a8f..61a051fefca9 100644
--- a/code/__DEFINES/misc_defines.dm
+++ b/code/__DEFINES/misc_defines.dm
@@ -553,6 +553,8 @@
#define CLASSIC_CAVES "Classic Caves"
#define DEADLY_DEEPROCK "Deadly Deeprock"
+///Sleep check QDEL. Like sleep check death, but checks deleting. Good for non mobs.
+#define SLEEP_CHECK_QDEL(X) sleep(X); if(QDELETED(src)) return;
// Request console message priority defines
#define RQ_NONEW_MESSAGES 0 // RQ_NONEWMESSAGES = no new message
diff --git a/code/__DEFINES/sound_defines.dm b/code/__DEFINES/sound_defines.dm
index 0aa85d3ccd9c..2a719176b670 100644
--- a/code/__DEFINES/sound_defines.dm
+++ b/code/__DEFINES/sound_defines.dm
@@ -10,13 +10,14 @@
#define CHANNEL_FIREALARM 1016 //fire alarm alarms
#define CHANNEL_ASH_STORM 1015
#define CHANNEL_RADIO_NOISE 1014 // radio headset noise
+#define CHANNEL_BOSS_MUSIC 1013
#define USER_VOLUME(M, C) M?.client?.prefs.get_channel_volume(C)
//THIS SHOULD ALWAYS BE THE LOWEST ONE!
//KEEP IT UPDATED
-#define CHANNEL_HIGHEST_AVAILABLE 1013
+#define CHANNEL_HIGHEST_AVAILABLE 1012
#define MAX_INSTRUMENT_CHANNELS (128 * 6)
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index add6fb00ba91..2c188e81e405 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -102,8 +102,11 @@
#define STATUS_EFFECT_CRYO_BEAM /datum/status_effect/cryo_beam //Chills target, freezes reagents in their blood, breaks if sight is lost.
+#define STATUS_EFFECT_BUBBLEGUM_CURSE /datum/status_effect/bubblegum_curse //Bleeding. Damage over time. Fog. And, of course, a suprise for people that try to run away.
+
#define STATUS_BOOKWYRM /datum/status_effect/bookwyrm
+
//#define STATUS_EFFECT_NECROPOLIS_CURSE /datum/status_effect/necropolis_curse
//#define CURSE_BLINDING 1 //makes the edges of the target's screen obscured
//#define CURSE_SPAWNING 2 //spawns creatures that attack the target only
diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm
index b7de92661161..b9a89f4d33aa 100644
--- a/code/__HELPERS/filters.dm
+++ b/code/__HELPERS/filters.dm
@@ -320,6 +320,6 @@ GLOBAL_LIST_INIT(master_filter_info, list(
in_atom.remove_filter("wibbly-[i]")
/// Used to create rays on an item. Make sure to removefilter("rays") when done with it
-/atom/proc/ray_filter_helper(_priority = 1, _size = 40, _color = "#FFFFFF", _factor = 6, _density = 20)
- add_filter(name = "ray", priority = _priority, params = list(type = "rays", size = _size, color = _color , factor = _factor, density = _density))
+/atom/proc/ray_filter_helper(_priority = 1, _size = 40, _color = "#FFFFFF", _factor = 6, _density = 20, _y = 0)
+ add_filter(name = "ray", priority = _priority, params = list(type = "rays", size = _size, color = _color , factor = _factor, density = _density, y = _y))
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 2c2af7b7691a..2bb8c5ab2f72 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -1593,17 +1593,21 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
y = t_center.y + c_dist - 1
x = t_center.x + c_dist
+ var/list/temp_list_one = list()
for(y in t_center.y-c_dist to y)
T = locate(x,y,t_center.z)
if(T)
- L += T
+ temp_list_one += T
+ L += reverselist(temp_list_one)
y = t_center.y - c_dist
x = t_center.x + c_dist - 1
+ var/list/temp_list_two = list()
for(x in t_center.x-c_dist to x)
T = locate(x,y,t_center.z)
if(T)
- L += T
+ temp_list_two += T
+ L += reverselist(temp_list_two)
y = t_center.y - c_dist + 1
x = t_center.x - c_dist
@@ -2054,6 +2058,8 @@ GLOBAL_DATUM_INIT(dview_mob, /mob/dview, new)
return "Ash Storms"
if(CHANNEL_RADIO_NOISE)
return "Radio Noise"
+ if(CHANNEL_BOSS_MUSIC)
+ return "Boss Music"
/proc/slot_bitfield_to_slot(input_slot_flags) // Kill off this garbage ASAP; slot flags and clothing flags should be IDENTICAL. GOSH DARN IT. Doesn't work with ears or pockets, either.
switch(input_slot_flags)
diff --git a/code/_onclick/hud/fullscreen.dm b/code/_onclick/hud/fullscreen.dm
index 49a45597902d..aa4d3b8a42c7 100644
--- a/code/_onclick/hud/fullscreen.dm
+++ b/code/_onclick/hud/fullscreen.dm
@@ -104,6 +104,11 @@
icon_state = "payback"
show_when_dead = TRUE
+/obj/screen/fullscreen/fog
+ icon = 'icons/mob/screen_fog.dmi'
+ icon_state = "fog"
+ color = "#FF0000"
+
/obj/screen/fullscreen/flash
icon = 'icons/mob/screen_gen.dmi'
screen_loc = "WEST,SOUTH to EAST,NORTH"
diff --git a/code/datums/beam.dm b/code/datums/beam.dm
index 15bc2711bbee..d40051220839 100644
--- a/code/datums/beam.dm
+++ b/code/datums/beam.dm
@@ -131,6 +131,11 @@
..()
A.ex_act(1)
+/obj/effect/ebeam/vetus/Destroy()
+ for(var/mob/living/M in get_turf(src))
+ M.electrocute_act(20, "the giant arc", flags = SHOCK_NOGLOVES) //fuck your gloves.
+ return ..()
+
/obj/effect/ebeam/disintegration_telegraph
alpha = 100
layer = ON_EDGED_TURF_LAYER
diff --git a/code/datums/components/boss_music.dm b/code/datums/components/boss_music.dm
new file mode 100644
index 000000000000..85af91c4d5e1
--- /dev/null
+++ b/code/datums/components/boss_music.dm
@@ -0,0 +1,70 @@
+/**
+ * Attaches to a hostile simplemob and plays that music while they have a target.
+ */
+/datum/component/boss_music
+ ///The music track we will play to players.
+ var/boss_track
+ ///How long the track is, used to clear players out when the music is supposed to end.
+ var/track_duration
+
+ ///List of all mobs listening to the boss music currently. Cleared on Destroy or after `track_duration`.
+ var/list/players_listening_uids = list()
+ ///List of callback timers, used to clear out mobs listening to boss music after `track_duration`.
+ var/list/music_callbacks = list()
+
+/datum/component/boss_music/Initialize(boss_track, track_duration)
+ . = ..()
+ if(!ishostile(parent))
+ return COMPONENT_INCOMPATIBLE
+ src.boss_track = boss_track
+ src.track_duration = track_duration
+
+/datum/component/boss_music/Destroy(force, silent)
+ . = ..()
+ for(var/callback in music_callbacks)
+ deltimer(callback)
+ music_callbacks = null
+
+ for(var/player_refs in players_listening_uids)
+ clear_target(player_refs)
+ players_listening_uids = null
+
+/datum/component/boss_music/RegisterWithParent()
+ . = ..()
+ RegisterSignal(parent, COMSIG_HOSTILE_FOUND_TARGET, PROC_REF(on_target_found))
+
+/datum/component/boss_music/UnregisterFromParent()
+ UnregisterSignal(parent, COMSIG_HOSTILE_FOUND_TARGET)
+ return ..()
+
+///Handles giving the boss music to a new target the fauna has recieved.
+///Keeps track of them to not repeatedly overwrite its own track.
+/datum/component/boss_music/proc/on_target_found(atom/source, mob/new_target)
+ SIGNAL_HANDLER
+ if(QDELETED(source) || !istype(new_target))
+ return
+
+ var/target_uid = new_target.UID()
+ if(target_uid in players_listening_uids)
+ return
+
+ players_listening_uids += target_uid
+ RegisterSignal(new_target, COMSIG_MOB_DEATH, PROC_REF(on_mob_death))
+ music_callbacks += addtimer(CALLBACK(src, PROC_REF(clear_target), target_uid), track_duration, TIMER_STOPPABLE)
+ new_target.playsound_local(new_target, boss_track, 200, FALSE, channel = CHANNEL_BOSS_MUSIC, pressure_affected = FALSE, use_reverb = FALSE)
+
+///Called when a mob listening to boss music dies- ends their music early.
+/datum/component/boss_music/proc/on_mob_death(mob/living/source)
+ SIGNAL_HANDLER
+ var/target_uid = source.UID()
+ clear_target(target_uid)
+
+///Removes `old_target` from the list of players listening, and stops their music if it is still playing.
+///This allows them to have music played again if they re-enter combat with this fauna.
+/datum/component/boss_music/proc/clear_target(incoming_uid)
+ players_listening_uids -= incoming_uid
+
+ var/mob/old_target = locateUID(incoming_uid)
+ if(old_target)
+ UnregisterSignal(old_target, COMSIG_MOB_DEATH)
+ old_target.stop_sound_channel(CHANNEL_BOSS_MUSIC)
diff --git a/code/datums/status_effects/debuffs.dm b/code/datums/status_effects/debuffs.dm
index 757095315be5..4a56b018a94f 100644
--- a/code/datums/status_effects/debuffs.dm
+++ b/code/datums/status_effects/debuffs.dm
@@ -985,3 +985,135 @@
owner.reagents.remove_reagent(R.id, 0.75)
if(prob(10))
to_chat(owner, "Your blood freezes in your veins, get away!")
+
+/datum/status_effect/bubblegum_curse
+ id = "bubblegum curse"
+ alert_type = /obj/screen/alert/status_effect/bubblegum_curse
+ duration = -1 //Kill it. There is no other option.
+ tick_interval = 1 SECONDS
+ /// The damage the status effect does per tick.
+ var/damage = 0.75
+ var/source_UID
+ /// Are we starting the process to check if the person has still gotten out of range of bubble / crossed zlvls.
+ var/coward_checking = FALSE
+
+/datum/status_effect/bubblegum_curse/on_creation(mob/living/new_owner, mob/living/source)
+ . = ..()
+ source_UID = source.UID()
+ owner.overlay_fullscreen("Bubblegum", /obj/screen/fullscreen/fog, 1)
+
+/datum/status_effect/bubblegum_curse/tick()
+ var/mob/living/simple_animal/hostile/megafauna/bubblegum/attacker = locateUID(source_UID)
+ if(!attacker)
+ qdel(src)
+ if(attacker.health <= attacker.maxHealth / 2)
+ owner.clear_fullscreen("Bubblegum")
+ owner.overlay_fullscreen("Bubblegum", /obj/screen/fullscreen/fog, 2)
+ if(!coward_checking)
+ if(owner.z != attacker.z)
+ addtimer(CALLBACK(src, PROC_REF(onstation_coward_callback)), 12 SECONDS)
+ coward_checking = TRUE
+ else if(get_dist(attacker, owner) >= 25)
+ addtimer(CALLBACK(src, PROC_REF(runaway_coward_callback)), 12 SECONDS)
+ coward_checking = TRUE
+
+ owner.apply_damage(damage, BRUTE)
+ if(ishuman(owner))
+ var/mob/living/carbon/human/H = owner
+ H.bleed(0.33)
+ if(prob(5))
+ to_chat(owner, "[pick("You feel your sins crawling on your back.", "You felt your sins weighing on your neck.", "You feel your blood pulsing inside you.", "YOU'LL NEVER ESCAPE ME", "YOU'LL DIE FOR INSULTING ME LIKE THIS")]")
+
+/datum/status_effect/bubblegum_curse/on_remove()
+ owner.clear_fullscreen("Bubblegum")
+
+/datum/status_effect/bubblegum_curse/proc/onstation_coward_callback()
+ coward_checking = FALSE
+ var/mob/living/simple_animal/hostile/megafauna/bubblegum/attacker = locateUID(source_UID)
+ if(owner.z != attacker.z)
+ to_chat(owner, "YOU CHALLENGE ME LIKE THIS... AND YOU RUN WITH YOUR FALSE MAGICS?")
+ else
+ return
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "REALLY?")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "SUCH INSOLENCE!")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "SO PATHETIC...")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "...SO FOOLISH!")
+ get_over_here()
+
+/datum/status_effect/bubblegum_curse/proc/runaway_coward_callback()
+ coward_checking = FALSE
+ var/mob/living/simple_animal/hostile/megafauna/bubblegum/attacker = locateUID(source_UID)
+ if(get_dist(attacker, owner) >= 25)
+ to_chat(owner, "My my, you can run FAST.")
+ else
+ return
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "I thought you wanted a true fight?")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "Perhaps I was mistaken.")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "You are a coward who does not want a fight...")
+ SLEEP_CHECK_QDEL(2 SECONDS)
+ to_chat(owner, "...BUT I WANT YOU DEAD!")
+ get_over_here()
+
+/datum/status_effect/bubblegum_curse/proc/get_over_here()
+ var/mob/living/simple_animal/hostile/megafauna/bubblegum/attacker = locateUID(source_UID)
+ if(!attacker)
+ return //Let's not nullspace
+ var/turf/TA = get_turf(owner)
+ owner.Immobilize(3 SECONDS)
+ new /obj/effect/decal/cleanable/blood/bubblegum(TA)
+ new /obj/effect/temp_visual/bubblegum_hands/rightsmack(TA)
+ sleep(6)
+ var/turf/TB = get_turf(owner)
+ to_chat(owner, "[attacker] rends you!")
+ playsound(TB, attacker.attack_sound, 100, TRUE, -1)
+ owner.adjustBruteLoss(10)
+ new /obj/effect/decal/cleanable/blood/bubblegum(TB)
+ new /obj/effect/temp_visual/bubblegum_hands/leftsmack(TB)
+ sleep(6)
+ var/turf/TC = get_turf(owner)
+ to_chat(owner, "[attacker] rends you!")
+ playsound(TC, attacker.attack_sound, 100, TRUE, -1)
+ owner.adjustBruteLoss(10)
+ new /obj/effect/decal/cleanable/blood/bubblegum(TC)
+ new /obj/effect/temp_visual/bubblegum_hands/rightsmack(TC)
+ sleep(6)
+ var/turf/TD = get_turf(owner)
+ to_chat(owner, "[attacker] rends you!")
+ playsound(TD, attacker.attack_sound, 100, TRUE, -1)
+ owner.adjustBruteLoss(10)
+ new /obj/effect/temp_visual/bubblegum_hands/leftpaw(TD)
+ new /obj/effect/temp_visual/bubblegum_hands/leftthumb(TD)
+ sleep(8)
+ to_chat(owner, "[attacker] drags you through the blood!")
+ playsound(TD, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
+ var/turf/targetturf = get_step(attacker, attacker.dir)
+ owner.forceMove(targetturf)
+ playsound(targetturf, 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
+ addtimer(CALLBACK(attacker, TYPE_PROC_REF(/mob/living/simple_animal/hostile/megafauna/bubblegum, FindTarget), list(owner), 1), 2)
+
+/obj/screen/alert/status_effect/bubblegum_curse
+ name = "I SEE YOU"
+ desc = "YOUR SOUL WILL BE MINE FOR YOUR INSOLENCE"
+ icon_state = "bubblegumjumpscare"
+
+/obj/screen/alert/status_effect/bubblegum_curse/Initialize(mapload)
+ . = ..()
+ START_PROCESSING(SSobj, src)
+
+/obj/screen/alert/status_effect/bubblegum_curse/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ return ..()
+
+/obj/screen/alert/status_effect/bubblegum_curse/process()
+ var/new_filter = isnull(get_filter("ray"))
+ ray_filter_helper(1, 40,"#ce3030", 6, 20)
+ if(new_filter)
+ animate(get_filter("ray"), offset = 10, time = 10 SECONDS, loop = -1)
+ animate(offset = 0, time = 10 SECONDS)
diff --git a/code/game/area/areas/ruins/space_areas.dm b/code/game/area/areas/ruins/space_areas.dm
index a58edec0be56..5e97afab6814 100644
--- a/code/game/area/areas/ruins/space_areas.dm
+++ b/code/game/area/areas/ruins/space_areas.dm
@@ -150,6 +150,9 @@
icon_state = "dark"
requires_power = FALSE
+/area/ruin/space/bubblegum_arena
+ name = "Bubblegum Arena"
+
/area/ruin/space/wreck_cargoship
name = "Faint Signal"
icon_state = "yellow"
diff --git a/code/game/objects/effects/landmarks.dm b/code/game/objects/effects/landmarks.dm
index 5be01f245cbf..4d884a51ef8b 100644
--- a/code/game/objects/effects/landmarks.dm
+++ b/code/game/objects/effects/landmarks.dm
@@ -107,6 +107,18 @@ INITIALIZE_IMMEDIATE(/obj/effect/landmark/awaystart) //Without this away mission
/obj/effect/landmark/spawner/rev
name = "revenantspawn"
icon_state = "Rev"
+
+/obj/effect/landmark/spawner/bubblegum_arena
+ name = "bubblegum_arena_human"
+ icon_state = "Explorer"
+
+/obj/effect/landmark/spawner/bubblegum
+ name = "bubblegum_arena_bubblegum"
+ icon_state = "bubblegumjumpscare"
+
+/obj/effect/landmark/spawner/bubblegum_exit
+ name = "bubblegum_arena_exit"
+ icon_state = "bubblegumjumpscare"
/obj/effect/landmark/spawner/syndie
name = "Syndicate-Spawn"
diff --git a/code/game/objects/items/devices/radio/radio_objects.dm b/code/game/objects/items/devices/radio/radio_objects.dm
index e41bd366e03e..717c3e1e2430 100644
--- a/code/game/objects/items/devices/radio/radio_objects.dm
+++ b/code/game/objects/items/devices/radio/radio_objects.dm
@@ -61,7 +61,7 @@ GLOBAL_LIST_EMPTY(deadsay_radio_systems)
/// How many times this is disabled by EMPs
var/disable_timer = 0
/// Areas in which this radio cannot send messages
- var/static/list/blacklisted_areas = list(/area/adminconstruction, /area/tdome)
+ var/static/list/blacklisted_areas = list(/area/adminconstruction, /area/tdome, /area/ruin/space/bubblegum_arena)
flags = CONDUCT
slot_flags = SLOT_FLAG_BELT
diff --git a/code/game/objects/items/weapons/storage/boxes.dm b/code/game/objects/items/weapons/storage/boxes.dm
index 7b1065feada2..571c6f285e27 100644
--- a/code/game/objects/items/weapons/storage/boxes.dm
+++ b/code/game/objects/items/weapons/storage/boxes.dm
@@ -976,6 +976,16 @@
new /obj/item/stock_parts/matter_bin(src)
new /obj/item/screwdriver(src)
+/obj/item/storage/box/hardmode_box
+ name = "box of HRD-MDE project box"
+ desc = "Contains everything needed to get yourself killed for a medal."
+
+/obj/item/storage/box/hardmode_box/populate_contents()
+ for(var/I in 1 to 7)
+ new /obj/item/grenade/megafauna_hardmode(src)
+ new /obj/item/storage/lockbox/medal/hardmode_box(src)
+ new /obj/item/paper/hardmode(src)
+
#undef NODESIGN
#undef NANOTRASEN
#undef SYNDI
diff --git a/code/game/objects/items/weapons/storage/lockbox.dm b/code/game/objects/items/weapons/storage/lockbox.dm
index 68e090db9ca0..b3257d3587be 100644
--- a/code/game/objects/items/weapons/storage/lockbox.dm
+++ b/code/game/objects/items/weapons/storage/lockbox.dm
@@ -111,6 +111,37 @@
new /obj/item/clothing/accessory/medal/silver/valor(src)
new /obj/item/clothing/accessory/medal/heart(src)
+/obj/item/storage/lockbox/medal/hardmode_box
+ name = "\improper HRD-MDE program medal box"
+ desc = "A locked box used to store medals of pride. Use a fauna research disk on the box to transmit the data and print a medal."
+ req_access = list(ACCESS_MINING) //No grubby assistant hands on my hard earned medals
+ can_hold = list(/obj/item/clothing/accessory, /obj/item/coin) //Whoops almost gave miners boxes that could store 12 legion cores. Scoped to accessory if they want to store neclaces or hope or something in there. Or a coin collection.
+ var/list/completed_fauna = list()
+ var/number_of_megafauna = 7 //Increase this if new megafauna are added.
+
+/obj/item/storage/lockbox/medal/hardmode_box/Initialize(mapload)
+ . = ..()
+ number_of_megafauna = length(subtypesof(/obj/item/disk/fauna_research))
+
+/obj/item/storage/lockbox/medal/hardmode_box/populate_contents()
+ return
+
+/obj/item/storage/lockbox/medal/hardmode_box/attackby(obj/item/W, mob/user, params)
+ if(istype(W, /obj/item/disk/fauna_research))
+ var/obj/item/disk/fauna_research/disky = W
+ var/obj/item/pride = new disky.output(get_turf(src))
+ to_chat(user, "[src] accepts [disky], and prints out [pride]!")
+ qdel(disky)
+ if(!is_type_in_list(pride, completed_fauna))
+ completed_fauna += pride.type
+ if(length(completed_fauna) == number_of_megafauna)
+ to_chat(user, "[src] prints out a very fancy medal!")
+ var/obj/item/accomplishment = new /obj/item/clothing/accessory/medal/gold/heroism/hardmode_full(get_turf(src))
+ user.put_in_hands(accomplishment)
+ user.put_in_hands(pride)
+ return
+ return ..()
+
/obj/item/storage/lockbox/t4
name = "lockbox (T4)"
desc = "Contains three T4 breaching charges."
diff --git a/code/modules/client/preference/preferences.dm b/code/modules/client/preference/preferences.dm
index a8885ef65211..b5c6cf8253dc 100644
--- a/code/modules/client/preference/preferences.dm
+++ b/code/modules/client/preference/preferences.dm
@@ -89,6 +89,7 @@ GLOBAL_LIST_INIT(special_role_times, list( //minimum age (in days) for accounts
"1016" = 100, // CHANNEL_FIREALARM
"1015" = 100, // CHANNEL_ASH_STORM
"1014" = 100, // CHANNEL_RADIO_NOISE
+ "1013" = 100 // CHANNEL_BOSS_MUSIC
)
/// The volume mixer save timer handle. Used to debounce the DB call to save, to avoid spamming.
var/volume_mixer_saving = null
diff --git a/code/modules/clothing/under/accessories/accessory.dm b/code/modules/clothing/under/accessories/accessory.dm
index 22388a01e975..b956d816a0ef 100644
--- a/code/modules/clothing/under/accessories/accessory.dm
+++ b/code/modules/clothing/under/accessories/accessory.dm
@@ -216,6 +216,7 @@
/obj/item/clothing/accessory/medal/gold/heroism
name = "medal of exceptional heroism"
desc = "An extremely rare golden medal awarded only by CentComm. To receive such a medal is the highest honor and as such, very few exist."
+ icon_state = "ion"
// SILVER (awarded by Captain)
@@ -277,8 +278,73 @@
icon_state = "bronze_heart"
item_color = "bronze_heart"
+// Plasma, from NT research departments. For now, used by the HRD-MDE project for the moderate 2 fauna, drake and hierophant.
+/obj/item/clothing/accessory/medal/plasma
+ name = "plasma medal"
+ desc = "An eccentric medal made of plasma."
+ icon_state = "plasma"
+ item_color = "plasma"
+ materials = list(MAT_PLASMA = 1000)
+/obj/item/clothing/accessory/medal/plasma/temperature_expose(datum/gas_mixture/air, temperature, volume)
+ ..()
+ if(temperature > T0C + 200)
+ burn_up()
+
+/obj/item/clothing/accessory/medal/plasma/fire_act(datum/gas_mixture/air, exposed_temperature, exposed_volume, global_overlay)
+ . = ..()
+ burn_up()
+
+/obj/item/clothing/accessory/medal/plasma/proc/burn_up()
+ var/turf/simulated/T = get_turf(src)
+ if(istype(T))
+ T.atmos_spawn_air(LINDA_SPAWN_HEAT | LINDA_SPAWN_TOXINS | LINDA_SPAWN_OXYGEN, 10) //Technically twice as much plasma as it should spawn but a little more never hurt anyone.
+ visible_message("[src] bursts into flame!")
+ qdel(src)
+
+// Alloy, for the vetus speculator, or abductors I guess.
+
+/obj/item/clothing/accessory/medal/alloy
+ name = "alloy medal"
+ desc = "An eccentric medal made of some strange alloy."
+ icon_state = "alloy"
+ item_color = "alloy"
+ materials = list(MAT_METAL = 500, MAT_PLASMA = 500)
+
+// Mostly mining medals past here
+
+/obj/item/clothing/accessory/medal/gold/bubblegum
+ name = "bubblegum HRD-MDE award"
+ desc = "An award which represents magnificant contributions to the HRD-MDE project in the form of analysing Bubblegum, and the related blood space."
+
+/obj/item/clothing/accessory/medal/gold/heroism/hardmode_full //Kill every hardmode boss. In a shift. Good luck.
+ name = "medal of incredible dedication"
+ desc = "An extremely rare golden medal awarded only by CentComm. This medal was issued for miners who went above and beyond for the HRD-MDE project. Engraved on it is the phrase 'mori quam foedari'..."
+
+/obj/item/clothing/accessory/medal/silver/colossus
+ name = "colossus HRD-MDE award"
+ desc = "An award which represents major contributions to the HRD-MDE project in the form of analysing a colossus."
+
+/obj/item/clothing/accessory/medal/silver/legion
+ name = "legion HRD-MDE award"
+ desc = "An award which represents major contributions to the HRD-MDE project in the form of analysing the Legion."
+
+/obj/item/clothing/accessory/medal/blood_drunk
+ name = "blood drunk HRD-MDE award"
+ desc = "A award which represents minor contributions to the HRD-MDE project in the form of analysing the blood drunk miner."
+
+/obj/item/clothing/accessory/medal/plasma/hierophant
+ name = "hierophant HRD-MDE award"
+ desc = "An award which represents moderate contributions to the HRD-MDE project in the form of analysing the Hierophant."
+
+/obj/item/clothing/accessory/medal/plasma/ash_drake
+ name = "ash drake HRD-MDE award"
+ desc = "An award which represents moderate contributions to the HRD-MDE project in the form of analysing an ash drake."
+
+/obj/item/clothing/accessory/medal/alloy/vetus
+ name = "vetus speculator HRD-MDE award"
+ desc = "An award which represents major contributions to the HRD-MDE project in the form of analysing the Vetus Speculator."
/*
Holobadges are worn on the belt or neck, and can be used to show that the holder is an authorized
diff --git a/code/modules/mining/equipment/hardmode_grenade.dm b/code/modules/mining/equipment/hardmode_grenade.dm
new file mode 100644
index 000000000000..32eee7eb2630
--- /dev/null
+++ b/code/modules/mining/equipment/hardmode_grenade.dm
@@ -0,0 +1,79 @@
+/obj/item/grenade/megafauna_hardmode
+ name = "\improper HRD-MDE Scanning Grenade"
+ desc = "An advanced grenade that releases nanomachines, which enter nearby megafauna. This will enrage them greatly, but allows nanotrasen to fully research their abilities."
+ icon = 'icons/obj/grenade.dmi'
+ icon_state = "enrager"
+ item_state = "grenade"
+
+/obj/item/grenade/megafauna_hardmode/prime()
+ update_mob()
+ playsound(loc, 'sound/effects/empulse.ogg', 50, TRUE)
+ for(var/mob/living/simple_animal/hostile/megafauna/M in range(7, src))
+ M.enrage()
+ visible_message("[M] begins to wake up as the nanomachines enter them, it looks pissed!")
+ qdel(src)
+
+/obj/item/paper/hardmode
+ name = "HRD-MDE Scanner Guide"
+ icon_state = "paper"
+ info = {"Welcome to the NT HRD-MDE Project
+
+ This guide will cover the basics on the Hi-tech Research and Development, Mining Department Experiment project.
+
+ These grenades when used, will disperse a cloud of nanomachines into nearbye fauna, allowing a detailed examination of their body structure when alive. We will use this data to develope new products to sell, and we need your help!
+
+ We need to see these fauna working at their full potential with the nanomachines in them, so you will have to fight them. As a warning, these nanomachines have been known to irratate and annoy animals in testing, as well injecting a cocktail of drugs into them to get their organs outputting at maximum potential.
+
+ We operate on a limited budget, but we do provide payment for participating in this project: 0.1% of profits from any products made from this research, and medals showing off your pride for NT and promoting their research.
+
+ By participating in this experiment you waive all rights for compensation of death on the job.
+"}
+
+
+/obj/item/disk/fauna_research
+ name = "empty HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Seems empty?"
+ icon_state = "holodisk"
+ var/obj/item/clothing/accessory/medal/output
+
+/obj/item/disk/fauna_research/Initialize(mapload)
+ . = ..()
+ for(var/obj/structure/closet/C in get_turf(src))
+ forceMove(C)
+ return
+
+/obj/item/disk/fauna_research/blood_drunk_miner
+ name = "blood drunk HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the dash and resistance of the blood drunk miner."
+ output = /obj/item/clothing/accessory/medal/blood_drunk
+
+/obj/item/disk/fauna_research/hierophant
+ name = "\improper Hierophant HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the energy manipulation and material composition of the Hierophant."
+ output = /obj/item/clothing/accessory/medal/plasma/hierophant
+
+/obj/item/disk/fauna_research/ash_drake
+ name = "ash drake HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the fire production methods and rapid regeneration of the ash drakes."
+ output = /obj/item/clothing/accessory/medal/plasma/ash_drake
+
+/obj/item/disk/fauna_research/vetus
+ name = "\improper Vetus Speculator HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the anomaly manipulation and computing processes of the Vetus Speculator."
+ output = /obj/item/clothing/accessory/medal/alloy/vetus
+
+/obj/item/disk/fauna_research/colossus
+ name = "colossus HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the powerful voice and A-T field of the colossi."
+ output = /obj/item/clothing/accessory/medal/silver/colossus
+
+/obj/item/disk/fauna_research/legion
+ name = "\improper Legion HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the endless regeneration and disintegration laser of the Legion."
+ output = /obj/item/clothing/accessory/medal/silver/legion
+
+/obj/item/disk/fauna_research/bubblegum
+ name = "\improper Bubblegum HRD-MDE project disk"
+ desc = "A disk used by the HRD-MDE project. Contains data on the bloodcrawling and \[REDACTED\] of Bubblegum." //I hate this so much
+ output = /obj/item/clothing/accessory/medal/gold/bubblegum
+
diff --git a/code/modules/mining/lavaland/loot/bubblegum_loot.dm b/code/modules/mining/lavaland/loot/bubblegum_loot.dm
index 91c3d797f52b..b217e2a7d332 100644
--- a/code/modules/mining/lavaland/loot/bubblegum_loot.dm
+++ b/code/modules/mining/lavaland/loot/bubblegum_loot.dm
@@ -13,6 +13,76 @@
. = ..()
new /obj/item/crusher_trophy/demon_claws(src)
+/obj/structure/closet/crate/necropolis/bubblegum/bait/populate_contents()
+ return
+
+/obj/structure/closet/crate/necropolis/bubblegum/bait/open(by_hand)
+ . = ..()
+ for(var/obj/effect/bubblegum_trigger/B in contents)
+ B.targets_to_fuck_up += usr
+ B.activate()
+
+/obj/effect/bubblegum_trigger
+ var/list/targets_to_fuck_up = list()
+
+/obj/effect/bubblegum_trigger/Initialize(mapload, target_list)
+ . = ..()
+ addtimer(CALLBACK(src, PROC_REF(activate)), 15 SECONDS) //We try to auto engage the fun 15 seconds after death, or when manually opened, whichever comes first. If for some strange reason the target list is empty, we'll trigger when opened
+ targets_to_fuck_up = target_list
+
+/obj/effect/bubblegum_trigger/proc/activate()
+ if(!length(targets_to_fuck_up))
+ return
+ var/spawn_locs = list()
+ for(var/obj/effect/landmark/spawner/bubblegum_arena/R in GLOB.landmarks_list)
+ spawn_locs += get_turf(R)
+ for(var/mob/living/M in targets_to_fuck_up)
+ var/turf/T = get_turf(M)
+ M.Immobilize(1 SECONDS)
+ to_chat(M, "NO! I REFUSE TO LET YOU THINK YOU HAVE WON. I SHALL END YOUR INSIGNIFICANT LIFE!")
+ new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
+ new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
+ sleep(8)
+ playsound(T, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
+ var/turf/target_turf = pick(spawn_locs)
+ M.forceMove(target_turf)
+ playsound(target_turf, 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
+ for(var/obj/effect/landmark/spawner/bubblegum/B in GLOB.landmarks_list)
+ new /mob/living/simple_animal/hostile/megafauna/bubblegum/round_2(get_turf(B))
+
+
+/obj/effect/bubblegum_exit/Initialize(mapload, target_list)
+ . = ..()
+ addtimer(CALLBACK(src, PROC_REF(activate)), 10 SECONDS)
+
+/obj/effect/bubblegum_exit/proc/activate()
+ var/spawn_exit = list()
+ for(var/obj/effect/landmark/spawner/bubblegum_exit/E in GLOB.landmarks_list)
+ for(var/turf/T in range(4, E))
+ if(T.density)
+ continue
+ spawn_exit += get_turf(T)
+ var/area/probably_bubblearena = get_area(src)
+ for(var/mob/living/M in probably_bubblearena)
+ var/turf/T = get_turf(M)
+ M.Immobilize(1 SECONDS)
+ to_chat(M, "Now... get out of my home.")
+ new /obj/effect/temp_visual/bubblegum_hands/leftpaw(T)
+ new /obj/effect/temp_visual/bubblegum_hands/leftthumb(T)
+ sleep(8)
+ playsound(T, 'sound/misc/enter_blood.ogg', 100, TRUE, -1)
+ var/turf/target_turf = pick(spawn_exit)
+ M.forceMove(target_turf)
+ playsound(target_turf, 'sound/misc/exit_blood.ogg', 100, TRUE, -1)
+ for(var/obj/O in probably_bubblearena) //Mobs are out, lets get items / limbs / brains. Lets also exclude blood..
+ if(iseffect(O))
+ continue
+ if(istype(O, /obj/structure/stone_tile)) //Taking the tiles from the arena is funny, but a bit stupid
+ continue
+ var/turf/target_turf = pick(spawn_exit)
+ O.forceMove(target_turf)
+
+
// Mayhem
/obj/item/mayhem
diff --git a/code/modules/mining/machine_vending.dm b/code/modules/mining/machine_vending.dm
index 43539bc563e8..19321fad7a7d 100644
--- a/code/modules/mining/machine_vending.dm
+++ b/code/modules/mining/machine_vending.dm
@@ -91,6 +91,7 @@
EQUIPMENT("Soap", /obj/item/soap/nanotrasen, 200),
EQUIPMENT("Space Cash", /obj/item/stack/spacecash/c200, 2000),
EQUIPMENT("Whiskey", /obj/item/reagent_containers/food/drinks/bottle/whiskey, 100),
+ EQUIPMENT("HRD-MDE Project Box", /obj/item/storage/box/hardmode_box, 5000) //I want miners have to pay a lot to get this, but be set once they do.
)
prize_list["Extra"] = list() // Used in child vendors
diff --git a/code/modules/mob/living/damage_procs.dm b/code/modules/mob/living/damage_procs.dm
index fc18091e6e08..ed47d4a0bed3 100644
--- a/code/modules/mob/living/damage_procs.dm
+++ b/code/modules/mob/living/damage_procs.dm
@@ -9,6 +9,7 @@
standard 0 if fail
*/
/mob/living/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone, blocked = 0, sharp = FALSE, used_weapon, spread_damage = FALSE)
+ SEND_SIGNAL(src, COMSIG_MOB_APPLY_DAMAGE, damage, damagetype, def_zone)
var/hit_percent = (100 - blocked) / 100
if(!damage || (hit_percent <= 0))
return FALSE
diff --git a/code/modules/mob/living/simple_animal/hostile/hostile.dm b/code/modules/mob/living/simple_animal/hostile/hostile.dm
index 988454694eb9..a429d1c22950 100644
--- a/code/modules/mob/living/simple_animal/hostile/hostile.dm
+++ b/code/modules/mob/living/simple_animal/hostile/hostile.dm
@@ -235,6 +235,7 @@
return FALSE
/mob/living/simple_animal/hostile/proc/GiveTarget(new_target)//Step 4, give us our selected target
+ SEND_SIGNAL(src, COMSIG_HOSTILE_FOUND_TARGET, new_target)
target = new_target
LosePatience()
if(target != null)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
index 92b16aa46d2d..b11bf9f1d407 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/ancient_robot.dm
@@ -1,4 +1,4 @@
-#define BODY_SHIELD_COOLDOWN_TIME 5 SECONDS
+#define BODY_SHIELD_COOLDOWN_TIME enraged ? 3 SECONDS : 5 SECONDS
#define EXTRA_PLAYER_ANGER_NORMAL_CAP 6
#define EXTRA_PLAYER_ANGER_STATION_CAP 3
#define BLUESPACE 1
@@ -167,6 +167,28 @@ Difficulty: Hard
var/crate_type = pick(loot)
var/obj/structure/closet/crate/C = new crate_type(loc)
new core_type(C)
+ if(!enraged)
+ return
+ for(var/mob/living/M in urange(40, src)) //Bigger range, ran once per shift, as people run away from vetus as it blows up.
+ if(M.client)
+ new /obj/item/disk/fauna_research/vetus(C)
+
+/mob/living/simple_animal/hostile/megafauna/ancient_robot/enrage()
+ . = ..()
+ armour_penetration_percentage = 66
+ TL.armour_penetration_percentage = 66
+ TR.armour_penetration_percentage = 66
+ BL.armour_penetration_percentage = 66
+ BR.armour_penetration_percentage = 66
+
+/mob/living/simple_animal/hostile/megafauna/ancient_robot/unrage()
+ . = ..()
+ armour_penetration_percentage = 50
+ TL.armour_penetration_percentage = 50
+ TR.armour_penetration_percentage = 50
+ BL.armour_penetration_percentage = 50
+ BR.armour_penetration_percentage = 50
+
/mob/living/simple_animal/hostile/megafauna/ancient_robot/OpenFire()
if(charging)
@@ -178,6 +200,9 @@ Difficulty: Hard
anger_modifier = clamp(((maxHealth - health) / 50), 0, 20)
ranged_cooldown = world.time + (ranged_cooldown_time * ((10 - extra_player_anger) / 10))
+ if(enraged && prob(20)) //This attack is free, and can be combined with other attacks, so chance is low.
+ single_laser()
+
if(prob(30 + (anger_modifier / 2))) //Less scaling as the weaker attack / first calculated.
triple_charge()
@@ -189,6 +214,33 @@ Difficulty: Hard
calculate_extra_player_anger()
+/mob/living/simple_animal/hostile/megafauna/ancient_robot/proc/single_laser()
+ say(pick("KTMGMK JOYIU OTLKXTU", "ROQK G OTZKXTGR JOYQ", "HO-JOXKIZOUTGR RGYKXY KTMGMKJ"))
+ new /obj/effect/vetus_laser(get_turf(src))
+
+/obj/effect/vetus_laser
+ icon = 'icons/obj/tesla_engine/energy_ball.dmi'
+ icon_state = "energy_ball"
+ pixel_x = -32
+ pixel_y = -32
+
+/obj/effect/vetus_laser/Initialize(mapload)
+ . = ..()
+ var/newcolor = rgb(241, 137, 172)
+ add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
+ beam_it_up()
+
+/obj/effect/vetus_laser/ex_act(severity)
+ return
+
+/obj/effect/vetus_laser/proc/beam_it_up()
+ var/turf/beam_me_up_scotty = get_turf(src)
+ for(var/turf/T in spiral_range_turfs(9, src, 9))
+ T.Beam(beam_me_up_scotty, icon_state = "sm_arc_dbz_referance", time = 0.1, beam_type = /obj/effect/ebeam/vetus)
+ SLEEP_CHECK_QDEL(1)
+ qdel(src)
+
+
/mob/living/simple_animal/hostile/megafauna/ancient_robot/proc/triple_charge()
if(mode == BLUESPACE)
charge(delay = 24) //An extra charge, to make up for the longer time between teleports
@@ -201,10 +253,10 @@ Difficulty: Hard
charge(delay = 3)
SetRecoveryTime(15)
-/mob/living/simple_animal/hostile/megafauna/ancient_robot/proc/charge(atom/chargeat = target, delay = 5, chargepast = 2) //add limb charge as well
+/mob/living/simple_animal/hostile/megafauna/ancient_robot/proc/charge(atom/chargeat = target, delay = 5, chargepast = 2)
if(!chargeat)
return
- if(mode == BLUESPACE)
+ if(mode == BLUESPACE || (enraged && prob(13)))
new /obj/effect/temp_visual/bsg_kaboom(get_turf(src))
src.visible_message("[src] teleports somewhere nearby!")
do_teleport(src, target, 7, sound_in = 'sound/effects/phasein.ogg', safe_turf_pick = TRUE) //Teleport within 7 tiles of the target
@@ -253,7 +305,7 @@ Difficulty: Hard
playsound(get_turf(L), 'sound/effects/meteorimpact.ogg', 100, TRUE)
shake_camera(L, 4, 3)
shake_camera(src, 2, 3)
- if(mode == GRAV)
+ if(mode == GRAV || enraged)
var/atom/throw_target = get_edge_target_turf(L, get_dir(src, get_step_away(L, src)))
L.throw_at(throw_target, 3, 2)
..()
@@ -303,7 +355,7 @@ Difficulty: Hard
H.apply_status_effect(STATUS_EFFECT_BLUESPACESLOWDOWN)
if(GRAV)
visible_message("Debris from the battlefield begin to get compressed into rocks!")
- var/list/turfs = new/list()
+ var/list/turfs = list()
var/rocks = 0
for(var/turf/T in view(4, target))
if(T.density)
@@ -311,14 +363,17 @@ Difficulty: Hard
if(T in range (2, target))
continue
turfs += T
- while(rocks < 3 && length(turfs))
+ var/amount = enraged ? 5 : 3
+ while(rocks < amount && length(turfs))
var/turf/spot = pick_n_take(turfs)
+ if(!spot)
+ return
new /obj/effect/temp_visual/rock(spot)
addtimer(CALLBACK(src, PROC_REF(throw_rock), spot, target), 2 SECONDS)
rocks++
if(PYRO)
visible_message("The ground begins to heat up around you!")
- var/list/turfs = new/list()
+ var/list/turfs = list()
var/volcanos = 0
for(var/turf/T in view(4, target))
if(T.density)
@@ -326,10 +381,13 @@ Difficulty: Hard
if(T in range(1, target))
continue
turfs += T
- while(volcanos < 3 && length(turfs))
+ var/amount = enraged ? 5 : 3
+ while(volcanos < amount && length(turfs))
var/turf/spot = pick_n_take(turfs)
+ if(!spot)
+ return
for(var/turf/around in range(1, spot))
- new /obj/effect/temp_visual/lava_warning(around)
+ new /obj/effect/temp_visual/lava_warning(around, enraged ? 18 SECONDS : 6 SECONDS)
volcanos++
if(FLUX)
for(var/mob/living/carbon/human/H in view(7, src))
@@ -345,7 +403,7 @@ Difficulty: Hard
if(VORTEX)
visible_message("[src] begins vibrate rapidly. It's causing an earthquake!")
for(var/turf/turf in range(9,get_turf(target)))
- if(prob(15))
+ if(prob(enraged ? 40 : 15))
new /obj/effect/temp_visual/target/ancient(turf)
if(CRYO)
visible_message("[src]'s shell opens slightly, as sensors begin locking on to everyone around it!")
@@ -356,31 +414,33 @@ Difficulty: Hard
say(pick("JKVRUEOTM XGC VUCKX", "KXXUX OT GTUSGRE IUTZGOTSKTZ", "YZGHOROZE OT OTYZGHOROZE OT YZGHOROZE OT OTYZGH-"))
var/list/turfs = list()
var/anomalies = 0
- for(var/turf/T in view(5, src))
+ for(var/turf/T in view(enraged ? 7 : 5, src))
if(T.density)
continue
turfs += T
- while(anomalies < 3 && length(turfs))
+ var/amount = enraged ? 5 : 3
+ while(anomalies < amount && length(turfs))
var/turf/spot = pick(turfs)
turfs -= spot
+ var/time_to_use = enraged ? 25 SECONDS : 15 SECONDS
switch(mode)
if(BLUESPACE)
- var/obj/effect/anomaly/bluespace/A = new(spot, 150, FALSE)
+ var/obj/effect/anomaly/bluespace/A = new(spot, time_to_use, FALSE)
A.mass_teleporting = FALSE
if(GRAV)
- var/obj/effect/anomaly/grav/A = new(spot, 150, FALSE, FALSE)
+ var/obj/effect/anomaly/grav/A = new(spot, time_to_use, FALSE, FALSE)
A.knockdown = TRUE
if(PYRO)
- var/obj/effect/anomaly/pyro/A = new(spot, 150, FALSE)
+ var/obj/effect/anomaly/pyro/A = new(spot, time_to_use, FALSE)
A.produces_slime = FALSE
if(FLUX)
- var/obj/effect/anomaly/flux/A = new(spot, 150, FALSE)
+ var/obj/effect/anomaly/flux/A = new(spot, time_to_use, FALSE)
A.explosive = FALSE
A.knockdown = TRUE
if(VORTEX)
- new /obj/effect/anomaly/bhole(spot, 150, FALSE)
+ new /obj/effect/anomaly/bhole(spot, time_to_use, FALSE)
if(CRYO)
- new /obj/effect/anomaly/cryo(spot, 150, FALSE)
+ new /obj/effect/anomaly/cryo(spot, time_to_use, FALSE)
anomalies++
return
@@ -404,7 +464,9 @@ Difficulty: Hard
anger++
if(health <= health / 2)
anger += 2
- cap = (is_station_level(loc.z) ? EXTRA_PLAYER_ANGER_STATION_CAP : EXTRA_PLAYER_ANGER_NORMAL_CAP)
+ if(enraged)
+ anger += 2
+ cap = (is_station_level(loc.z) ? EXTRA_PLAYER_ANGER_STATION_CAP : EXTRA_PLAYER_ANGER_NORMAL_CAP) + enraged
extra_player_anger = clamp(anger,1,cap) - 1
/mob/living/simple_animal/hostile/megafauna/ancient_robot/proc/self_destruct()
@@ -515,7 +577,7 @@ Difficulty: Hard
if(charging)
if(mode == PYRO)
var/turf/C = get_turf(src)
- new /obj/effect/temp_visual/lava_warning(C)
+ new /obj/effect/temp_visual/lava_warning(C, enraged ? 18 SECONDS : 6 SECONDS)
for(var/turf/T in range (1,src))
new /obj/effect/hotspot(T)
T.hotspot_expose(700,50,1)
@@ -526,7 +588,7 @@ Difficulty: Hard
T.ex_act(3)
if(mode == CRYO)
var/turf/simulated/S = get_turf(src)
- S.MakeSlippery(TURF_WET_ICE, rand(10, 20 SECONDS))
+ S.MakeSlippery(TURF_WET_ICE, enraged ? rand(25, 35 SECONDS) : rand(10, 20 SECONDS))
for(var/turf/T in range (1, src))
new /obj/effect/snowcloud(T)
for(var/mob/living/carbon/C in T.contents)
@@ -539,6 +601,9 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/ancient_robot/mob_negates_gravity() //No more being thrown around like a spastic child by grav anomalies
return TRUE
+/mob/living/simple_animal/hostile/megafauna/ancient_robot/electrocute_act(shock_damage, source, siemens_coeff, flags)
+ return
+
/mob/living/simple_animal/hostile/ancient_robot_leg
name = "leg"
desc = "Legs with a mounted turret, for shooting and crushing small miners like you."
@@ -695,6 +760,9 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/ancient_robot_leg/mob_negates_gravity()
return TRUE
+/mob/living/simple_animal/hostile/ancient_robot_leg/electrocute_act(shock_damage, source, siemens_coeff, flags)
+ return
+
/obj/item/projectile/bullet/ancient_robot_bullet
damage = 8
damage_type = BRUTE
@@ -767,7 +835,7 @@ Difficulty: Hard
var/turf/T = get_turf(src)
playsound(T,'sound/magic/fleshtostone.ogg', 80, TRUE)
new /obj/effect/temp_visual/fireball/rock(T)
- sleep(duration)
+ SLEEP_CHECK_QDEL(duration)
if(ismineralturf(T))
var/turf/simulated/mineral/M = T
M.gets_drilled()
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
index d96248ec52ea..fe55c7f6b1e2 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner.dm
@@ -46,15 +46,17 @@ Difficulty: Medium
blood_volume = BLOOD_VOLUME_NORMAL
internal_gps = /obj/item/gps/internal/miner
medal_type = BOSS_MEDAL_MINER
- var/obj/item/melee/energy/cleaving_saw/miner/miner_saw
+ var/obj/item/melee/energy/cleaving_saw/miner_saw
var/time_until_next_transform = 0
var/dashing = FALSE
- var/dash_cooldown = 15
+ var/dash_cooldown = 0
+ var/dash_cooldown_to_use = 1.5 SECONDS
var/guidance = FALSE
var/transform_stop_attack = FALSE // stops the blood drunk miner from attacking after transforming his weapon until the next attack chain
deathmessage = "falls to the ground, decaying into glowing particles."
death_sound = "bodyfall"
footstep_type = FOOTSTEP_MOB_HEAVY
+ enraged_loot = /obj/item/disk/fauna_research/blood_drunk_miner
attack_action_types = list(/datum/action/innate/megafauna_attack/dash,
/datum/action/innate/megafauna_attack/kinetic_accelerator,
/datum/action/innate/megafauna_attack/transform_weapon)
@@ -67,7 +69,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/Initialize(mapload)
. = ..()
- miner_saw = new(src)
+ miner_saw = new /obj/item/melee/energy/cleaving_saw/miner(src)
/datum/action/innate/megafauna_attack/dash
name = "Dash To Target"
@@ -123,10 +125,14 @@ Difficulty: Medium
icon_state = "ka_tracer"
range = MINER_DASH_RANGE
+/obj/item/projectile/kinetic/miner/enraged
+ damage = 35
+
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/adjustHealth(amount, updating_health = TRUE)
- var/adjustment_amount = amount * 0.1
- if(world.time + adjustment_amount > next_move)
- changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
+ if(!enraged)
+ var/adjustment_amount = amount * 0.1
+ if(world.time + adjustment_amount > next_move)
+ changeNext_move(adjustment_amount) //attacking it interrupts it attacking, but only briefly
. = ..()
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/death()
@@ -170,7 +176,7 @@ Difficulty: Medium
changeNext_move(CLICK_CD_MELEE)
miner_saw.melee_attack_chain(src, target)
if(guidance)
- adjustHealth(-2)
+ adjustHealth(enraged ? -10 : -2)
if(prob(50))
transform_weapon() //Still follows the normal rules for cooldown between swaps.
return TRUE
@@ -186,6 +192,24 @@ Difficulty: Medium
if(. && target && !targets_the_same)
wander = TRUE
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/enrage()
+ . = ..()
+ miner_saw = new /obj/item/melee/energy/cleaving_saw(src) //Real saw for real men.
+ dash_cooldown_to_use = 0.5 SECONDS //Becomes a teleporting shit.
+ ranged_cooldown_time = 5 //They got some cooldown mods.
+ projectiletype = /obj/item/projectile/kinetic/miner/enraged
+ maxHealth = 1800
+ health = 1800 //Bit more of a challenge.
+
+/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/unrage()
+ . = ..()
+ miner_saw = new /obj/item/melee/energy/cleaving_saw/miner(src)
+ dash_cooldown_to_use = initial(dash_cooldown_to_use)
+ ranged_cooldown_time = initial(ranged_cooldown_time)
+ projectiletype = initial(projectiletype)
+ maxHealth = initial(maxHealth)
+ health = initial(health)
+
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/proc/dash_attack()
INVOKE_ASYNC(src, PROC_REF(dash), target)
shoot_ka()
@@ -232,7 +256,7 @@ Difficulty: Medium
accessable_turfs -= t
if(!LAZYLEN(accessable_turfs))
return
- dash_cooldown = world.time + initial(dash_cooldown)
+ dash_cooldown = world.time + dash_cooldown_to_use
target_turf = pick(accessable_turfs)
var/turf/step_back_turf = get_step(target_turf, get_cardinal_dir(target_turf, own_turf))
var/turf/step_forward_turf = get_step(own_turf, get_cardinal_dir(own_turf, target_turf))
@@ -291,7 +315,7 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/blood_drunk_miner/hunter/AttackingTarget()
. = ..()
- if(. && prob(12))
+ if(. && prob(enraged ? 40 : 12))
INVOKE_ASYNC(src, PROC_REF(dash))
#undef MINER_DASH_RANGE
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
index f91b6ac6b128..8a3d90563ffa 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/bubblegum.dm
@@ -1,4 +1,4 @@
-#define BUBBLEGUM_SMASH (health <= maxHealth * 0.5) // angery
+#define BUBBLEGUM_SMASH (health <= maxHealth * 0.5 || second_life) // angery
#define BUBBLEGUM_CAN_ENRAGE (enrage_till + (enrage_time * 2) <= world.time)
#define BUBBLEGUM_IS_ENRAGED (enrage_till > world.time)
@@ -59,6 +59,8 @@ Difficulty: Hard
var/enrage_till = 0
var/enrage_time = 70
var/revving_charge = FALSE
+ /// Is it on its enraged exclusive second life?
+ var/second_life = FALSE
internal_gps = /obj/item/gps/internal/bubblegum
medal_type = BOSS_MEDAL_BUBBLEGUM
score_type = BUBBLEGUM_SCORE
@@ -111,7 +113,48 @@ Difficulty: Hard
chosen_message = "You are now warping to blood around your clicked position."
chosen_attack_num = 4
-/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire()
+/mob/living/simple_animal/hostile/megafauna/bubblegum/enrage()
+ . = ..()
+ maxHealth = 2000 //Less health, as a phase 2
+ health = 2000
+ rapid_melee = 12 //Don't stand still
+ vision_range = 18
+ loot = list(/obj/effect/decal/cleanable/blood/gibs/bubblegum) //You'll get it in phase 2.
+ crusher_loot = list(/obj/effect/decal/cleanable/blood/gibs/bubblegum)
+ RegisterSignal(src, COMSIG_HOSTILE_FOUND_TARGET, PROC_REF(i_see_you))
+ for(var/mob/living/carbon/human/H in range(18)) //suprise motherfucker bubblegum wakes up fast
+ to_chat(H, "You DARE to insult my body with these constructs? I curse you as you curse ME!")
+ FindTarget(list(H), 1) //From down town with the pile driver
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/unrage()
+ return //They are pissed. Also whoever enraged them is stuck fighting them so, kinda a M.A.D situation.
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/i_see_you(source, target)
+ if(!ishuman(target))
+ return
+ var/mob/living/carbon/human/H = target
+ H.apply_status_effect(STATUS_EFFECT_BUBBLEGUM_CURSE, src)
+ if(second_life)
+ H.clear_fullscreen("bubblegum")
+ H.overlay_fullscreen("bubblegum", /obj/screen/fullscreen/fog, 2)
+
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/death(gibbed)
+ if(enraged && !second_life)
+ var/obj/structure/closet/crate/necropolis/bubblegum/bait/jebait = new /obj/structure/closet/crate/necropolis/bubblegum/bait(get_turf(src))
+ var/obj/effect/bubblegum_trigger/great_chest_ahead = new /obj/effect/bubblegum_trigger(jebait, ListTargets())
+ new /obj/effect/landmark/spawner/bubblegum_exit(get_turf(src))
+ great_chest_ahead.forceMove(jebait)
+ if(second_life)
+ var/area/A = get_area(src)
+ for(var/mob/M in A)
+ to_chat(M, "YOU FUCK... I... I'll... get you later. Enjoy the last few days of your life...")
+ new /obj/effect/bubblegum_exit(get_turf(src))
+ return ..()
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/OpenFire(atom/A)
+ if(second_life)
+ Shoot(A)
if(charging)
return
@@ -137,6 +180,9 @@ Difficulty: Hard
if(!BUBBLEGUM_SMASH)
triple_charge()
else
+ if(prob(25) && enraged)
+ hit_up_narsi()
+ return
if(prob(50 + anger_modifier))
hallucination_charge()
else
@@ -208,7 +254,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/try_bloodattack()
var/list/targets = get_mobs_on_blood()
if(targets.len)
- INVOKE_ASYNC(src, PROC_REF(bloodattack), targets, prob(50))
+ INVOKE_ASYNC(src, PROC_REF(bloodattack), targets, prob(enraged ? 75 : 50))
return TRUE
return FALSE
@@ -255,7 +301,7 @@ Difficulty: Hard
to_chat(L, "[src] rends you!")
playsound(T, attack_sound, 100, TRUE, -1)
var/limb_to_hit = L.get_organ(pick(BODY_ZONE_HEAD, BODY_ZONE_CHEST, BODY_ZONE_R_ARM, BODY_ZONE_L_ARM, BODY_ZONE_R_LEG, BODY_ZONE_L_LEG))
- L.apply_damage(10, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, MELEE, null, null, armour_penetration_flat, armour_penetration_percentage))
+ L.apply_damage(second_life ? 20 : 10, BRUTE, limb_to_hit, L.run_armor_check(limb_to_hit, MELEE, null, null, armour_penetration_flat, armour_penetration_percentage))
SLEEP_CHECK_DEATH(3)
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/bloodgrab(turf/T, handedness)
@@ -318,6 +364,27 @@ Difficulty: Hard
return TRUE
return FALSE
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/hit_up_narsi()
+ SetRecoveryTime(20)
+ visible_message("[pick("[SSticker.cultdat.entity_name], I call on YOU for one of MY favours you owe me!", "[SSticker.cultdat.entity_title1], I call on you for some support...", "Let us see how you like the minions of [SSticker.cultdat.entity_title2]!", "Oh, [SSticker.cultdat.entity_title3] join me in RENDING THIS WHELP APART!")]")
+ var/list/turfs = list()
+ var/constructs = 0
+ for(var/turf/T in view(6, target))
+ if(T.density)
+ continue
+ if(T in range(2, target))
+ continue
+ turfs += T
+ var/amount = enraged ? 4 : 3
+ while(constructs < amount && length(turfs))
+ var/turf/spot = pick_n_take(turfs)
+ if(!spot)
+ return
+ var/mob/living/simple_animal/hostile/construct/wraith/hostile/summon = new /mob/living/simple_animal/hostile/construct/wraith/hostile(spot)
+ summon.faction = faction.Copy()
+ constructs++
+
/mob/living/simple_animal/hostile/megafauna/bubblegum/proc/be_aggressive()
if(BUBBLEGUM_IS_ENRAGED)
return TRUE
@@ -340,8 +407,10 @@ Difficulty: Hard
if(!BUBBLEGUM_CAN_ENRAGE)
return FALSE
enrage_till = world.time + enrage_time
+ if(enraged)
+ adjustHealth(-75)
update_approach()
- change_move_delay(5)
+ change_move_delay(enraged ? 3 : 4) //3 if enraged, 4 otherwise
var/newcolor = rgb(149, 10, 10)
add_atom_colour(newcolor, TEMPORARY_COLOUR_PRIORITY)
var/datum/callback/cb = CALLBACK(src, PROC_REF(blood_enrage_end))
@@ -554,3 +623,26 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/bubblegum/hallucination/try_bloodattack()
return
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/round_2
+ desc = "Oh they are PISSED. And quite injured too..."
+ health = 750
+ maxHealth = 750
+ armour_penetration_percentage = 75
+ second_life = TRUE
+ enraged = TRUE
+ rapid_melee = 12
+ projectiletype = /obj/item/projectile/magic/arcane_barrage/blood
+ projectilesound = 'sound/effects/splat.ogg'
+ deathmessage = null
+ death_sound = 'sound/hallucinations/veryfar_noise.ogg'
+ ranged = TRUE
+ ranged_cooldown_time = 10
+ enraged_loot = /obj/item/disk/fauna_research/bubblegum
+
+/mob/living/simple_animal/hostile/megafauna/bubblegum/round_2/Initialize(mapload)
+ . = ..()
+ RegisterSignal(src, COMSIG_HOSTILE_FOUND_TARGET, PROC_REF(i_see_you))
+ for(var/mob/living/carbon/human/H in range(20))
+ to_chat(H, "I WILL END YOU HERE AND NOW!")
+ FindTarget(list(H), 1)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
index 02d7f2664d90..dc527b96fdf3 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/colossus.dm
@@ -54,6 +54,7 @@ Difficulty: Very Hard
loot = list(/obj/structure/closet/crate/necropolis/colossus)
deathmessage = "disintegrates, leaving a glowing core in its wake."
death_sound = 'sound/misc/demon_dies.ogg'
+ enraged_loot = /obj/item/disk/fauna_research/colossus
attack_action_types = list(/datum/action/innate/megafauna_attack/spiral_attack,
/datum/action/innate/megafauna_attack/aoe_attack,
/datum/action/innate/megafauna_attack/shotgun,
@@ -61,6 +62,15 @@ Difficulty: Very Hard
/// Have we used our final attack yet?
var/final_available = TRUE
+/mob/living/simple_animal/hostile/megafauna/colossus/Initialize(mapload)
+ . = ..()
+ return INITIALIZE_HINT_LATELOAD
+
+/mob/living/simple_animal/hostile/megafauna/colossus/LateInitialize()
+ . = ..()
+ for(var/mob/living/simple_animal/hostile/megafauna/hierophant/H in GLOB.mob_list)
+ H.RegisterSignal(src, COMSIG_MOB_APPLY_DAMAGE, TYPE_PROC_REF(/mob/living/simple_animal/hostile/megafauna/hierophant, easy_anti_cheese))
+
/datum/action/innate/megafauna_attack/spiral_attack
name = "Spiral Shots"
icon_icon = 'icons/mob/actions/actions.dmi'
@@ -93,6 +103,14 @@ Difficulty: Very Hard
. = ..(("[uppertext(message)]"), sanitize = FALSE, ignore_speech_problems = TRUE, ignore_atmospherics = TRUE)
+/mob/living/simple_animal/hostile/megafauna/colossus/enrage()
+ . = ..()
+ move_to_delay = 5
+
+/mob/living/simple_animal/hostile/megafauna/colossus/unrage()
+ . = ..()
+ move_to_delay = initial(move_to_delay)
+
/mob/living/simple_animal/hostile/megafauna/colossus/OpenFire()
anger_modifier = clamp(((maxHealth - health)/50),0,20)
ranged_cooldown = world.time + 120
@@ -109,7 +127,7 @@ Difficulty: Very Hard
alternating_dir_shots()
return
- if(enrage(target))
+ if(target_trying_to_cheese_us(target))
if(move_to_delay == initial(move_to_delay))
say("You can't dodge")
ranged_cooldown = world.time + 30
@@ -120,9 +138,10 @@ Difficulty: Very Hard
else
move_to_delay = initial(move_to_delay)
- if(health <= maxHealth / 10 && final_available) //One time use final attack
- final_available = FALSE
+ if(health <= maxHealth / (enraged ? 10 : 9) && final_available) //One time use final attack. Want to make it not get skipped as much on base colossus, but a little easier to skip on enraged as it can be used multiple times
final_attack()
+ if(!enraged)
+ final_available = FALSE
else if(prob(20 + anger_modifier)) //Major attack
select_spiral_attack()
else if(prob(20))
@@ -133,23 +152,28 @@ Difficulty: Very Hard
else
alternating_dir_shots()
-/mob/living/simple_animal/hostile/megafauna/colossus/proc/enrage(mob/living/L)
- if(ishuman(L))
- var/mob/living/carbon/human/H = L
- if(H.mind && H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
- return TRUE
-
-/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots()
- ranged_cooldown = world.time + 40
- telegraph(DIR_SHOTS)
- SLEEP_CHECK_DEATH(1.5 SECONDS)
+/mob/living/simple_animal/hostile/megafauna/colossus/proc/target_trying_to_cheese_us(mob/living/L)
+ if(!ishuman(L))
+ return
+ var/mob/living/carbon/human/H = L
+ if(H.mind && H.mind.martial_art && prob(H.mind.martial_art.deflection_chance))
+ return TRUE
+
+/mob/living/simple_animal/hostile/megafauna/colossus/proc/alternating_dir_shots(telegraphing = TRUE)
+ var/rage = enraged ? 5 : 10
+ if(telegraphing)
+ ranged_cooldown = world.time + 4 SECONDS
+ telegraph(DIR_SHOTS)
+ SLEEP_CHECK_DEATH(1.5 SECONDS)
dir_shots(GLOB.diagonals)
- SLEEP_CHECK_DEATH(10)
+ SLEEP_CHECK_DEATH(rage)
dir_shots(GLOB.cardinal)
- SLEEP_CHECK_DEATH(10)
+ SLEEP_CHECK_DEATH(rage)
dir_shots(GLOB.diagonals)
- SLEEP_CHECK_DEATH(10)
+ SLEEP_CHECK_DEATH(rage)
dir_shots(GLOB.cardinal)
+ if(telegraphing)
+ alternating_dir_shots(FALSE)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/select_spiral_attack()
if(health < maxHealth/3)
@@ -204,14 +228,14 @@ Difficulty: Very Hard
var/turf/U = get_turf(src)
playsound(U, 'sound/magic/clockwork/invoke_general.ogg', 300, TRUE, 5)
for(var/T in RANGE_TURFS(12, U) - U)
- if(prob(5))
+ if(prob(enraged ? 10 : 5))
shoot_projectile(T)
/mob/living/simple_animal/hostile/megafauna/colossus/proc/blast(set_angle, do_sleep = TRUE)
ranged_cooldown = world.time + 20
if(do_sleep)
telegraph(BLAST)
- SLEEP_CHECK_DEATH(1.5 SECONDS)
+ SLEEP_CHECK_DEATH(enraged ? 0.1 SECONDS : 1.5 SECONDS)
var/turf/target_turf = get_turf(target)
playsound(src, 'sound/magic/clockwork/invoke_general.ogg', 200, TRUE, 2)
newtonian_move(get_dir(target_turf, src))
@@ -306,10 +330,7 @@ Difficulty: Very Hard
/mob/living/simple_animal/hostile/megafauna/colossus/float(on) //we don't want this guy to float, messes up his animations
if(throwing)
return
- if(on && !floating)
- floating = TRUE
- else if(!on && floating)
- floating = FALSE
+ floating = on
/obj/item/projectile/colossus
name ="death bolt"
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
index 849341d9f15b..68d3e7b8cffa 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/drake.dm
@@ -61,6 +61,7 @@ Difficulty: Medium
deathmessage = "collapses into a pile of bones, its flesh sloughing away."
death_sound = 'sound/misc/demon_dies.ogg'
footstep_type = FOOTSTEP_MOB_HEAVY
+ enraged_loot = /obj/item/disk/fauna_research/ash_drake
attack_action_types = list(/datum/action/innate/megafauna_attack/fire_cone,
/datum/action/innate/megafauna_attack/fire_cone_meteors,
/datum/action/innate/megafauna_attack/mass_fire,
@@ -104,7 +105,7 @@ Difficulty: Medium
if(swooping)
return
- anger_modifier = clamp(((maxHealth - health)/50),0,20)
+ anger_modifier = clamp(max((maxHealth - health) / 50, enraged ? 15 : 0), 0, 20)
ranged_cooldown = world.time + ranged_cooldown_time
if(client)
@@ -124,6 +125,8 @@ Difficulty: Medium
else if(prob(10+anger_modifier))
shoot_fire_attack()
+ else if(enraged && prob(20))
+ arena_escape_enrage()
else
fire_cone()
@@ -138,7 +141,7 @@ Difficulty: Medium
return
target.visible_message("Fire rains from the sky!")
for(var/turf/turf in range(9,get_turf(target)))
- if(prob(11))
+ if(prob(enraged ? 44 : 11))
new /obj/effect/temp_visual/target(turf)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_pools(amount, delay = 0.8)
@@ -148,15 +151,15 @@ Difficulty: Medium
while(amount > 0)
if(QDELETED(target))
break
- var/turf/T = pick(RANGE_TURFS(1, target))
- new /obj/effect/temp_visual/lava_warning(T, 60) // longer reset time for the lava
+ var/turf/T = pick(RANGE_TURFS(enraged ? 2 : 1, target))
+ new /obj/effect/temp_visual/lava_warning(T, enraged ? 18 SECONDS : 6 SECONDS) // longer reset time for the lava
amount--
SLEEP_CHECK_DEATH(delay)
/mob/living/simple_animal/hostile/megafauna/dragon/proc/lava_swoop(amount = 30)
if(health < maxHealth * 0.5)
- return swoop_attack(lava_arena = TRUE, swoop_cooldown = 60)
- INVOKE_ASYNC(src, PROC_REF(lava_pools), amount)
+ return swoop_attack(lava_arena = TRUE, swoop_cooldown = enraged ? 2 SECONDS : 6 SECONDS)
+ INVOKE_ASYNC(src, PROC_REF(lava_pools), enraged ? 60 : amount)
swoop_attack(FALSE, target, 1000) // longer cooldown until it gets reset below
SLEEP_CHECK_DEATH(0)
fire_cone()
@@ -169,6 +172,8 @@ Difficulty: Medium
/mob/living/simple_animal/hostile/megafauna/dragon/proc/mass_fire(spiral_count = 12, range = 15, times = 3)
SLEEP_CHECK_DEATH(0)
+ if(prob(50) && enraged)
+ INVOKE_ASYNC(src, PROC_REF(fire_rain))
for(var/i = 1 to times)
SetRecoveryTime(50)
playsound(get_turf(src),'sound/magic/fireball.ogg', 200, TRUE)
@@ -185,12 +190,12 @@ Difficulty: Medium
target.visible_message("[src] encases you in an arena of fire!")
var/amount = 3
var/turf/center = get_turf(target)
- var/list/walled = RANGE_TURFS(3, center) - RANGE_TURFS(2, center)
+ var/list/walled = RANGE_TURFS(enraged ? 4 : 3, center) - RANGE_TURFS(enraged ? 3 : 2, center)
var/list/drakewalls = list()
for(var/turf/T in walled)
drakewalls += new /obj/effect/temp_visual/drakewall(T) // no people with lava immunity can just run away from the attack for free
var/list/indestructible_turfs = list()
- for(var/turf/T in RANGE_TURFS(2, center))
+ for(var/turf/T in RANGE_TURFS(enraged ? 3 : 2, center))
if(istype(T, /turf/simulated/floor/indestructible))
continue
if(!istype(T, /turf/simulated/wall/indestructible))
@@ -199,14 +204,14 @@ Difficulty: Medium
indestructible_turfs += T
SLEEP_CHECK_DEATH(10) // give them a bit of time to realize what attack is actually happening
- var/list/turfs = RANGE_TURFS(2, center)
+ var/list/turfs = RANGE_TURFS(enraged ? 3 : 2, center)
while(amount > 0)
var/list/empty = indestructible_turfs.Copy() // can't place safe turfs on turfs that weren't changed to be open
var/any_attack = 0
for(var/turf/T in turfs)
for(var/mob/living/L in T.contents)
if(L.client)
- empty += pick(((RANGE_TURFS(2, L) - RANGE_TURFS(1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield
+ empty += pick(((RANGE_TURFS(enraged ? 3 : 2, L) - RANGE_TURFS(enraged ? 2 : 1, L)) & turfs) - empty) // picks a turf within 2 of the creature not outside or in the shield
any_attack = 1
for(var/obj/mecha/M in T.contents)
empty += pick(((RANGE_TURFS(2, M) - RANGE_TURFS(1, M)) & turfs) - empty)
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
index 42c8456c6e91..d2a79230e927 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -39,7 +39,7 @@ Difficulty: Hard
desc = "A massive metal club that hangs in the air as though waiting. It'll make you dance to its beat."
health = 2500
maxHealth = 2500
- attacktext = "clubs"
+ attacktext = "slams into"
attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
icon_state = "hierophant"
icon_living = "hierophant"
@@ -47,7 +47,7 @@ Difficulty: Hard
icon = 'icons/mob/lavaland/hierophant_new.dmi'
faction = list("boss") //asteroid mobs? get that shit out of my beautiful square house
speak_emote = list("preaches")
- armour_penetration_percentage = 50
+ armour_penetration_percentage = 100 //It does 15 damage / only attacks when enraged
melee_damage_lower = 15
melee_damage_upper = 15
speed = 10
@@ -63,6 +63,7 @@ Difficulty: Hard
score_type = HIEROPHANT_SCORE
del_on_death = TRUE
death_sound = 'sound/magic/repulse.ogg'
+ enraged_loot = /obj/item/disk/fauna_research/hierophant
attack_action_types = list(/datum/action/innate/megafauna_attack/blink,
/datum/action/innate/megafauna_attack/chaser_swarm,
/datum/action/innate/megafauna_attack/cross_blasts,
@@ -81,10 +82,13 @@ Difficulty: Hard
var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...", "Kix fiex. Liepmrk...")
var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
var/list/stored_nearby = list() // stores people nearby the hierophant when it enters the death animation
+ ///If the hiero has changed colour, stop the rays animation.
+ var/colour_shifting = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/Initialize(mapload)
. = ..()
spawned_beacon = new(loc)
+ AddComponent(/datum/component/boss_music, 'sound/lavaland/hiero_boss.ogg', 145 SECONDS)
/datum/action/innate/megafauna_attack/blink
name = "Blink To Target"
@@ -114,6 +118,14 @@ Difficulty: Hard
chosen_message = "You are now repeatedly blinking at your target."
chosen_attack_num = 4
+/mob/living/simple_animal/hostile/megafauna/hierophant/enrage()
+ . = ..()
+ move_to_delay = 5
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/unrage()
+ . = ..()
+ move_to_delay = initial(move_to_delay)
+
/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
if(blinking)
return
@@ -194,12 +206,26 @@ Difficulty: Hard
else //just release a burst of power
INVOKE_ASYNC(src, PROC_REF(burst), get_turf(src))
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/easy_anti_cheese(mob/living/simple_animal/S)
+ if(enraged || get_dist(S, src) > 20)
+ return
+ for(var/mob/living/L in urange(20, src))
+ if(L.client)
+ enrage()
+ arena_trap(L, TRUE)
+ FindTarget(list(L), 1)
+ for(var/mob/living/simple_animal/hostile/megafauna/colossus/C in GLOB.mob_list)
+ UnregisterSignal(C, COMSIG_MOB_APPLY_DAMAGE)
+ break
+
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink_spam(blink_counter, target_slowness, cross_counter)
ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
- if(health < maxHealth * 0.5 && blink_counter > 1)
+ if(((health < maxHealth * 0.5) || enraged) && blink_counter > 1)
visible_message("\"Mx ampp rsx iwgeti.\"")
var/oldcolor = color
animate(src, color = "#660099", time = 6)
+ colour_shifting = TRUE
+ remove_filter("rays")
SLEEP_CHECK_DEATH(6)
while(!QDELETED(target) && blink_counter)
if(loc == target.loc || loc == target) //we're on the same tile as them after about a second we can stop now
@@ -210,6 +236,7 @@ Difficulty: Hard
blinking = TRUE
SLEEP_CHECK_DEATH(4 + target_slowness)
animate(src, color = oldcolor, time = 8)
+ colour_shifting = FALSE
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8)
SLEEP_CHECK_DEATH(8)
blinking = FALSE
@@ -222,6 +249,8 @@ Difficulty: Hard
blinking = TRUE
var/oldcolor = color
animate(src, color = "#660099", time = 6)
+ colour_shifting = TRUE
+ remove_filter("rays")
SLEEP_CHECK_DEATH(6)
while(!QDELETED(target) && cross_counter)
cross_counter--
@@ -231,6 +260,7 @@ Difficulty: Hard
INVOKE_ASYNC(src, PROC_REF(blasts), target, GLOB.diagonals)
SLEEP_CHECK_DEATH(6 + target_slowness)
animate(src, color = oldcolor, time = 8)
+ colour_shifting = FALSE
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8)
SLEEP_CHECK_DEATH(8)
blinking = FALSE
@@ -242,6 +272,8 @@ Difficulty: Hard
blinking = TRUE
var/oldcolor = color
animate(src, color = "#660099", time = 6)
+ colour_shifting = TRUE
+ remove_filter("rays")
SLEEP_CHECK_DEATH(6)
var/list/targets = ListTargets()
var/list/cardinal_copy = GLOB.cardinal.Copy()
@@ -259,6 +291,7 @@ Difficulty: Hard
SLEEP_CHECK_DEATH(8 + target_slowness)
chaser_cooldown = world.time + initial(chaser_cooldown)
animate(src, color = oldcolor, time = 8)
+ colour_shifting = FALSE
addtimer(CALLBACK(src, TYPE_PROC_REF(/atom, update_atom_colour)), 8)
SLEEP_CHECK_DEATH(8)
blinking = FALSE
@@ -273,7 +306,7 @@ Difficulty: Hard
new /obj/effect/temp_visual/hierophant/telegraph/diagonal(T, src)
else
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
- playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
+ playsound(T,'sound/effects/bin_close.ogg', 75, TRUE)
SLEEP_CHECK_DEATH(2)
new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
for(var/d in directions)
@@ -288,19 +321,20 @@ Difficulty: Hard
previousturf = J
J = get_step(previousturf, set_dir)
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_trap(mob/victim) //trap a target in an arena
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_trap(mob/victim, forced = FALSE) //trap a target in an arena
var/turf/T = get_turf(victim)
if(!istype(victim) || victim.stat == DEAD || !T || arena_cooldown > world.time)
return
if((istype(get_area(T), /area/ruin/unpowered/hierophant) || istype(get_area(src), /area/ruin/unpowered/hierophant)) && victim != src)
- return
+ if(!forced)
+ return
arena_cooldown = world.time + initial(arena_cooldown)
for(var/d in GLOB.cardinal)
INVOKE_ASYNC(src, PROC_REF(arena_squares), T, d)
for(var/t in RANGE_EDGE_TURFS(11, T))
new /obj/effect/temp_visual/hierophant/wall(t, src)
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
- if(get_dist(src, T) >= 11) //hey you're out of range I need to get closer to you!
+ if(get_dist(src, T) >= 11 || forced) //hey you're out of range I need to get closer to you!
INVOKE_ASYNC(src, PROC_REF(blink), T)
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/arena_squares(turf/T, set_dir) //make a fancy effect extending from the arena target
@@ -322,8 +356,8 @@ Difficulty: Hard
var/turf/source = get_turf(src)
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
new /obj/effect/temp_visual/hierophant/telegraph(source, src)
- playsound(T,'sound/magic/wand_teleport.ogg', 200, TRUE)
- playsound(source,'sound/machines/airlock_open.ogg', 200, TRUE)
+ playsound(T,'sound/magic/wand_teleport.ogg', 80, TRUE)
+ playsound(source,'sound/machines/airlock_open.ogg', 80, TRUE)
blinking = TRUE
SLEEP_CHECK_DEATH(2) //short delay before we start...
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src)
@@ -355,14 +389,14 @@ Difficulty: Hard
if(!T)
return
new /obj/effect/temp_visual/hierophant/telegraph(T, src)
- playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
+ playsound(T,'sound/effects/bin_close.ogg', 75, TRUE)
SLEEP_CHECK_DEATH(2)
for(var/t in RANGE_TURFS(1, T))
new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
//expanding square
/proc/hierophant_burst(mob/caster, turf/original, burst_range, spread_speed = 0.5)
- playsound(original,'sound/machines/airlock_open.ogg', 200, TRUE)
+ playsound(original,'sound/machines/airlock_open.ogg', 75, TRUE)
var/last_dist = 0
for(var/t in spiral_range_turfs(burst_range, original))
var/turf/T = t
@@ -377,8 +411,25 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original, spread_speed)
hierophant_burst(src, original, burst_range, spread_speed)
+/mob/living/simple_animal/hostile/megafauna/hierophant/float(on) //we don't want this guy to float, messes up his animations
+ if(throwing)
+ return
+ floating = on
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/do_attack_animation(atom/A, visual_effect_icon, obj/item/used_item, no_effect)
+ if(!enraged) //We do not want it to animate attacking as that breaks the cool animation. If it is not enraged, it can do it. However this only happens if admin controlled
+ ..()
+
/mob/living/simple_animal/hostile/megafauna/hierophant/Life()
. = ..()
+ if(enraged && !colour_shifting)
+ var/new_filter = isnull(get_filter("ray"))
+ ray_filter_helper(1, 40, "#660099", 6, 20, 16)
+ if(new_filter)
+ animate(get_filter("ray"), offset = 10, y = 8, time = 10 SECONDS, loop = -1)
+ animate(offset = 0, time = 10 SECONDS)
+ else
+ remove_filter("ray")
if(. && spawned_beacon && !QDELETED(spawned_beacon) && !client)
if(target || loc == spawned_beacon.loc)
timeout_time = initial(timeout_time)
@@ -399,6 +450,8 @@ Difficulty: Hard
if(health > 0 || stat == DEAD)
return
else
+ for(var/mob/living/simple_animal/hostile/megafauna/colossus/C in GLOB.mob_list)
+ UnregisterSignal(C, COMSIG_MOB_APPLY_DAMAGE)
set_stat(DEAD)
blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
visible_message("\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"")
@@ -448,6 +501,11 @@ Difficulty: Hard
if(target && isliving(target))
var/mob/living/L = target
if(L.stat != DEAD)
+ if(enraged)
+ ..()
+ if(L.move_resist < INFINITY)
+ var/atom/throw_target = get_edge_target_turf(L, get_dir(src, get_step_away(L, src)))
+ L.throw_at(throw_target, 1, 2) //Yeet them away. Makes crusher harder / stops endless backstab
if(ranged_cooldown <= world.time)
calculate_rage()
ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75)
@@ -474,7 +532,7 @@ Difficulty: Hard
if(!stat && .)
var/obj/effect/temp_visual/hierophant/squares/HS = new(oldLoc)
HS.setDir(movement_dir)
- playsound(src, 'sound/mecha/mechmove04.ogg', 150, TRUE, -4)
+ playsound(src, 'sound/mecha/mechmove04.ogg', 65, TRUE, -4)
if(target)
arena_trap(target)
@@ -485,7 +543,7 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/proc/calculate_rage() //how angry we are overall
did_reset = FALSE //oh hey we're doing SOMETHING, clearly we might need to heal if we recall
- anger_modifier = clamp(((maxHealth - health) / 42),0,50)
+ anger_modifier = clamp((max((maxHealth - health) / 42, enraged ? 40 : 0)),0,50)
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
@@ -666,7 +724,7 @@ Difficulty: Hard
var/turf/T = get_turf(src)
if(!T)
return
- playsound(T,'sound/magic/blind.ogg', 125, TRUE, -5) //make a sound
+ playsound(T,'sound/magic/blind.ogg', 65, TRUE, -5) //make a sound
sleep(6) //wait a little
bursting = TRUE
do_damage(T) //do damage and mark us as bursting
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
index 7ee14ad12dbb..75a4d1cc5e91 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/legion.dm
@@ -45,6 +45,7 @@ Difficulty: Medium
score_type = LEGION_SCORE
loot = list(/obj/item/storm_staff)
crusher_loot = list(/obj/item/storm_staff, /obj/item/crusher_trophy/empowered_legion_skull)
+ enraged_loot = /obj/item/disk/fauna_research/legion
vision_range = 13
elimination = TRUE
appearance_flags = 0
@@ -56,6 +57,36 @@ Difficulty: Medium
. = ..()
transform *= 2
+/mob/living/simple_animal/hostile/megafauna/legion/enrage()
+ health = 1250
+ maxHealth = 1250
+ transform /= 1.5
+ loot = list(/datum/nothing)
+ crusher_loot = list(/datum/nothing)
+ var/mob/living/simple_animal/hostile/megafauna/legion/legiontwo = new /mob/living/simple_animal/hostile/megafauna/legion(get_turf(src))
+ legiontwo.transform /= 1.5
+ legiontwo.loot = list(/datum/nothing)
+ legiontwo.crusher_loot = list(/datum/nothing)
+ legiontwo.health = 1250
+ legiontwo.maxHealth = 1250
+
+/mob/living/simple_animal/hostile/megafauna/legion/unrage()
+ . = ..()
+ for(var/mob/living/simple_animal/hostile/megafauna/legion/other in GLOB.mob_list)
+ if(other != src)
+ other.loot = initial(loot)
+ other.crusher_loot = initial(crusher_loot)
+ other.maxHealth = 2500
+ other.health = 2500
+ qdel(src) //Suprise, it's the one on lavaland that regrows to full.
+
+/mob/living/simple_animal/hostile/megafauna/legion/death(gibbed)
+ for(var/mob/living/simple_animal/hostile/megafauna/legion/other in GLOB.mob_list)
+ if(other != src)
+ other.loot = initial(loot)
+ other.crusher_loot = initial(crusher_loot)
+ . = ..()
+
/mob/living/simple_animal/hostile/megafauna/legion/AttackingTarget()
. = ..()
if(. && ishuman(target))
@@ -98,7 +129,11 @@ Difficulty: Medium
"You summon a big [A]!")
ranged_cooldown = world.time + 5 SECONDS
else
- var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril/A = new(loc)
+ var/mob/living/simple_animal/hostile/asteroid/hivelord/legion/A
+ if(enraged)
+ A = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/advanced/tendril(loc)
+ else
+ A = new /mob/living/simple_animal/hostile/asteroid/hivelord/legion/tendril(loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
@@ -159,11 +194,15 @@ Difficulty: Medium
return
if(.)
var/matrix/M = new
- resize = 1 + (health / maxHealth)
+ resize = (enraged ? 0.33 : 1) + (health / maxHealth)
M.Scale(resize, resize)
transform = M
- if(amount > 0 && prob(33))
- var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/A = new(loc)
+ if(amount > 0 && (enraged || prob(33)))
+ var/mob/living/simple_animal/hostile/asteroid/hivelordbrood/A
+ if(enraged)
+ A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion/advanced(loc)
+ else
+ A = new /mob/living/simple_animal/hostile/asteroid/hivelordbrood/legion(loc)
A.GiveTarget(target)
A.friends = friends
A.faction = faction
diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
index fdc8f6cc87a5..9e244ae95ea3 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/megafauna.dm
@@ -40,6 +40,10 @@
var/nest_range = 10
var/chosen_attack = 1 // chosen attack num
var/list/attack_action_types = list()
+ /// Has someone enabled hard mode?
+ var/enraged = FALSE
+ /// Path of the hardmode loot disk, if applicable.
+ var/enraged_loot
/mob/living/simple_animal/hostile/megafauna/Initialize(mapload)
. = ..()
@@ -74,6 +78,10 @@
var/datum/status_effect/crusher_damage/C = has_status_effect(STATUS_EFFECT_CRUSHERDAMAGETRACKING)
if(C && crusher_loot && C.total_damage >= maxHealth * 0.6)
spawn_crusher_loot()
+ if(enraged && length(loot) && enraged_loot) //Don't drop a disk if the boss drops no loot. Important for legion.
+ for(var/mob/living/M in urange(20, src)) //Yes big range, but for bubblegum arena
+ if(M.client)
+ loot += enraged_loot //Disk for each miner / borg.
if(!elimination) //used so the achievment only occurs for the last legion to die.
SSblackbox.record_feedback("tally", "megafauna_kills", 1, "[initial(name)]")
return ..()
@@ -89,10 +97,15 @@
var/mob/living/L = target
if(L.stat != DEAD)
if(!client && ranged && ranged_cooldown <= world.time)
- OpenFire()
+ OpenFire(L)
else
devour(L)
+/mob/living/simple_animal/hostile/megafauna/onTransitZ(old_z, new_z)
+ . = ..()
+ if(!istype(get_area(src), /area/shuttle)) //I'll be funny and make non teleported enrage mobs not lose enrage. Harder to pull off, and also funny when it happens accidently. Or if one gets on the escape shuttle.
+ unrage()
+
/mob/living/simple_animal/hostile/megafauna/onShuttleMove(turf/oldT, turf/T1, rotation, mob/caller)
var/turf/oldloc = loc
. = ..()
@@ -130,6 +143,15 @@
recovery_time = world.time + buffer_time
ranged_cooldown = world.time + buffer_time
+/// This proc is called by the HRD-MDE grenade to enrage the megafauna. This should increase the megafaunas attack speed if possible, give it new moves, or disable weak moves. This should be reverseable, and reverses on zlvl change.
+/mob/living/simple_animal/hostile/megafauna/proc/enrage()
+ if(enraged || ((health / maxHealth) * 100 <= 80))
+ return
+ enraged = TRUE
+
+/mob/living/simple_animal/hostile/megafauna/proc/unrage()
+ enraged = FALSE
+
/mob/living/simple_animal/hostile/megafauna/DestroySurroundings()
. = ..()
for(var/turf/simulated/floor/chasm/C in circlerangeturfs(src, 1))
diff --git a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
index 04c2a1f032d2..4c89d2b6bd94 100644
--- a/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
+++ b/code/modules/mob/living/simple_animal/hostile/mining/hivelord.dm
@@ -273,6 +273,9 @@
stat_attack = DEAD
can_infest_dead = TRUE
+/mob/living/simple_animal/hostile/asteroid/hivelord/legion/advanced/tendril
+ fromtendril = TRUE
+
//Legion that spawns Legions
/mob/living/simple_animal/hostile/asteroid/big_legion
name = "big legion"
diff --git a/icons/effects/bubblegum.dmi b/icons/effects/bubblegum.dmi
index a53dd7d563aa..76c0c0caf9fc 100644
Binary files a/icons/effects/bubblegum.dmi and b/icons/effects/bubblegum.dmi differ
diff --git a/icons/effects/spawner_icons.dmi b/icons/effects/spawner_icons.dmi
index cd78697ca168..a01678d2301d 100644
Binary files a/icons/effects/spawner_icons.dmi and b/icons/effects/spawner_icons.dmi differ
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
index f4369f4acac2..b3a990bc54c1 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/mob/screen_fog.dmi b/icons/mob/screen_fog.dmi
new file mode 100644
index 000000000000..762578101579
Binary files /dev/null and b/icons/mob/screen_fog.dmi differ
diff --git a/icons/mob/ties.dmi b/icons/mob/ties.dmi
index fd40d8db0618..2b6f4974624d 100644
Binary files a/icons/mob/ties.dmi and b/icons/mob/ties.dmi differ
diff --git a/icons/obj/clothing/ties.dmi b/icons/obj/clothing/ties.dmi
index d9a988e02d23..d48bd8258eec 100644
Binary files a/icons/obj/clothing/ties.dmi and b/icons/obj/clothing/ties.dmi differ
diff --git a/icons/obj/clothing/ties_overlay.dmi b/icons/obj/clothing/ties_overlay.dmi
index 727aaa911639..68fbd505ae75 100644
Binary files a/icons/obj/clothing/ties_overlay.dmi and b/icons/obj/clothing/ties_overlay.dmi differ
diff --git a/icons/obj/grenade.dmi b/icons/obj/grenade.dmi
index 5d619868eadc..e175f79dc9f8 100644
Binary files a/icons/obj/grenade.dmi and b/icons/obj/grenade.dmi differ
diff --git a/icons/obj/module.dmi b/icons/obj/module.dmi
index a1dad69342b2..fe9c40361f11 100644
Binary files a/icons/obj/module.dmi and b/icons/obj/module.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 805bd67a0a37..28009db6d493 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -364,6 +364,7 @@
#include "code\datums\cache\powermonitor.dm"
#include "code\datums\components\_component.dm"
#include "code\datums\components\boomerang.dm"
+#include "code\datums\components\boss_music.dm"
#include "code\datums\components\caltrop.dm"
#include "code\datums\components\deadchat_control.dm"
#include "code\datums\components\decal.dm"
@@ -1938,6 +1939,7 @@
#include "code\modules\mining\satchel_ore_boxdm.dm"
#include "code\modules\mining\shelters.dm"
#include "code\modules\mining\equipment\explorer_gear.dm"
+#include "code\modules\mining\equipment\hardmode_grenade.dm"
#include "code\modules\mining\equipment\kinetic_crusher.dm"
#include "code\modules\mining\equipment\lazarus_injector.dm"
#include "code\modules\mining\equipment\marker_beacons.dm"
diff --git a/sound/lavaland/hiero_boss.ogg b/sound/lavaland/hiero_boss.ogg
new file mode 100644
index 000000000000..23412b5346d1
Binary files /dev/null and b/sound/lavaland/hiero_boss.ogg differ