diff --git a/_maps/map_files/cyberiad/cyberiad.dmm b/_maps/map_files/cyberiad/cyberiad.dmm
index 40efa820622..16ae46b48d7 100644
--- a/_maps/map_files/cyberiad/cyberiad.dmm
+++ b/_maps/map_files/cyberiad/cyberiad.dmm
@@ -28853,7 +28853,7 @@
/area/chapel/office)
"baA" = (
/obj/structure/rack,
-/obj/item/storage/fancy/candle_box,
+/obj/item/storage/fancy/candle_box/full,
/turf/simulated/floor/plasteel{
icon_state = "vault";
dir = 5
@@ -31966,13 +31966,13 @@
/area/chapel/office)
"bfW" = (
/obj/structure/rack,
-/obj/item/storage/fancy/candle_box,
-/obj/item/storage/fancy/candle_box{
+/obj/item/storage/fancy/candle_box/full{
pixel_x = -3;
pixel_y = 3
},
-/obj/item/storage/fancy/candle_box{
- pixel_x = 3;
+/obj/item/storage/fancy/candle_box/full,
+/obj/item/storage/fancy/candle_box/full{
+ pixel_x = -3;
pixel_y = -3
},
/turf/simulated/floor/plating,
@@ -35632,7 +35632,7 @@
/area/chapel/main)
"bmU" = (
/obj/structure/table/wood,
-/obj/item/storage/fancy/candle_box,
+/obj/item/storage/fancy/candle_box/full,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -79001,7 +79001,7 @@
"cKD" = (
/obj/structure/table,
/obj/structure/window/reinforced,
-/obj/item/storage/fancy/candle_box,
+/obj/item/storage/fancy/candle_box/full,
/turf/simulated/floor/plating,
/area/maintenance/asmaint)
"cKE" = (
diff --git a/_maps/map_files/cyberiad/z2.dmm b/_maps/map_files/cyberiad/z2.dmm
index b6544287437..c7620721a8c 100644
--- a/_maps/map_files/cyberiad/z2.dmm
+++ b/_maps/map_files/cyberiad/z2.dmm
@@ -1867,7 +1867,7 @@
icon_state = "tube1";
dir = 1
},
-/obj/machinery/computer/syndicate_depot/teleporter/targeted,
+/obj/machinery/computer/syndicate_depot/teleporter,
/turf/unsimulated/floor{
icon_state = "dark"
},
diff --git a/_maps/map_files/cyberiad/z6.dmm b/_maps/map_files/cyberiad/z6.dmm
index 0ee95c18491..b2171008b2b 100644
--- a/_maps/map_files/cyberiad/z6.dmm
+++ b/_maps/map_files/cyberiad/z6.dmm
@@ -5428,16 +5428,6 @@
/obj/item/stack/tile,
/turf/space,
/area/space/nearstation)
-"lz" = (
-/obj/machinery/light{
- dir = 1;
- on = 1
- },
-/obj/machinery/portable_atmospherics/canister/air,
-/turf/simulated/floor/plasteel{
- icon_state = "dark"
- },
-/area/syndicate_depot/core)
"lA" = (
/obj/machinery/door/poddoor{
id_tag = "syndi_depot_lvl2";
@@ -5698,7 +5688,7 @@
},
/area/syndicate_depot/outer)
"mm" = (
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"mn" = (
/obj/machinery/light{
@@ -5866,7 +5856,7 @@
/area/syndicate_depot/core)
"mK" = (
/obj/structure/sign/poster/contraband/syndicate_recruitment,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"mL" = (
/obj/machinery/door/unpowered/shuttle,
@@ -5887,7 +5877,7 @@
/area/syndicate_depot/core)
"mO" = (
/obj/structure/sign/poster/contraband/lamarr,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"mP" = (
/obj/structure/closet/crate,
@@ -6067,8 +6057,8 @@
name = "Derelict Annex"
})
"no" = (
-/obj/machinery/bluespace_beacon/syndicate,
/obj/effect/decal/warning_stripes/yellow,
+/obj/machinery/bluespace_beacon/syndicate,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -6118,7 +6108,7 @@
/area/syndicate_depot/core)
"nt" = (
/obj/structure/sign/poster/contraband/fun_police,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nu" = (
/obj/machinery/door/poddoor/multi_tile/two_tile_hor,
@@ -6157,20 +6147,21 @@
"nz" = (
/obj/item/lighter/zippo/black,
/obj/structure/table,
+/obj/effect/spawner/random_spawners/syndicate/loot/stetchkin,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
/area/syndicate_depot/core)
"nA" = (
/obj/structure/sign/poster/contraband/lusty_xenomorph,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nB" = (
/obj/effect/landmark{
dir = 6;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nC" = (
/obj/effect/spawner/random_spawners/syndicate/layout/door/vault,
@@ -6187,7 +6178,7 @@
dir = 4;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nE" = (
/obj/structure/sign/poster/contraband/energy_swords,
@@ -6195,7 +6186,7 @@
dir = 4;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nF" = (
/obj/effect/spawner/random_spawners/syndicate/layout/spacepod,
@@ -6209,18 +6200,18 @@
dir = 4;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nH" = (
/obj/effect/landmark{
dir = 10;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nI" = (
/obj/structure/sign/poster/official/high_class_martini,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nJ" = (
/obj/machinery/light/small{
@@ -6282,11 +6273,11 @@
/area/syndicate_depot/core)
"nQ" = (
/obj/structure/sign/poster/official/air1,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nR" = (
-/obj/item/storage/box/donkpockets,
/obj/structure/table,
+/obj/item/storage/box/donkpockets,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -6305,11 +6296,11 @@
/area/syndicate_depot/core)
"nU" = (
/obj/structure/sign/poster/contraband/tools,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nV" = (
/obj/structure/sign/poster/contraband/hacking_guide,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"nW" = (
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/officer,
@@ -6479,7 +6470,7 @@
/area/syndicate_depot/core)
"os" = (
/obj/structure/table,
-/obj/item/wrench,
+/obj/effect/spawner/random_spawners/syndicate/loot/stetchkin,
/turf/simulated/floor/plasteel{
icon_state = "dark"
},
@@ -6533,14 +6524,14 @@
d2 = 2;
icon_state = "1-2"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oz" = (
/obj/effect/landmark{
dir = 5;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oA" = (
/obj/structure/sign/poster/contraband/syndicate_pistol,
@@ -6548,7 +6539,7 @@
dir = 4;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oB" = (
/obj/effect/spawner/random_spawners/syndicate/mob,
@@ -6559,29 +6550,17 @@
dir = 9;
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oD" = (
/obj/structure/sign/poster/official/state_laws,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oE" = (
/obj/effect/landmark{
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
-/area/syndicate_depot/core)
-"oF" = (
-/obj/machinery/door_control{
- active_power_usage = 0;
- id = "syndi_depot_rear";
- idle_power_usage = 0;
- name = "mysterious button";
- normaldoorcontrol = 0;
- use_power = 0
- },
-/obj/structure/sign/poster/contraband/syndicate_recruitment,
-/turf/simulated/wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oG" = (
/obj/effect/decal/warning_stripes/east,
@@ -6639,33 +6618,9 @@
},
/turf/simulated/floor/mineral/silver,
/area/syndicate_depot/core)
-"oN" = (
-/obj/machinery/door_control{
- active_power_usage = 0;
- id = "syndi_depot_rear";
- idle_power_usage = 0;
- name = "mysterious button";
- normaldoorcontrol = 0;
- pixel_x = 24;
- use_power = 0
- },
-/turf/simulated/floor/plasteel{
- icon_state = "dark"
- },
-/area/syndicate_depot/core)
"oO" = (
/obj/structure/sign/poster/contraband/missing_gloves,
-/turf/simulated/wall/r_wall,
-/area/syndicate_depot/core)
-"oP" = (
-/obj/machinery/door/poddoor{
- id_tag = "syndi_depot_rear";
- name = "Sealed Doors";
- protected = 0
- },
-/turf/simulated/floor/plasteel{
- icon_state = "dark"
- },
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oQ" = (
/obj/machinery/atmospherics/unary/passive_vent/high_volume{
@@ -6740,7 +6695,7 @@
/obj/effect/landmark{
name = "syndi_depot_shield"
},
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"oY" = (
/obj/machinery/atmospherics/unary/passive_vent/high_volume{
@@ -6790,10 +6745,6 @@
pixel_x = 24
},
/obj/structure/cable,
-/obj/machinery/turretid/syndicate{
- name = "external turret controls";
- pixel_y = 32
- },
/turf/simulated/floor/plating/airless,
/area/syndicate_depot/outer)
"pf" = (
@@ -6821,7 +6772,7 @@
/area/syndicate_depot/outer)
"pi" = (
/obj/structure/sign/poster/official/obey,
-/turf/simulated/wall/r_wall,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
/area/syndicate_depot/core)
"pj" = (
/turf/simulated/floor/plasteel{
@@ -6865,13 +6816,6 @@
icon_state = "brown"
},
/area/derelict/arrival)
-"pp" = (
-/turf/simulated/mineral,
-/area/syndicate_depot/core)
-"pq" = (
-/obj/effect/spawner/random_spawners/blood_maybe,
-/turf/simulated/floor/plating/asteroid/airless,
-/area/syndicate_depot/core)
"pr" = (
/obj/structure/closet/crate/can,
/obj/effect/spawner/lootdrop/maintenance,
@@ -6933,17 +6877,6 @@
/area/derelict/eva{
name = "Derelict Annex"
})
-"pw" = (
-/obj/item/candle,
-/obj/structure/table,
-/turf/simulated/floor/plating/asteroid/airless,
-/area/syndicate_depot/core)
-"px" = (
-/obj/structure/chair{
- dir = 8
- },
-/turf/simulated/floor/plating/asteroid/airless,
-/area/syndicate_depot/core)
"py" = (
/obj/structure/chair{
dir = 8
@@ -6971,13 +6904,6 @@
/obj/structure/spider/stickyweb,
/turf/simulated/floor/plasteel,
/area/derelict/crew_quarters)
-"pC" = (
-/turf/simulated/floor/plating/asteroid/airless,
-/area/syndicate_depot/core)
-"pD" = (
-/obj/structure/falsewall,
-/turf/simulated/floor/plating/airless,
-/area/syndicate_depot/core)
"pE" = (
/obj/machinery/light/small{
dir = 8
@@ -6987,9 +6913,6 @@
icon_state = "dark"
},
/area/syndicate_depot/core)
-"pF" = (
-/turf/simulated/wall,
-/area/syndicate_depot/core)
"pG" = (
/obj/structure/flora/rock/pile,
/turf/simulated/floor/plating/airless,
@@ -11101,6 +11024,18 @@
dir = 9
},
/area/derelict/arrival)
+"yg" = (
+/obj/machinery/door_control{
+ active_power_usage = 0;
+ id = "syndi_depot_rear";
+ idle_power_usage = 0;
+ name = "mysterious button";
+ normaldoorcontrol = 0;
+ use_power = 0
+ },
+/obj/structure/sign/poster/contraband/syndicate_recruitment,
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
+/area/syndicate_depot/outer)
"yh" = (
/obj/structure/rack,
/obj/item/newspaper{
@@ -11666,6 +11601,141 @@
icon_state = "dark"
},
/area/syndicate_depot/core)
+"BB" = (
+/obj/structure/falsewall,
+/obj/structure/fans/tiny,
+/turf/simulated/floor/plating/airless,
+/area/syndicate_depot/outer)
+"DH" = (
+/obj/machinery/light{
+ dir = 1;
+ on = 1
+ },
+/obj/item/flag/chameleon{
+ icon_state = "syndiflag";
+ name = "Syndicate Flag";
+ used = 1
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/core)
+"GF" = (
+/obj/item/flag/chameleon{
+ icon_state = "syndiflag";
+ name = "Syndicate Flag";
+ used = 1
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"GH" = (
+/obj/effect/spawner/random_spawners/syndicate/turret,
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"Hg" = (
+/obj/structure/dispenser,
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"KK" = (
+/obj/machinery/door/airlock/external{
+ id_tag = "sst_away";
+ req_access_txt = "150"
+ },
+/obj/structure/fans/tiny,
+/turf/unsimulated/floor{
+ name = "plating"
+ },
+/area/syndicate_depot/outer)
+"Mc" = (
+/obj/machinery/door/poddoor{
+ id_tag = "syndi_depot_rear";
+ name = "Sealed Doors";
+ protected = 0
+ },
+/obj/machinery/door/airlock/external{
+ id_tag = "sst_away";
+ req_access_txt = "150"
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"OV" = (
+/obj/machinery/door/airlock/external{
+ id_tag = "sst_away";
+ req_access_txt = "150"
+ },
+/obj/structure/fans/tiny,
+/turf/unsimulated/floor{
+ name = "plating"
+ },
+/area/syndicate_depot/core)
+"OX" = (
+/turf/simulated/wall/mineral/plastitanium/nodiagonal,
+/area/syndicate_depot/outer)
+"Pn" = (
+/obj/structure/table,
+/obj/effect/spawner/random_spawners/syndicate/loot/stetchkin,
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"Sv" = (
+/obj/effect/spawner/random_spawners/blood_maybe,
+/turf/simulated/floor/plating/asteroid/airless,
+/area/syndicate_depot/outer)
+"UB" = (
+/obj/item/candle,
+/obj/structure/table,
+/turf/simulated/floor/plating/asteroid/airless,
+/area/syndicate_depot/outer)
+"UM" = (
+/obj/machinery/door_control{
+ active_power_usage = 0;
+ id = "syndi_depot_rear";
+ idle_power_usage = 0;
+ name = "mysterious button";
+ normaldoorcontrol = 0;
+ pixel_x = 24;
+ use_power = 0
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"Yh" = (
+/obj/machinery/light{
+ dir = 1;
+ on = 1
+ },
+/obj/machinery/portable_atmospherics/canister/oxygen,
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
+"YV" = (
+/obj/structure/chair{
+ dir = 8
+ },
+/turf/simulated/floor/plating/asteroid/airless,
+/area/syndicate_depot/outer)
+"ZQ" = (
+/obj/machinery/turretid/syndicate{
+ name = "external turret controls";
+ pixel_x = -32;
+ pixel_y = 0;
+ req_access = list(150)
+ },
+/turf/simulated/floor/plasteel{
+ icon_state = "dark"
+ },
+/area/syndicate_depot/outer)
(1,1,1) = {"
aa
@@ -55577,7 +55647,7 @@ lK
lK
mi
lK
-mf
+lK
lK
lK
lK
@@ -56614,7 +56684,7 @@ mm
mm
mm
lK
-mf
+lK
lK
lI
lI
@@ -59924,7 +59994,7 @@ aa
aa
lG
lH
-lH
+lI
lH
lH
lH
@@ -60439,7 +60509,7 @@ aa
lF
lH
lH
-lH
+lI
lH
lH
lI
@@ -60457,7 +60527,7 @@ mw
mA
mA
mm
-lV
+DH
mA
nZ
ol
@@ -60729,7 +60799,7 @@ mm
mm
nx
mA
-mA
+os
mm
lK
lK
@@ -61211,7 +61281,7 @@ lF
lH
lH
lH
-lH
+lI
lH
lH
lH
@@ -61466,7 +61536,7 @@ aa
aa
lF
lH
-lH
+lI
lH
lH
lH
@@ -61481,7 +61551,7 @@ mm
mB
mm
mm
-mm
+mB
mm
mm
mm
@@ -61734,7 +61804,7 @@ lI
lK
mg
mm
-lz
+mR
mA
mB
mA
@@ -61991,12 +62061,12 @@ lK
lK
lK
mm
-ms
+mM
mA
mO
mh
mA
-zP
+mA
mm
mA
mA
@@ -62255,7 +62325,7 @@ nk
ns
mA
nA
-mR
+lV
mA
nS
mm
@@ -62494,7 +62564,7 @@ aa
aa
lG
lH
-lH
+lI
lH
lH
lH
@@ -62512,7 +62582,7 @@ no
mA
zP
mm
-mM
+zP
mA
mA
ob
@@ -62522,7 +62592,7 @@ oe
pa
mm
nM
-oN
+mA
mA
mA
mM
@@ -62756,7 +62826,7 @@ lH
lH
lH
lH
-lH
+lI
lI
lI
lK
@@ -62770,6 +62840,7 @@ mm
mm
mm
mm
+OV
mm
mm
mm
@@ -62780,7 +62851,6 @@ mm
mm
mm
mm
-mC
mm
mm
mm
@@ -63011,8 +63081,8 @@ lH
lH
lH
lH
-lH
-lH
+lI
+lI
lI
lI
lI
@@ -63028,17 +63098,17 @@ lK
lK
lK
lK
-mn
+lK
+lK
+lK
+lK
mf
-lK
-lK
-lK
mn
lK
lK
-mC
-zO
-mC
+lK
+lK
+lK
lK
lK
lK
@@ -63265,17 +63335,20 @@ aa
aa
lF
lH
-lH
-lH
-lH
-lH
-lH
+lI
lH
lI
lI
lI
lI
lI
+lI
+lI
+lI
+lI
+lK
+lK
+lK
lK
lK
lK
@@ -63293,9 +63366,6 @@ lK
lK
lK
lK
-mm
-oP
-mm
lK
lK
lK
@@ -63523,36 +63593,36 @@ aa
lF
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lI
-lI
-lI
-lI
-lI
-lK
-lK
-lI
-lI
-lI
-lI
-lI
-lK
lI
lI
lI
lI
lI
lI
-pp
-pp
-pD
-pp
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+OX
+KK
+OX
+OX
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
lI
lI
lI
@@ -63782,12 +63852,6 @@ lH
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
lI
lI
lI
@@ -63802,14 +63866,17 @@ lI
lI
lI
lI
+OX
+Hg
+lX
+lX
+OX
lI
lI
lI
lI
-oF
-pw
-pC
-pp
+OX
+OX
lI
lI
lI
@@ -63817,7 +63884,10 @@ lI
lI
lI
lI
-lH
+lI
+lK
+lI
+lI
lH
lH
lH
@@ -64038,36 +64108,37 @@ lF
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
lI
lI
lI
lI
lI
lI
-lH
-lH
lI
lI
lI
lI
lI
+lI
+lI
+lI
+lI
+OX
+Yh
+lX
+lX
+OX
+OX
+yg
lK
-me
+UB
lK
lK
-pq
-px
-pq
-pF
lI
+lI
+lI
+OX
+OX
lK
lK
lK
@@ -64081,7 +64152,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -64292,43 +64362,44 @@ aa
aa
aa
lF
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lI
-lI
lI
lH
lH
lH
lI
-lH
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+Pn
+lX
+lX
+Mc
+ZQ
+BB
+lK
+YV
+Sv
+OX
+OX
+lI
lI
lI
lK
-lK
-lK
-lK
-lI
-lI
-me
-lI
-lI
-lH
lI
lK
-me
-lH
+OX
+OX
lI
lH
lH
@@ -64338,7 +64409,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -64552,30 +64622,31 @@ lF
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
lI
lI
lI
-lH
-lH
lI
lI
-lH
-lH
-me
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+GF
+lX
+UM
+OX
+OX
+lI
+Sv
+lK
lK
-me
-lI
-lI
lI
lK
lK
@@ -64595,7 +64666,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -64808,34 +64878,35 @@ aa
lF
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lI
-lH
-lH
lI
lI
lI
-lH
-lH
-lH
-lH
-lH
lI
-lK
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+OX
+GH
+OX
+OX
+lI
+lI
lK
lK
lI
lI
lK
-me
+OX
lI
lK
lI
@@ -64852,7 +64923,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -65066,38 +65136,38 @@ lF
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
lI
lI
-lH
-lH
-lH
-lH
lI
-lH
-lH
-lH
-lH
-lH
-lH
-me
-lK
-lK
-lK
-lK
-lK
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+OX
+OX
+lI
+lI
+lI
lI
lK
lK
-me
lK
-lH
+lK
+OX
+lK
+lK
+OX
+lK
lH
lH
lH
@@ -65323,37 +65393,37 @@ lF
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
lI
lI
-lH
-lH
lI
lI
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lK
lK
lK
lK
lK
lI
-lI
-lH
+OX
lH
lH
lH
@@ -65579,33 +65649,34 @@ aa
lG
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
+lI
lH
lI
lI
lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+OX
+OX
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-me
+lK
+lK
+lK
+OX
lI
lK
lK
@@ -65623,7 +65694,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -65839,30 +65909,31 @@ lH
lH
lH
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-me
-lH
lI
lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lI
+lH
+lH
+OX
+lK
+lI
+OX
lK
lI
lI
@@ -65880,7 +65951,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
@@ -66098,35 +66168,35 @@ lH
lH
lH
lH
+lI
+lI
+lI
lH
lH
+lI
+lI
+lI
+lI
lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
-lH
+lI
+lI
+lI
+lI
lH
lH
lH
lH
lI
+OX
+lK
lI
lK
-me
-lH
lK
lK
lK
lK
lK
-lH
-lH
+OX
lH
lH
lH
@@ -66355,17 +66425,18 @@ lH
lH
lH
lH
+lI
lH
lH
lH
lH
lH
+lI
lH
lH
lH
-lH
-lH
-lH
+lI
+lI
lH
lH
lH
@@ -66378,12 +66449,11 @@ lK
lI
lI
lI
-lI
-me
+OX
+OX
lI
lH
-lH
-lH
+OX
lH
lH
lH
@@ -66622,6 +66692,7 @@ lH
lH
lH
lH
+lI
lH
lH
lH
@@ -66651,7 +66722,6 @@ lH
lH
lH
lH
-lH
lF
aa
aa
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index f451a34a8b7..9e55ae1ff00 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -1,3 +1,4 @@
+
//These are all the different status effects. Use the paths for each effect in the defines.
#define STATUS_EFFECT_MULTIPLE 0 //if it allows multiple instances of the effect
@@ -6,7 +7,7 @@
#define STATUS_EFFECT_REPLACE 2 //if it allows only one, but new instances replace
-#define BASIC_STATUS_EFFECT /datum/status_effect //Has no effect.
+#define STATUS_EFFECT_REFRESH 3 // if it only allows one, and new instances just instead refresh the timer
///////////
// BUFFS //
@@ -16,6 +17,8 @@
#define STATUS_EFFECT_VOID_PRICE /datum/status_effect/void_price //The price of healing yourself with void energy. Deals 3 brute damage every 3 seconds for 30 seconds.
#define STATUS_EFFECT_EXERCISED /datum/status_effect/exercised //Prevents heart disease
+#define STATUS_EFFECT_REGENERATIVE_CORE /datum/status_effect/regenerative_core
+
//#define STATUS_EFFECT_VANGUARD /datum/status_effect/vanguard_shield //Grants temporary stun absorption, but will stun the user based on how many stuns they absorbed.
//#define STATUS_EFFECT_INATHNEQS_ENDOWMENT /datum/status_effect/inathneqs_endowment //A 15-second invulnerability and stun absorption, granted by Inath-neq.
//#define STATUS_EFFECT_WRAITHSPECS /datum/status_effect/wraith_spectacles
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 4ecfe95d24c..a6ff50e74fc 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -294,16 +294,16 @@ This is always put in the attack log.
if(!isnull(custom_level))
loglevel = custom_level
else if(istype(target))
- if(isLivingSSD(target)) // Attacks on SSDs are shown to admins with any log level except ATKLOG_NONE
- loglevel = ATKLOG_FEW
- else if(istype(user) && !user.ckey && !target.ckey) // Attacks between NPCs are only shown to admins with ATKLOG_ALL
+ if(istype(user) && !user.ckey && !target.ckey) // Attacks between NPCs are only shown to admins with ATKLOG_ALL
loglevel = ATKLOG_ALL
- else if(!user.ckey || !target.ckey) // Player v NPC combat is de-prioritized.
+ else if(!user.ckey || !target.ckey || (user.ckey == target.ckey)) // Player v NPC combat is de-prioritized. Also no self-harm, nobody cares
loglevel = ATKLOG_ALMOSTALL
else
var/area/A = get_area(target)
if(A && A.hide_attacklogs)
loglevel = ATKLOG_ALMOSTALL
+ if(isLivingSSD(target)) // Attacks on SSDs are shown to admins with any log level except ATKLOG_NONE. Overrides custom level
+ loglevel = ATKLOG_FEW
msg_admin_attack("[key_name_admin(user)] vs [key_name_admin(target)]: [what_done]", loglevel)
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index baa0adc07ec..8ae35d52179 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -242,6 +242,12 @@
// Lavaland
var/lavaland_budget = 60
+ //cube monkey limit
+ var/cubemonkeycap = 20
+
+ // Makes gamemodes respect player limits
+ var/enable_gamemode_player_limit = 0
+
/datum/configuration/New()
for(var/T in subtypesof(/datum/game_mode))
var/datum/game_mode/M = T
@@ -720,6 +726,8 @@
config.developer_express_start = 1
if("disable_localhost_admin")
config.disable_localhost_admin = 1
+ if("enable_gamemode_player_limit")
+ config.enable_gamemode_player_limit = 1
else
log_config("Unknown setting in configuration: '[name]'")
@@ -782,6 +790,8 @@
config.enable_night_shifts = TRUE
if("lavaland_budget")
config.lavaland_budget = text2num(value)
+ if("cubemonkey_cap")
+ config.cubemonkeycap = text2num(value)
else
log_config("Unknown setting in configuration: '[name]'")
diff --git a/code/controllers/subsystem/mobs.dm b/code/controllers/subsystem/mobs.dm
index 17edb6410fa..a8a1fb72ceb 100644
--- a/code/controllers/subsystem/mobs.dm
+++ b/code/controllers/subsystem/mobs.dm
@@ -7,6 +7,7 @@ SUBSYSTEM_DEF(mobs)
var/list/currentrun = list()
var/static/list/clients_by_zlevel[][]
var/static/list/dead_players_by_zlevel[][] = list(list()) // Needs to support zlevel 1 here, MaxZChanged only happens when z2 is created and new_players can login before that.
+ var/static/list/cubemonkeys = list()
/datum/controller/subsystem/mobs/stat_entry()
..("P:[GLOB.mob_list.len]")
diff --git a/code/controllers/subsystem/tickets/tickets.dm b/code/controllers/subsystem/tickets/tickets.dm
index 951a96558ca..5e42b233496 100644
--- a/code/controllers/subsystem/tickets/tickets.dm
+++ b/code/controllers/subsystem/tickets/tickets.dm
@@ -94,6 +94,8 @@ SUBSYSTEM_DEF(tickets)
//Inform the user that they have opened a ticket
to_chat(C, "You have opened [ticket_name] number #[(getTicketCounter() - 1)]! Please be patient and we will help you soon!")
+ var/ticket_open_sound = sound('sound/effects/adminticketopen.ogg')
+ SEND_SOUND(C, ticket_open_sound)
//Set ticket state with key N to open
/datum/controller/subsystem/tickets/proc/openTicket(N)
@@ -111,7 +113,47 @@ SUBSYSTEM_DEF(tickets)
message_staff("[usr.client] / ([usr]) resolved [ticket_name] number [N]")
to_chat_safe(returnClient(N), "Your [ticket_name] has now been resolved.")
return TRUE
+
+/datum/controller/subsystem/tickets/proc/autoRespond(N)
+ var/datum/ticket/T = allTickets[N]
+ var/client/C = usr.client
+ if((T.staffAssigned && T.staffAssigned != C) || (T.lastStaffResponse && T.lastStaffResponse != C) || T.ticketState != TICKET_OPEN) //if someone took this ticket, is it the same admin who is autoresponding? if so, then skip the warning
+ if(alert(usr, "[T.ticketState == TICKET_OPEN ? "This ticket is already marked as closed or resolved" : "Another admin appears to already be handling this."] Are you sure you want to continue?", "Confirmation", "Yes", "No") != "Yes")
+ return
+ T.assignStaff(C)
+
+ var/response_phrases = list("Thanks" = "Thanks, have a Paradise day!",
+ "Handling It" = "The issue is being looked into, thanks.",
+ "Already Resolved" = "The problem has been resolved already.",
+ "Mentorhelp" = "Please redirect your question to Mentorhelp, as they are better experienced with these types of questions.",
+ "Happens Again" = "Thanks, let us know if it continues to happen.",
+ "Clear Cache" = "To fix a blank screen, please leave the game and clear your Byond Cache. To clear your Byond Cache, there is a Settings icon in the top right of the launcher. After you click that, go into the Games tab and hit the Clear Cache button. If the issue persists a few minutes after rejoining and doing this, please adminhelp again and state you cleared your cache." ,
+ "IC Issue" = "This is an In Character (IC) issue and will not be handled by admins. You could speak to Security, Internal Affairs, a Departmental Head, Nanotrasen Representetive, or any other relevant authority currently on station.",
+ "Reject" = "Reject",
+ "Appeal on the Forums" = "Appealing a ban must occur on the forums. Privately messaging, or adminhelping about your ban will not resolve it. To appeal your ban, please head to [config.banappeals]"
+ )
+
+ var/sorted_responses = list()
+ for(var/key in response_phrases) //build a new list based on the short descriptive keys of the master list so we can send this as the input instead of the full paragraphs to the admin choosing which autoresponse
+ sorted_responses += key
+
+ var/message_key = input("Select an autoresponse. This will mark the ticket as resolved.", "Autoresponse") as null|anything in sortTim(sorted_responses, /proc/cmp_text_asc) //use sortTim and cmp_text_asc to sort alphabetically
+
+ switch(message_key)
+ if(null) //they cancelled
+ T.staffAssigned = initial(T.staffAssigned) //if they cancel we dont need to hold this ticket anymore
+ return
+ if("Reject")
+ if(!closeTicket(N))
+ to_chat(C, "Unable to close ticket")
+ else
+ var/msg_sound = sound('sound/effects/adminhelp.ogg')
+ SEND_SOUND(returnClient(N), msg_sound)
+ to_chat(returnClient(N), "[key_name_hidden(C)] is autoresponding with: [response_phrases[message_key]]")//for this we want the full value of whatever key this is to tell the player so we do response_phrases[message_key]
+ message_staff("[C] has auto responded to [T.clientName]\'s adminhelp with: [message_key] ") //we want to use the short named keys for this instead of the full sentence which is why we just do message_key
+ resolveTicket(N)
+ log_game("[C] has auto responded to [T.clientName]\'s adminhelp with: [response_phrases[message_key]]")
//Set ticket state with key N to closed
/datum/controller/subsystem/tickets/proc/closeTicket(N)
var/datum/ticket/T = allTickets[N]
@@ -299,7 +341,7 @@ UI STUFF
dat += "| [T.content[i]] |
"
dat += "
"
- dat += "Re-OpenResolve
"
+ dat += "Re-OpenAutoResolve
"
if(!T.staffAssigned)
dat += "No staff member assigned to this [ticket_name] - Take Ticket
"
@@ -407,6 +449,10 @@ UI STUFF
takeTicket(indexNum)
showDetailUI(usr, indexNum)
+ if(href_list["autorespond"])
+ var/indexNum = text2num(href_list["autorespond"])
+ autoRespond(indexNum)
+
if(href_list["resolveall"])
if(ticket_system_name == "Mentor Tickets")
usr.client.resolveAllMentorTickets()
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 6a2f02c2562..043117efb84 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -212,7 +212,7 @@
/datum/action/item_action/toggle_unfriendly_fire
name = "Toggle Friendly Fire \[ON\]"
- desc = "Toggles if the staff causes friendly fire."
+ desc = "Toggles if the club's blasts cause friendly fire."
button_icon_state = "vortex_ff_on"
/datum/action/item_action/toggle_unfriendly_fire/Trigger()
@@ -220,8 +220,8 @@
UpdateButtonIcon()
/datum/action/item_action/toggle_unfriendly_fire/UpdateButtonIcon()
- if(istype(target, /obj/item/hierophant_staff))
- var/obj/item/hierophant_staff/H = target
+ if(istype(target, /obj/item/hierophant_club))
+ var/obj/item/hierophant_club/H = target
if(H.friendly_fire_check)
button_icon_state = "vortex_ff_off"
name = "Toggle Friendly Fire \[OFF\]"
@@ -247,12 +247,12 @@
/datum/action/item_action/vortex_recall
name = "Vortex Recall"
- desc = "Recall yourself, and anyone nearby, to an attuned hierophant rune at any time.
If no such rune exists, will produce a rune at your location."
+ desc = "Recall yourself, and anyone nearby, to an attuned hierophant beacon at any time.
If the beacon is still attached, will detach it."
button_icon_state = "vortex_recall"
/datum/action/item_action/vortex_recall/IsAvailable()
- if(istype(target, /obj/item/hierophant_staff))
- var/obj/item/hierophant_staff/H = target
+ if(istype(target, /obj/item/hierophant_club))
+ var/obj/item/hierophant_club/H = target
if(H.teleporting)
return 0
return ..()
diff --git a/code/datums/ruins/lavaland.dm b/code/datums/ruins/lavaland.dm
index 7fe8ad7248e..bb80fe84d01 100644
--- a/code/datums/ruins/lavaland.dm
+++ b/code/datums/ruins/lavaland.dm
@@ -124,8 +124,8 @@ datum/map_template/ruin/lavaland/ash_walker
id = "hierophant"
description = "A strange, square chunk of metal of massive size. Inside awaits only death and many, many squares."
suffix = "lavaland_surface_hierophant.dmm"
- allow_duplicates = FALSE
always_place = TRUE
+ allow_duplicates = FALSE
/datum/map_template/ruin/lavaland/blood_drunk_miner
name = "Blood-Drunk Miner"
diff --git a/code/datums/status_effects/buffs.dm b/code/datums/status_effects/buffs.dm
index 25673377bee..378ee0eb676 100644
--- a/code/datums/status_effects/buffs.dm
+++ b/code/datums/status_effects/buffs.dm
@@ -55,6 +55,7 @@
. = ..()
if(.)
if(ishuman(owner))
+ owner.status_flags |= IGNORESLOWDOWN
var/mob/living/carbon/human/H = owner
for(var/X in H.bodyparts)
var/obj/item/organ/external/BP = X
@@ -65,8 +66,7 @@
H.dna.species.clone_mod *= 0.1
H.dna.species.stamina_mod *= 0.1
add_attack_logs(owner, owner, "gained blood-drunk stun immunity", ATKLOG_ALL)
- var/status = CANSTUN | CANWEAKEN | CANPARALYSE | IGNORESLOWDOWN
- owner.status_flags &= ~status
+ owner.add_stun_absorption("blooddrunk", INFINITY, 4)
owner.playsound_local(get_turf(owner), 'sound/effects/singlebeat.ogg', 40, 1)
/datum/status_effect/blooddrunk/on_remove()
@@ -81,7 +81,9 @@
H.dna.species.clone_mod *= 10
H.dna.species.stamina_mod *= 10
add_attack_logs(owner, owner, "lost blood-drunk stun immunity", ATKLOG_ALL)
- owner.status_flags |= CANSTUN | CANWEAKEN | CANPARALYSE | IGNORESLOWDOWN
+ owner.status_flags &= ~IGNORESLOWDOWN
+ if(islist(owner.stun_absorption) && owner.stun_absorption["blooddrunk"])
+ owner.stun_absorption -= "blooddrunk"
/datum/status_effect/exercised
id = "Exercised"
@@ -96,3 +98,23 @@
/datum/status_effect/exercised/Destroy()
. = ..()
STOP_PROCESSING(SSprocessing, src)
+
+/obj/screen/alert/status_effect/regenerative_core
+ name = "Reinforcing Tendrils"
+ desc = "You can move faster than your broken body could normally handle!"
+ icon_state = "regenerative_core"
+ name = "Regenerative Core Tendrils"
+
+/datum/status_effect/regenerative_core
+ id = "Regenerative Core"
+ duration = 1 MINUTES
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = /obj/screen/alert/status_effect/regenerative_core
+
+/datum/status_effect/regenerative_core/on_apply()
+ owner.status_flags |= IGNORESLOWDOWN
+ owner.revive()
+ return TRUE
+
+/datum/status_effect/regenerative_core/on_remove()
+ owner.status_flags &= ~IGNORESLOWDOWN
\ No newline at end of file
diff --git a/code/datums/status_effects/neutral.dm b/code/datums/status_effects/neutral.dm
index 8f5023e4a74..b2365ad4e1c 100644
--- a/code/datums/status_effects/neutral.dm
+++ b/code/datums/status_effects/neutral.dm
@@ -43,5 +43,5 @@
duration = 40
alert_type = null
-/datum/status_effect/high_five/on_timeout()
- owner.visible_message("[owner] was left hanging....")
+/datum/status_effect/high_five/on_remove()
+ owner.visible_message("[owner] was left hanging....")
\ No newline at end of file
diff --git a/code/datums/status_effects/status_effect.dm b/code/datums/status_effects/status_effect.dm
index dd478a8f64c..8ed41c559b5 100644
--- a/code/datums/status_effects/status_effect.dm
+++ b/code/datums/status_effects/status_effect.dm
@@ -1,4 +1,3 @@
-
//Status effects are used to apply temporary or permanent effects to mobs. Mobs are aware of their status effects at all times.
//This file contains their code, plus code for applying and removing them.
//When making a new status effect, add a define to status_effects.dm in __DEFINES for ease of use!
@@ -52,13 +51,11 @@
tick()
tick_interval = world.time + initial(tick_interval)
if(duration != -1 && duration < world.time)
- on_timeout()
qdel(src)
/datum/status_effect/proc/on_apply() //Called whenever the buff is applied; returning FALSE will cause it to autoremove itself.
return TRUE
/datum/status_effect/proc/tick() //Called every tick.
-/datum/status_effect/proc/on_timeout()//called when a buff times out
/datum/status_effect/proc/on_remove() //Called whenever the buff expires or is removed; do note that at the point this is called, it is out of the owner's status_effects but owner is not yet null
/datum/status_effect/proc/be_replaced() //Called instead of on_remove when a status effect is replaced by itself or when a status effect with on_remove_on_mob_delete = FALSE has its mob deleted
owner.clear_alert(id)
@@ -66,6 +63,19 @@
owner = null
qdel(src)
+/datum/status_effect/proc/refresh()
+ var/original_duration = initial(duration)
+ if(original_duration == -1)
+ return
+ duration = world.time + original_duration
+
+//clickdelay/nextmove modifiers!
+/datum/status_effect/proc/nextmove_modifier()
+ return 1
+
+/datum/status_effect/proc/nextmove_adjust()
+ return 0
+
////////////////
// ALERT HOOK //
////////////////
@@ -87,6 +97,9 @@
if(S.id == initial(S1.id) && S.status_type)
if(S.status_type == STATUS_EFFECT_REPLACE)
S.be_replaced()
+ else if(S.status_type == STATUS_EFFECT_REFRESH)
+ S.refresh()
+ return
else
return
var/list/arguments = args.Copy()
@@ -117,4 +130,108 @@
var/datum/status_effect/S1 = effect
for(var/datum/status_effect/S in status_effects)
if(initial(S1.id) == S.id)
- . += S
\ No newline at end of file
+ . += S
+
+//////////////////////
+// STACKING EFFECTS //
+//////////////////////
+
+/datum/status_effect/stacking
+ id = "stacking_base"
+ duration = -1 //removed under specific conditions
+ alert_type = null
+ var/stacks = 0 //how many stacks are accumulated, also is # of stacks that target will have when first applied
+ var/delay_before_decay //deciseconds until ticks start occuring, which removes stacks (first stack will be removed at this time plus tick_interval)
+ tick_interval = 10 //deciseconds between decays once decay starts
+ var/stack_decay = 1 //how many stacks are lost per tick (decay trigger)
+ var/stack_threshold //special effects trigger when stacks reach this amount
+ var/max_stacks //stacks cannot exceed this amount
+ var/consumed_on_threshold = TRUE //if status should be removed once threshold is crossed
+ var/threshold_crossed = FALSE //set to true once the threshold is crossed, false once it falls back below
+ var/overlay_file
+ var/underlay_file
+ var/overlay_state // states in .dmi must be given a name followed by a number which corresponds to a number of stacks. put the state name without the number in these state vars
+ var/underlay_state // the number is concatonated onto the string based on the number of stacks to get the correct state name
+ var/mutable_appearance/status_overlay
+ var/mutable_appearance/status_underlay
+
+/datum/status_effect/stacking/proc/threshold_cross_effect() //what happens when threshold is crossed
+
+/datum/status_effect/stacking/proc/stacks_consumed_effect() //runs if status is deleted due to threshold being crossed
+
+/datum/status_effect/stacking/proc/fadeout_effect() //runs if status is deleted due to being under one stack
+
+/datum/status_effect/stacking/proc/stack_decay_effect() //runs every time tick() causes stacks to decay
+
+/datum/status_effect/stacking/proc/on_threshold_cross()
+ threshold_cross_effect()
+ if(consumed_on_threshold)
+ stacks_consumed_effect()
+ qdel(src)
+
+/datum/status_effect/stacking/proc/on_threshold_drop()
+
+/datum/status_effect/stacking/proc/can_have_status()
+ return owner.stat != DEAD
+
+/datum/status_effect/stacking/proc/can_gain_stacks()
+ return owner.stat != DEAD
+
+/datum/status_effect/stacking/tick()
+ if(!can_have_status())
+ qdel(src)
+ else
+ add_stacks(-stack_decay)
+ stack_decay_effect()
+
+/datum/status_effect/stacking/proc/add_stacks(stacks_added)
+ if(stacks_added > 0 && !can_gain_stacks())
+ return FALSE
+ owner.cut_overlay(status_overlay)
+ owner.underlays -= status_underlay
+ stacks += stacks_added
+ if(stacks > 0)
+ if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
+ threshold_crossed = TRUE
+ on_threshold_cross()
+ else if(stacks < stack_threshold && threshold_crossed)
+ threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
+ on_threshold_drop()
+ if(stacks_added > 0)
+ tick_interval += delay_before_decay //refreshes time until decay
+ stacks = min(stacks, max_stacks)
+ status_overlay.icon_state = "[overlay_state][stacks]"
+ status_underlay.icon_state = "[underlay_state][stacks]"
+ owner.add_overlay(status_overlay)
+ owner.underlays += status_underlay
+ else
+ fadeout_effect()
+ qdel(src) //deletes status if stacks fall under one
+
+/datum/status_effect/stacking/on_creation(mob/living/new_owner, stacks_to_apply)
+ ..()
+ add_stacks(stacks_to_apply)
+
+/datum/status_effect/stacking/on_apply()
+ if(!can_have_status())
+ return FALSE
+ status_overlay = mutable_appearance(overlay_file, "[overlay_state][stacks]")
+ status_underlay = mutable_appearance(underlay_file, "[underlay_state][stacks]")
+ var/icon/I = icon(owner.icon, owner.icon_state, owner.dir)
+ var/icon_height = I.Height()
+ status_overlay.pixel_x = -owner.pixel_x
+ status_overlay.pixel_y = FLOOR(icon_height * 0.25, 1)
+ status_overlay.transform = matrix() * (icon_height/world.icon_size) //scale the status's overlay size based on the target's icon size
+ status_underlay.pixel_x = -owner.pixel_x
+ status_underlay.transform = matrix() * (icon_height/world.icon_size) * 3
+ status_underlay.alpha = 40
+ owner.add_overlay(status_overlay)
+ owner.underlays += status_underlay
+ return ..()
+
+/datum/status_effect/stacking/Destroy()
+ if(owner)
+ owner.cut_overlay(status_overlay)
+ owner.underlays -= status_underlay
+ QDEL_NULL(status_overlay)
+ return ..()
\ No newline at end of file
diff --git a/code/datums/supplypacks.dm b/code/datums/supplypacks.dm
index 0f349ab1f12..f64a00968d6 100644
--- a/code/datums/supplypacks.dm
+++ b/code/datums/supplypacks.dm
@@ -508,6 +508,25 @@ var/list/all_supply_groups = list(supply_emergency,supply_security,supply_engine
cost = 30
containername = "security clothing crate"
+/datum/supply_packs/security/officerpack // Starter pack for an officer. Contains everything in a locker but backpack (officer already start with one). Convenient way to equip new officer on highpop.
+ name = "Officer Starter Pack"
+ contains = list(/obj/item/clothing/suit/armor/vest/security,
+ /obj/item/radio/headset/headset_sec/alt,
+ /obj/item/clothing/head/soft/sec,
+ /obj/item/reagent_containers/spray/pepper,
+ /obj/item/flash,
+ /obj/item/grenade/flashbang,
+ /obj/item/storage/belt/security/sec,
+ /obj/item/holosign_creator/security,
+ /obj/item/clothing/mask/gas/sechailer,
+ /obj/item/clothing/glasses/hud/security/sunglasses,
+ /obj/item/clothing/head/helmet,
+ /obj/item/melee/baton/loaded,
+ /obj/item/clothing/suit/armor/secjacket)
+ cost = 30 // Convenience has a price and this pack is genuinely loaded
+ containername = "officer starter crate"
+
+
//////////////////////////////////////////////////////////////////////////////
//////////////////////////// Engineering /////////////////////////////////////
diff --git a/code/datums/uplink_item.dm b/code/datums/uplink_item.dm
index a62155eb10d..00dd2d813ad 100644
--- a/code/datums/uplink_item.dm
+++ b/code/datums/uplink_item.dm
@@ -1459,7 +1459,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
/datum/uplink_item/device_tools/shield
name = "Energy Shield"
- desc = "An incredibly useful personal shield projector, capable of reflecting energy projectiles and defending against other attacks."
+ desc = "An incredibly useful personal shield projector, capable of reflecting energy projectiles, but it cannot block other attacks. Pair with an Energy Sword for a killer combination."
item = /obj/item/shield/energy
reference = "ESD"
cost = 16
@@ -1758,4 +1758,4 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item))
reference = "RTCB"
item = /obj/item/stack/telecrystal/fifty
cost = 50
- gamemodes = list(/datum/game_mode/nuclear)
\ No newline at end of file
+ gamemodes = list(/datum/game_mode/nuclear)
diff --git a/code/game/area/areas/depot-areas.dm b/code/game/area/areas/depot-areas.dm
index d7d6499f659..86940fcb412 100644
--- a/code/game/area/areas/depot-areas.dm
+++ b/code/game/area/areas/depot-areas.dm
@@ -32,6 +32,7 @@
var/detected_pod = FALSE
var/detected_double_agent = FALSE
var/mine_trigger_count = 0
+ var/perimeter_shield_status = FALSE
var/obj/machinery/computer/syndicate_depot/syndiecomms/comms_computer = null
var/obj/structure/fusionreactor/reactor
@@ -114,9 +115,13 @@
updateicon()
/area/syndicate_depot/core/proc/locker_looted()
- something_looted = TRUE
- if(on_peaceful)
- increase_alert("Thieves!")
+ if(!something_looted)
+ something_looted = TRUE
+ if(on_peaceful)
+ increase_alert("Thieves!")
+ if(perimeter_shield_status)
+ increase_alert("Perimeter shield breach!")
+
/area/syndicate_depot/core/proc/armory_locker_looted()
if(!run_finished && !used_self_destruct)
@@ -146,7 +151,8 @@
if(detected_pod)
return
detected_pod = TRUE
- increase_alert("Hostile spacepod detected: [P]")
+ if(!called_backup)
+ increase_alert("Hostile spacepod detected: [P]")
/area/syndicate_depot/core/proc/saw_double_agent(mob/living/M)
if(detected_double_agent)
@@ -170,9 +176,6 @@
L.locked = !L.locked
L.req_access = list(access_syndicate_leader)
L.update_icon()
- for(var/obj/machinery/computer/syndicate_depot/teleporter/P in src)
- if(!P.portal_enabled)
- P.toggle_portal()
else
log_game("Depot visit: ended")
alert_log += "Visitor mode ended."
@@ -317,7 +320,7 @@
A.update_icon()
/area/syndicate_depot/core/proc/toggle_falsewalls()
- for(var/obj/structure/falsewall/reinforced/F in src)
+ for(var/obj/structure/falsewall/plastitanium/F in src)
spawn(0)
F.toggle()
diff --git a/code/game/gamemodes/blob/blob.dm b/code/game/gamemodes/blob/blob.dm
index df61106c4ab..33b68f94079 100644
--- a/code/game/gamemodes/blob/blob.dm
+++ b/code/game/gamemodes/blob/blob.dm
@@ -104,6 +104,7 @@ var/list/blob_nodes = list()
to_chat(blob.current, "Find a good location to spawn the core and then take control and overwhelm the station!")
to_chat(blob.current, "When you have found a location, wait until you spawn; this will happen automatically and you cannot speed up the process.")
to_chat(blob.current, "If you go outside of the station level, or in space, then you will die; make sure your location has lots of ground to cover.")
+ SEND_SOUND(blob.current, 'sound/magic/mutate.ogg')
return
/datum/game_mode/blob/proc/show_message(var/message)
@@ -207,4 +208,4 @@ var/list/blob_nodes = list()
/datum/game_mode/proc/update_blob_icons_removed(datum/mind/mob_mind)
var/datum/atom_hud/antag/antaghud = huds[ANTAG_HUD_BLOB]
antaghud.leave_hud(mob_mind.current)
- set_antag_hud(mob_mind.current, null)
\ No newline at end of file
+ set_antag_hud(mob_mind.current, null)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index aa366415f31..e7fb9b4969f 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -50,7 +50,7 @@
if((player.client)&&(player.ready))
playerC++
- if(playerC >= required_players)
+ if(!config.enable_gamemode_player_limit || (playerC >= required_players))
return 1
return 0
diff --git a/code/game/gamemodes/miniantags/guardian/types/assassin.dm b/code/game/gamemodes/miniantags/guardian/types/assassin.dm
index e9ea9239483..4b17e597aa5 100644
--- a/code/game/gamemodes/miniantags/guardian/types/assassin.dm
+++ b/code/game/gamemodes/miniantags/guardian/types/assassin.dm
@@ -2,7 +2,6 @@
melee_damage_lower = 15
melee_damage_upper = 15
armour_penetration = 0
- damage_transfer = 0.6
playstyle_string = "As an Assassin type you do medium damage and have no damage resistance, but can enter stealth, massively increasing the damage of your next attack and causing it to ignore armor. Stealth is broken when you attack or take damage."
magic_fluff_string = "..And draw the Space Ninja, a lethal, invisible assassin."
tech_fluff_string = "Boot sequence complete. Assassin modules loaded. Holoparasite swarm online."
diff --git a/code/game/machinery/computer/depot.dm b/code/game/machinery/computer/depot.dm
index 149e2b7ff49..02be740b7d3 100644
--- a/code/game/machinery/computer/depot.dm
+++ b/code/game/machinery/computer/depot.dm
@@ -196,6 +196,7 @@
if(istype(perimeterarea) && (GAMEMODE_IS_NUCLEAR || prob(20)))
spawn(200)
perimeterarea.perimeter_shields_up()
+ depotarea.perimeter_shield_status = TRUE
/obj/machinery/computer/syndicate_depot/shieldcontrol/Destroy()
if(istype(perimeterarea) && perimeterarea.shield_list.len)
@@ -219,8 +220,10 @@
return
if(perimeterarea.shield_list.len)
perimeterarea.perimeter_shields_down()
+ depotarea.perimeter_shield_status = FALSE
else
perimeterarea.perimeter_shields_up()
+ depotarea.perimeter_shield_status = TRUE
playsound(user, sound_yes, 50, 0)
@@ -282,17 +285,13 @@
to_chat(user, "[src] has already been used to transmit a message to the Syndicate.")
return
message_sent = TRUE
- if(user.mind && user.mind.special_role == SPECIAL_ROLE_TRAITOR)
- var/input = stripped_input(user, "Please choose a message to transmit to Syndicate HQ via quantum entanglement. Transmission does not guarantee a response. This function may only be used ONCE.", "To abort, send an empty message.", "")
- if(!input)
- message_sent = FALSE
- return
- Syndicate_announce(input, user)
- to_chat(user, "Message transmitted.")
- log_say("[key_name(user)] has sent a Syndicate comms message from the depot: [input]", user)
- else
- to_chat(user, "[src] requires authentication with syndicate codewords, which you do not know.")
- raise_alert("Detected unauthorized access by [user] to [src]!")
+ var/input = stripped_input(user, "Please choose a message to transmit to Syndicate HQ via quantum entanglement. Transmission does not guarantee a response. This function may only be used ONCE.", "To abort, send an empty message.", "")
+ if(!input)
+ message_sent = FALSE
+ return
+ Syndicate_announce(input, user)
+ to_chat(user, "Message transmitted.")
+ log_say("[key_name(user)] has sent a Syndicate comms message from the depot: [input]", user)
updateUsrDialog()
playsound(user, sound_yes, 50, 0)
@@ -318,7 +317,9 @@
to_chat(user, "Only verified agents of the Syndicate may sign in as visitors. Everyone else will be shot on sight.")
else if(subcommand == DEPOT_VISITOR_START)
if(depotarea.something_looted)
- to_chat(user, "Visitor sign-in is not possible after supplies have been taken from the depot.")
+ to_chat(user, "Visitor sign-in is not possible after supplies have been taken from a locker in the depot.")
+ else if("syndicate" in user.faction)
+ to_chat(user, "You are already recognized as a member of the Syndicate, and do not need to sign in.")
else if(user.mind && user.mind.special_role == SPECIAL_ROLE_TRAITOR)
grant_syndie_faction(user)
depotarea.peaceful_mode(TRUE, TRUE)
@@ -359,6 +360,7 @@
icon_keyboard = "teleport_key"
var/obj/machinery/bluespace_beacon/syndicate/mybeacon
var/obj/effect/portal/redspace/myportal
+ var/obj/effect/portal/redspace/myportal2
var/portal_enabled = FALSE
var/portaldir = WEST
@@ -394,18 +396,6 @@
return FALSE
/obj/machinery/computer/syndicate_depot/teleporter/proc/choosetarget()
- var/list/eligible_turfs = list()
- for(var/obj/item/radio/beacon/R in GLOB.beacons)
- var/turf/T = get_turf(R)
- if(!is_station_level(T.z))
- continue
- eligible_turfs += T
- if(eligible_turfs.len)
- return pick(eligible_turfs)
- else
- return FALSE
-
-/obj/machinery/computer/syndicate_depot/teleporter/targeted/choosetarget()
var/list/L = list()
var/list/areaindex = list()
@@ -434,9 +424,15 @@
myportal = P
var/area/A = get_area(tele_target)
P.name = "[A] portal"
+ var/obj/effect/portal/redspace/P2 = new(get_turf(tele_target), portal_turf, src, 0)
+ myportal2 = P2
+ P2.name = "mysterious portal"
else if(!portal_enabled && myportal)
qdel(myportal)
myportal = null
+ if(myportal2)
+ qdel(myportal2)
+ myportal2 = null
/obj/machinery/computer/syndicate_depot/teleporter/get_menu(mob/user)
var/menutext = "Syndicate Teleporter Control
"
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index eb536953b45..0e773e0ea95 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -71,9 +71,23 @@
playsound(C.loc, "sound/goonstation/machines/printer_dotmatrix.ogg", 50, 1)
GLOB.cell_logs += P
+ var/datum/data/record/G = find_record("name", logname, data_core.general)
+ var/prisoner_drank = "unknown"
+ var/prisoner_trank = "unknown"
+ if(G)
+ if(G.fields["rank"])
+ prisoner_drank = G.fields["rank"]
+ if(G.fields["real_rank"]) // Ignore alt job titles - necessary for lookups
+ prisoner_trank = G.fields["real_rank"]
+
var/datum/data/record/R = find_security_record("name", logname)
- Radio.autosay("Detainee [logname] has been incarcerated for [seconds_to_time(timetoset / 10)] for the charges of, '[logcharges]'. \
- Arresting Officer: [usr.name].[R ? "" : " Detainee record not found, manual record update required."]", name, "Security", list(z))
+
+ var/announcetext = "Detainee [logname] ([prisoner_drank]) has been incarcerated for [seconds_to_time(timetoset / 10)] for the charges of, '[logcharges]'. \
+ Arresting Officer: [usr.name].[R ? "" : " Detainee record not found, manual record update required."]"
+ Radio.autosay(announcetext, name, "Security", list(z))
+
+ if(prisoner_trank != "unknown")
+ notify_dept_head(prisoner_trank, announcetext)
if(R)
prisoner = R
@@ -87,9 +101,33 @@
R.fields["comments"] = list()
R.fields["comments"] += "Autogenerated by [name] on [current_date_string] [station_time_timestamp()]
Sentenced to [timetoset/10] seconds for the charges of \"[logcharges]\" by [rank] [usr.name]."
update_all_mob_security_hud()
-
return 1
+
+/obj/machinery/door_timer/proc/notify_dept_head(jobtitle, antext)
+ if(!jobtitle || !antext)
+ return
+ if(jobtitle == "Civilian")
+ // Don't notify the HoP about greytiding civilians
+ return
+ var/datum/job/brigged_job = SSjobs.GetJob(jobtitle)
+ if(!brigged_job)
+ return
+ if(!brigged_job.department_head[1])
+ return
+ var/boss_title = brigged_job.department_head[1]
+
+ var/obj/item/pda/target_pda
+ for(var/obj/item/pda/check_pda in PDAs)
+ if(check_pda.ownrank == boss_title)
+ target_pda = check_pda
+ if(!target_pda)
+ return
+ var/datum/data/pda/app/messenger/PM = target_pda.find_program(/datum/data/pda/app/messenger)
+ if(PM && PM.can_receive())
+ PM.notify("Message from Brig Timer (Automated), \"[antext]\" (Unable to Reply)")
+
+
/obj/machinery/door_timer/Initialize()
..()
diff --git a/code/game/machinery/poolcontroller.dm b/code/game/machinery/poolcontroller.dm
index 0d6f76aad38..4b512297ffd 100644
--- a/code/game/machinery/poolcontroller.dm
+++ b/code/game/machinery/poolcontroller.dm
@@ -116,7 +116,7 @@
if(!drownee)
return
- if(drownee && (drownee.lying || deep_water)) //Mob lying down or water is deep (determined by controller)
+ if(drownee && ((drownee.lying && !drownee.player_logged) || deep_water)) //Mob lying down and not SSD or water is deep (determined by controller)
if(drownee.internal)
return //Has internals, no drowning
if((NO_BREATHE in drownee.dna.species.species_traits) || (BREATHLESS in drownee.mutations))
diff --git a/code/game/mecha/equipment/tools/medical_tools.dm b/code/game/mecha/equipment/tools/medical_tools.dm
index 2d0e6e69e26..df2c284e9fb 100644
--- a/code/game/mecha/equipment/tools/medical_tools.dm
+++ b/code/game/mecha/equipment/tools/medical_tools.dm
@@ -197,7 +197,7 @@
if(to_inject && patient.reagents.get_reagent_amount(R.id) + to_inject <= inject_amount*2)
occupant_message("Injecting [patient] with [to_inject] units of [R.name].")
log_message("Injecting [patient] with [to_inject] units of [R.name].")
- add_attack_logs(chassis.occupant, patient, "Injected with [name] containing [R], transferred [to_inject] units")
+ add_attack_logs(chassis.occupant, patient, "Injected with [name] containing [R], transferred [to_inject] units", R.harmless ? ATKLOG_ALMOSTALL : null)
SG.reagents.trans_id_to(patient,R.id,to_inject)
update_equip_info()
return
diff --git a/code/game/objects/effects/spawners/random_spawners.dm b/code/game/objects/effects/spawners/random_spawners.dm
index 03e49c56a50..d2324b5dd93 100644
--- a/code/game/objects/effects/spawners/random_spawners.dm
+++ b/code/game/objects/effects/spawners/random_spawners.dm
@@ -186,7 +186,7 @@
name = "common loot"
icon_state = "x3"
spawn_inside = /obj/structure/closet/secure_closet/syndicate/depot
- // Loot schema: costumes, toys, useless gimmick items, trapped items
+ // Loot schema: costumes, toys, useless gimmick items
result = list(/datum/nothing = 13,
/obj/item/storage/toolbox/syndicate = 1,
/obj/item/storage/fancy/cigarettes/cigpack_syndicate = 1,
@@ -201,6 +201,16 @@
/obj/item/coin/antagtoken/syndicate = 1,
/obj/item/storage/box/syndie_kit/cutouts = 1)
+/obj/effect/spawner/random_spawners/syndicate/loot/stetchkin
+ name = "20pc stetchkin"
+ icon_state = "x3"
+ spawn_inside = null
+ result = list(/datum/nothing = 1,
+ /obj/item/wrench = 1,
+ /obj/item/reagent_containers/food/snacks/syndicake = 1,
+ /obj/item/coin/antagtoken/syndicate = 1,
+ /obj/item/gun/projectile/automatic/pistol = 1)
+
/obj/effect/spawner/random_spawners/syndicate/loot/level2
name = "rare loot"
// Loot schema: space gear, basic armor, basic ammo (10mm, rcd), drugs, more dangerous/useful gimmick items, lower-value minerals
@@ -291,18 +301,18 @@
/obj/effect/spawner/random_spawners/syndicate/layout/door
name = "50pc door 25pc falsewall 25pc wall"
result = list(/obj/machinery/door/airlock/hatch/syndicate = 6,
- /turf/simulated/wall/r_wall = 2,
- /obj/structure/falsewall/reinforced = 2)
+ /turf/simulated/wall/mineral/plastitanium/nodiagonal = 2,
+ /obj/structure/falsewall/plastitanium = 2)
/obj/effect/spawner/random_spawners/syndicate/layout/door/secret
name = "50pc falsewall 50pc wall"
- result = list(/turf/simulated/wall/r_wall = 1,
- /obj/structure/falsewall/reinforced = 1)
+ result = list(/turf/simulated/wall/mineral/plastitanium/nodiagonal = 1,
+ /obj/structure/falsewall/plastitanium = 1)
/obj/effect/spawner/random_spawners/syndicate/layout/door/vault
name = "80pc vaultdoor 20pc wall"
result = list(/obj/machinery/door/airlock/hatch/syndicate/vault = 4,
- /turf/simulated/wall/r_wall = 1)
+ /turf/simulated/wall/mineral/plastitanium/nodiagonal = 1)
/obj/effect/spawner/random_spawners/syndicate/layout/spacepod
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 94731757895..f331ff72f94 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -238,6 +238,7 @@
return 0
/obj/item/lightreplacer/afterattack(atom/T, mob/U, proximity)
+ . = ..()
if(!proximity)
return
if(!isturf(T))
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 63e7eeb88fb..7388cff9e5b 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -58,7 +58,7 @@
/obj/item/shield/energy
name = "energy combat shield"
- desc = "A shield capable of stopping most melee attacks. Protects user from almost all energy projectiles. It can be retracted, expanded, and stored anywhere."
+ desc = "A shield that reflects almost all energy projectiles, but is useless against physical attacks. It can be retracted, expanded, and stored anywhere."
icon_state = "eshield0" // eshield1 for expanded
force = 3
throwforce = 3
diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm
index ed5c43b5a67..ef3a900ad3d 100644
--- a/code/game/objects/structures/false_walls.dm
+++ b/code/game/objects/structures/false_walls.dm
@@ -326,7 +326,7 @@
mineral = /obj/item/stack/sheet/mineral/plastitanium
walltype = /turf/simulated/wall/mineral/plastitanium
smooth = SMOOTH_MORE
- canSmoothWith = list(/turf/simulated/wall/mineral/plastitanium, /obj/machinery/door/airlock/shuttle, /obj/machinery/door/airlock, /obj/structure/window/full/shuttle, /obj/structure/shuttle/engine/heater)
+ canSmoothWith = list(/turf/simulated/wall/mineral/plastitanium, /turf/simulated/wall/mineral/plastitanium/nodiagonal, /obj/machinery/door/airlock/shuttle, /obj/machinery/door/airlock, /obj/structure/window/full/shuttle, /obj/structure/shuttle/engine/heater)
/obj/structure/falsewall/brass
name = "clockwork wall"
@@ -345,4 +345,3 @@
var/turf/T = get_turf(src)
new /obj/effect/temp_visual/ratvar/wall/false(T)
new /obj/effect/temp_visual/ratvar/beam/falsewall(T)
-
diff --git a/code/game/turfs/simulated/floor/indestructible.dm b/code/game/turfs/simulated/floor/indestructible.dm
index 3217a4c7996..adb41ac335e 100644
--- a/code/game/turfs/simulated/floor/indestructible.dm
+++ b/code/game/turfs/simulated/floor/indestructible.dm
@@ -74,15 +74,16 @@
temperature = T20C
/turf/simulated/floor/indestructible/hierophant
- icon_state = "hierophant1"
+ name = "floor"
+ icon = 'icons/turf/floors/hierophant_floor.dmi'
+ icon_state = "floor"
oxygen = 14
nitrogen = 23
temperature = 300
planetary_atmos = TRUE
- desc = "A floor with a square pattern. It's faintly cool to the touch."
+ smooth = SMOOTH_TRUE
/turf/simulated/floor/indestructible/hierophant/get_smooth_underlay_icon(mutable_appearance/underlay_appearance, turf/asking_turf, adjacency_dir)
return FALSE
-/turf/simulated/floor/indestructible/hierophant/two
- icon_state = "hierophant2"
+/turf/simulated/floor/indestructible/hierophant/two
\ No newline at end of file
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index 188136057da..dd7f501aaa4 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -345,7 +345,7 @@
if(do_after(user, max(5, damage / 5) * WT.toolspeed, target = src) && WT && WT.isOn())
to_chat(user, "You finish repairing the damage to [src].")
cut_overlay(dent_decals)
- dent_decals.Cut()
+ dent_decals?.Cut()
take_damage(-damage)
else
to_chat(user, "You begin slicing through the outer plating.")
diff --git a/code/game/turfs/simulated/walls_indestructible.dm b/code/game/turfs/simulated/walls_indestructible.dm
index e25992a2555..8850fbf24fa 100644
--- a/code/game/turfs/simulated/walls_indestructible.dm
+++ b/code/game/turfs/simulated/walls_indestructible.dm
@@ -29,17 +29,17 @@
return
/turf/simulated/wall/indestructible/attackby(obj/item/I, mob/user, params)
- return
+ return
/turf/simulated/wall/indestructible/attack_hand(mob/user)
- return
+ return
/turf/simulated/wall/indestructible/attack_hulk(mob/user, does_attack_animation = FALSE)
return
/turf/simulated/wall/indestructible/attack_animal(mob/living/simple_animal/M)
return
-
+
/turf/simulated/wall/indestructible/mech_melee_attack(obj/mecha/M)
return
@@ -66,9 +66,9 @@
/turf/simulated/wall/indestructible/hierophant
name = "wall"
- desc = "A wall made out of smooth, cold stone."
+ desc = "A wall made out of a strange metal. The squares on it pulse in a predictable pattern."
icon = 'icons/turf/walls/hierophant_wall.dmi'
- icon_state = "hierophant"
+ icon_state = "wall"
smooth = SMOOTH_TRUE
/turf/simulated/wall/indestructible/uranium
diff --git a/code/game/turfs/simulated/walls_reinforced.dm b/code/game/turfs/simulated/walls_reinforced.dm
index 45abe2e155c..1ae3332e9b3 100644
--- a/code/game/turfs/simulated/walls_reinforced.dm
+++ b/code/game/turfs/simulated/walls_reinforced.dm
@@ -40,7 +40,7 @@
return ..()
/turf/simulated/wall/r_wall/proc/try_repair(obj/item/I, mob/user, params)
- if(damage && iswelder(I))
+ if((damage || LAZYLEN(dent_decals)) && iswelder(I))
var/obj/item/weldingtool/WT = I
if(!WT.remove_fuel(0, user))
to_chat(user, "You need more welding fuel to complete this task.")
@@ -50,6 +50,8 @@
playsound(src, WT.usesound, 100, 1)
if(do_after(user, max(5, damage / 5) * WT.toolspeed, target = src) && WT && WT.isOn())
to_chat(user, "You finish repairing the damage to [src].")
+ cut_overlay(dent_decals)
+ dent_decals?.Cut()
take_damage(-damage)
return TRUE
diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm
index af2d728c467..a3d39396c06 100644
--- a/code/modules/admin/topic.dm
+++ b/code/modules/admin/topic.dm
@@ -1569,6 +1569,12 @@
else //Ahelp
SStickets.resolveTicket(index)
+ else if(href_list["autorespond"])
+ var/index = text2num(href_list["autorespond"])
+ if(!check_rights(R_ADMIN|R_MOD))
+ return
+ SStickets.autoRespond(index)
+
else if(href_list["cult_nextobj"])
if(alert(usr, "Validate the current Cult objective and unlock the next one?", "Cult Cheat Code", "Yes", "No") != "Yes")
return
diff --git a/code/modules/admin/verbs/adminhelp.dm b/code/modules/admin/verbs/adminhelp.dm
index b64b8cd56f5..e7c21adda20 100644
--- a/code/modules/admin/verbs/adminhelp.dm
+++ b/code/modules/admin/verbs/adminhelp.dm
@@ -125,7 +125,7 @@ var/list/adminhelp_ignored_words = list("unknown","the","a","an","of","monkey","
ticketNum = T.ticketNum // ticketNum is the number of their ticket.
T.addResponse(src, msg)
- msg = "[span][selected_type]: [key_name(src, TRUE, selected_type)] ([ADMIN_QUE(mob,"?")]) ([ADMIN_PP(mob,"PP")]) ([ADMIN_VV(mob,"VV")]) ([ADMIN_TP(mob,"TP")]) ([ADMIN_SM(mob,"SM")]) ([admin_jump_link(mob)]) (TICKET) [ai_found ? "(CL)" : ""] (TAKE) (RESOLVE) : [span][msg]"
+ msg = "[span][selected_type]: [key_name(src, TRUE, selected_type)] ([ADMIN_QUE(mob,"?")]) ([ADMIN_PP(mob,"PP")]) ([ADMIN_VV(mob,"VV")]) ([ADMIN_TP(mob,"TP")]) ([ADMIN_SM(mob,"SM")]) ([admin_jump_link(mob)]) (TICKET) [ai_found ? "(CL)" : ""] (TAKE) (RESOLVE) [isMhelp ? "" : "(AUTO)"] : [span][msg]"
if(isMhelp)
//Open a new adminticket and inform the user.
SSmentor_tickets.newTicket(src, prunedmsg, msg)
diff --git a/code/modules/admin/verbs/playsound.dm b/code/modules/admin/verbs/playsound.dm
index c7d654dbe68..995673e7d20 100644
--- a/code/modules/admin/verbs/playsound.dm
+++ b/code/modules/admin/verbs/playsound.dm
@@ -28,9 +28,12 @@ var/list/sounds_cache = list()
log_admin("[key_name(src)] played sound [S]")
message_admins("[key_name_admin(src)] played sound [S]", 1)
+
for(var/mob/M in GLOB.player_list)
if(M.client.prefs.sound & SOUND_MIDI)
- M << uploaded_sound
+ if(isnewplayer(M) && (M.client.prefs.sound & SOUND_LOBBY))
+ M.stop_sound_channel(CHANNEL_LOBBYMUSIC)
+ SEND_SOUND(M, uploaded_sound)
feedback_add_details("admin_verb","PGS") //If you are copy-pasting this, ensure the 2nd parameter is unique to the new proc!
diff --git a/code/modules/awaymissions/zlevel.dm b/code/modules/awaymissions/zlevel.dm
index 920f91a7ed0..c406a76cb73 100644
--- a/code/modules/awaymissions/zlevel.dm
+++ b/code/modules/awaymissions/zlevel.dm
@@ -156,11 +156,13 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
for(var/i in get_affected_turfs(central_turf, 1))
var/turf/T = i
+ for(var/obj/structure/spawner/nest in T)
+ qdel(nest)
for(var/mob/living/simple_animal/monster in T)
qdel(monster)
for(var/obj/structure/flora/ash/plant in T)
qdel(plant)
-
+
load(central_turf,centered = TRUE)
loaded++
@@ -229,7 +231,7 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
//TODO : handle forced ruins with multiple variants
forced_ruins -= current_pick
forced = FALSE
-
+
if(failed_to_place)
for(var/datum/map_template/ruin/R in ruins_availible)
if(R.id == current_pick.id)
@@ -252,5 +254,5 @@ var/global/list/potentialRandomZlevels = generateMapList(filename = "config/away
for(var/datum/map_template/ruin/R in ruins_availible)
if(R.cost > budget)
ruins_availible -= R
-
+
log_world("Ruin loader finished with [budget] left to spend.")
diff --git a/code/modules/clothing/spacesuits/hardsuit.dm b/code/modules/clothing/spacesuits/hardsuit.dm
index f1cd49e65ec..d1554f84866 100644
--- a/code/modules/clothing/spacesuits/hardsuit.dm
+++ b/code/modules/clothing/spacesuits/hardsuit.dm
@@ -205,7 +205,7 @@
name = "atmospherics hardsuit"
desc = "A special suit that protects against hazardous, low pressure environments. Has thermal shielding."
icon_state = "hardsuit-atmos"
- item_state = "atmo_hardsuit"
+ item_state = "atmos_hardsuit"
armor = list("melee" = 30, "bullet" = 5, "laser" = 10, "energy" = 5, "bomb" = 10, "bio" = 100, "rad" = 25, "fire" = 100, "acid" = 75)
heat_protection = UPPER_TORSO|LOWER_TORSO|LEGS|FEET|ARMS|HANDS //Uncomment to enable firesuit protection
max_heat_protection_temperature = FIRE_IMMUNITY_MAX_TEMP_PROTECT
diff --git a/code/modules/customitems/item_defines.dm b/code/modules/customitems/item_defines.dm
index edd0165d213..3a0bdb8d795 100644
--- a/code/modules/customitems/item_defines.dm
+++ b/code/modules/customitems/item_defines.dm
@@ -272,12 +272,14 @@
new /obj/item/reagent_containers/food/drinks/cans/cola(src)
-/obj/item/instrument/guitar/jello_guitar //Antcolon3: Dan Jello
+/obj/item/instrument/guitar/jello_guitar //Pineapple Salad: Dan Jello
name = "Dan Jello's Pink Guitar"
desc = "Dan Jello's special pink guitar."
icon = 'icons/obj/custom_items.dmi'
icon_state = "jello_guitar"
item_state = "jello_guitar"
+ righthand_file = 'icons/mob/inhands/fluff_righthand.dmi'
+ lefthand_file = 'icons/mob/inhands/fluff_lefthand.dmi'
/obj/item/fluff/wingler_comb
name = "blue comb"
diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm
index b177d7a7aaf..87b9d6733ac 100644
--- a/code/modules/flufftext/Hallucination.dm
+++ b/code/modules/flufftext/Hallucination.dm
@@ -217,7 +217,7 @@ Gunshots/explosions/opening doors/less rare audio (done)
qdel(src)
/obj/effect/hallucination/simple/clown
- image_icon = 'icons/mob/animal.dmi'
+ image_icon = 'icons/mob/simple_human.dmi'
image_state = "clown"
/obj/effect/hallucination/simple/clown/New(loc, mob/living/carbon/T, duration)
diff --git a/code/modules/food_and_drinks/food/condiment.dm b/code/modules/food_and_drinks/food/condiment.dm
index d512e3888a9..51acd9be5e8 100644
--- a/code/modules/food_and_drinks/food/condiment.dm
+++ b/code/modules/food_and_drinks/food/condiment.dm
@@ -44,7 +44,7 @@
if(!reagents || !reagents.total_volume)
return // The condiment might be empty after the delay.
user.visible_message("[user] feeds [M] from [src].")
- add_attack_logs(user, M, "Fed [src] containing [reagents.log_list()]")
+ add_attack_logs(user, M, "Fed [src] containing [reagents.log_list()]", reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
var/fraction = min(10/reagents.total_volume, 1)
reagents.reaction(M, INGEST, fraction)
diff --git a/code/modules/food_and_drinks/food/foods/meat.dm b/code/modules/food_and_drinks/food/foods/meat.dm
index 38fdaf59a68..d74fdef6ecc 100644
--- a/code/modules/food_and_drinks/food/foods/meat.dm
+++ b/code/modules/food_and_drinks/food/foods/meat.dm
@@ -271,6 +271,12 @@
return 1
/obj/item/reagent_containers/food/snacks/monkeycube/proc/Expand()
+ if(LAZYLEN(SSmobs.cubemonkeys) >= config.cubemonkeycap)
+ if(fingerprintslast)
+ to_chat(get_mob_by_ckey(fingerprintslast), "Bluespace harmonics prevent the spawning of more than [config.cubemonkeycap] monkeys on the station at one time!")
+ else
+ visible_message("[src] fails to expand!")
+ return
if(!QDELETED(src))
visible_message("[src] expands!")
if(fingerprintslast)
@@ -283,6 +289,7 @@
if(LAZYLEN(fingerprintshidden))
creature.fingerprintshidden = fingerprintshidden.Copy()
creature.set_species(monkey_type)
+ SSmobs.cubemonkeys += creature
qdel(src)
/obj/item/reagent_containers/food/snacks/monkeycube/syndicate
diff --git a/code/modules/mining/equipment/regenerative_core.dm b/code/modules/mining/equipment/regenerative_core.dm
index 9d56d8ccd6e..4b5e5c911da 100644
--- a/code/modules/mining/equipment/regenerative_core.dm
+++ b/code/modules/mining/equipment/regenerative_core.dm
@@ -84,7 +84,7 @@
else
to_chat(user, "You start to smear [src] on yourself. Disgusting tendrils hold you together and allow you to keep moving, but for how long?")
feedback_add_details("hivelord_core","[src.type]|used|self")
- H.revive()
+ H.apply_status_effect(STATUS_EFFECT_REGENERATIVE_CORE)
user.drop_item()
qdel(src)
diff --git a/code/modules/mining/equipment/survival_pod.dm b/code/modules/mining/equipment/survival_pod.dm
index 9c76ed8e73f..68a7270477c 100644
--- a/code/modules/mining/equipment/survival_pod.dm
+++ b/code/modules/mining/equipment/survival_pod.dm
@@ -338,7 +338,7 @@
/obj/item/shield/changeling,
/obj/item/lava_staff,
/obj/item/katana/energy,
- /obj/item/hierophant_staff,
+ /obj/item/hierophant_club,
/obj/item/storage/toolbox/green/memetic,
/obj/item/gun/projectile/automatic/l6_saw,
/obj/item/gun/magic/staff/chaos,
diff --git a/code/modules/mining/lavaland/loot/hierophant_loot.dm b/code/modules/mining/lavaland/loot/hierophant_loot.dm
index 23e894746d2..d7f47baed1d 100644
--- a/code/modules/mining/lavaland/loot/hierophant_loot.dm
+++ b/code/modules/mining/lavaland/loot/hierophant_loot.dm
@@ -1,115 +1,190 @@
-/obj/item/hierophant_staff
- name = "Hierophant's staff"
- desc = "A large club with intense magic power infused into it."
- icon_state = "hierophant_staff"
- item_state = "hierophant_staff"
- icon = 'icons/obj/guns/magic.dmi'
+#define HIEROPHANT_CLUB_CARDINAL_DAMAGE 30
+
+/obj/item/hierophant_club
+ name = "hierophant club"
+ desc = "The strange technology of this large club allows various nigh-magical feats. It used to beat you, but now you can set the beat."
+ icon_state = "hierophant_club_ready_beacon"
+ item_state = "hierophant_club_ready_beacon"
+ icon = 'icons/obj/lavaland/artefacts.dmi'
+ lefthand_file = 'icons/mob/inhands/64x64_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/64x64_righthand.dmi'
+ inhand_x_dimension = 64
+ inhand_y_dimension = 64
slot_flags = SLOT_BACK
w_class = WEIGHT_CLASS_BULKY
- force = 20
- hitsound = "swing_hit"
- //hitsound = 'sound/weapons/sonic_jackhammer.ogg'
+ force = 15
+ attack_verb = list("clubbed", "beat", "pummeled")
+ hitsound = 'sound/weapons/sonic_jackhammer.ogg'
actions_types = list(/datum/action/item_action/vortex_recall, /datum/action/item_action/toggle_unfriendly_fire)
var/cooldown_time = 20 //how long the cooldown between non-melee ranged attacks is
- var/chaser_cooldown = 101 //how long the cooldown between firing chasers at mobs is
+ var/chaser_cooldown = 81 //how long the cooldown between firing chasers at mobs is
var/chaser_timer = 0 //what our current chaser cooldown is
+ var/chaser_speed = 0.8 //how fast our chasers are
var/timer = 0 //what our current cooldown is
- var/blast_range = 3 //how long the cardinal blast's walls are
- var/obj/effect/hierophant/rune //the associated rune we teleport to
+ var/blast_range = 13 //how long the cardinal blast's walls are
+ var/obj/effect/hierophant/beacon //the associated beacon we teleport to
var/teleporting = FALSE //if we ARE teleporting
var/friendly_fire_check = FALSE //if the blasts we make will consider our faction against the faction of hit targets
-/obj/item/hierophant_staff/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
+/obj/item/hierophant_club/examine(mob/user)
+ ..()
+ to_chat(user, "The[beacon ? " beacon is not currently":"re is a beacon"] attached.")
+
+/obj/item/hierophant_club/suicide_act(mob/living/user)
+ atom_say("Xverwpsgexmrk...")
+ user.visible_message("[user] holds [src] into the air! It looks like [user.p_theyre()] trying to commit suicide!")
+ new/obj/effect/temp_visual/hierophant/telegraph(get_turf(user))
+ playsound(user,'sound/machines/airlock_open.ogg', 75, TRUE)
+ user.visible_message("[user] fades out, leaving [user.p_their()] belongings behind!")
+ for(var/obj/item/I in user)
+ if(I != src)
+ user.unEquip(I)
+ for(var/turf/T in RANGE_TURFS(1, user))
+ var/obj/effect/temp_visual/hierophant/blast/B = new(T, user, TRUE)
+ B.damage = 0
+ user.unEquip(src) //Drop us last, so it goes on top of their stuff
+ qdel(user)
+ return OBLITERATION
+
+
+/obj/item/hierophant_club/afterattack(atom/target, mob/user, proximity_flag, click_parameters)
..()
var/turf/T = get_turf(target)
if(!T || timer > world.time)
return
+ calculate_anger_mod(user)
timer = world.time + CLICK_CD_MELEE //by default, melee attacks only cause melee blasts, and have an accordingly short cooldown
if(proximity_flag)
- spawn(0)
- aoe_burst(T, user)
+ INVOKE_ASYNC(src, .proc/aoe_burst, T, user)
add_attack_logs(user, target, "Fired 3x3 blast at [src]")
else
if(ismineralturf(target) && get_dist(user, target) < 6) //target is minerals, we can hit it(even if we can't see it)
- spawn(0)
- cardinal_blasts(T, user)
+ INVOKE_ASYNC(src, .proc/cardinal_blasts, T, user)
timer = world.time + cooldown_time
else if(target in view(5, get_turf(user))) //if the target is in view, hit it
timer = world.time + cooldown_time
if(isliving(target) && chaser_timer <= world.time) //living and chasers off cooldown? fire one!
chaser_timer = world.time + chaser_cooldown
- new /obj/effect/temp_visual/hierophant/chaser(get_turf(user), user, target, 1.5, friendly_fire_check)
+ var/obj/effect/temp_visual/hierophant/chaser/C = new(get_turf(user), user, target, chaser_speed, friendly_fire_check)
+ C.damage = 30
+ C.monster_damage_boost = FALSE
add_attack_logs(user, target, "Fired a chaser at [src]")
else
- spawn(0)
- cardinal_blasts(T, user) //otherwise, just do cardinal blast
+ INVOKE_ASYNC(src, .proc/cardinal_blasts, T, user) //otherwise, just do cardinal blast
add_attack_logs(user, target, "Fired cardinal blast at [src]")
else
- to_chat(user, "That target is out of range!") //too far away
+ to_chat(user, "That target is out of range!" )
+ timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
-/obj/item/hierophant_staff/ui_action_click(mob/user, actiontype)
+/obj/item/hierophant_club/proc/calculate_anger_mod(mob/user) //we get stronger as the user loses health
+ chaser_cooldown = initial(chaser_cooldown)
+ cooldown_time = initial(cooldown_time)
+ chaser_speed = initial(chaser_speed)
+ blast_range = initial(blast_range)
+ if(isliving(user))
+ var/mob/living/L = user
+ var/health_percent = L.health / L.maxHealth
+ chaser_cooldown += round(health_percent * 20) //two tenths of a second for each missing 10% of health
+ cooldown_time += round(health_percent * 10) //one tenth of a second for each missing 10% of health
+ chaser_speed = max(chaser_speed + health_percent, 0.5) //one tenth of a second faster for each missing 10% of health
+ blast_range -= round(health_percent * 10) //one additional range for each missing 10% of health
+
+/obj/item/hierophant_club/update_icon()
+ icon_state = "hierophant_club[timer <= world.time ? "_ready":""][(beacon && !QDELETED(beacon)) ? "":"_beacon"]"
+ item_state = icon_state
+ if(ismob(loc))
+ var/mob/M = loc
+ M.update_inv_l_hand()
+ M.update_inv_r_hand()
+ M.update_inv_back()
+
+/obj/item/hierophant_club/proc/prepare_icon_update()
+ update_icon()
+ sleep(timer - world.time)
+ update_icon()
+
+/obj/item/hierophant_club/ui_action_click(mob/user, actiontype)
if(actiontype == /datum/action/item_action/toggle_unfriendly_fire) //toggle friendly fire...
friendly_fire_check = !friendly_fire_check
to_chat(user, "You toggle friendly fire [friendly_fire_check ? "off":"on"]!")
return
- if(user.is_in_active_hand(src) && user.is_in_inactive_hand(src)) //you need to hold the staff to teleport
- to_chat(user, "You need to hold the staff in your hands to [rune ? "teleport with it" : "create a rune"]!")
+ if(timer > world.time)
return
- if(!rune)
+ if(user.is_in_active_hand(src) && user.is_in_inactive_hand(src)) //you need to hold the staff to teleport
+ to_chat(user, "You need to hold the club in your hands to [beacon ? "teleport with it":"detach the beacon"]!")
+ return
+ if(!beacon || QDELETED(beacon))
if(isturf(user.loc))
- user.visible_message("[user] holds [src] carefully in front of [user.p_them()], moving it in a strange pattern...", \
- "You start creating a hierophant rune to teleport to...")
+ user.visible_message("[user] starts fiddling with [src]'s pommel...", \
+ "You start detaching the hierophant beacon...")
timer = world.time + 51
- if(do_after(user, 50, target = user))
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ if(do_after(user, 50, target = user) && !beacon)
var/turf/T = get_turf(user)
- playsound(T,'sound/magic/blind.ogg', 200, 1, -4)
+ playsound(T,'sound/magic/blind.ogg', 200, TRUE, -4)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, user)
- var/obj/effect/hierophant/H = new/obj/effect/hierophant(T)
- rune = H
+ beacon = new/obj/effect/hierophant(T)
user.update_action_buttons_icon()
- user.visible_message("[user] creates a strange rune beneath [user.p_them()]!", \
- "You create a hierophant rune, which you can teleport yourself and any allies to at any time!\n\
- You can remove the rune to place a new one by striking it with the staff.")
+ user.visible_message("[user] places a strange machine beneath [user.p_their()] feet!", \
+ "You detach the hierophant beacon, allowing you to teleport yourself and any allies to it at any time!\n\
+ You can remove the beacon to place it again by striking it with the club.")
else
timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
else
- to_chat(user, "You need to be on solid ground to produce a rune!")
+ to_chat(user, "You need to be on solid ground to detach the beacon!")
return
- if(get_dist(user, rune) <= 2) //rune too close abort
- to_chat(user, "You are too close to the rune to teleport to it!")
+ if(get_dist(user, beacon) <= 2) //beacon too close abort
+ to_chat(user, "You are too close to the beacon to teleport to it!")
return
- if(is_blocked_turf(get_turf(rune)))
- to_chat(user, "The rune is blocked by something, preventing teleportation!")
+ if(is_blocked_turf(get_turf(beacon), TRUE))
+ to_chat(user, "The beacon is blocked by something, preventing teleportation!")
+ return
+ if(!isturf(user.loc))
+ to_chat(user, "You don't have enough space to teleport from here!")
return
teleporting = TRUE //start channel
user.update_action_buttons_icon()
user.visible_message("[user] starts to glow faintly...")
timer = world.time + 50
- if(do_after(user, 40, target = user) && rune)
- var/turf/T = get_turf(rune)
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ beacon.icon_state = "hierophant_tele_on"
+ var/obj/effect/temp_visual/hierophant/telegraph/edge/TE1 = new /obj/effect/temp_visual/hierophant/telegraph/edge(user.loc)
+ var/obj/effect/temp_visual/hierophant/telegraph/edge/TE2 = new /obj/effect/temp_visual/hierophant/telegraph/edge(beacon.loc)
+ if(do_after(user, 40, target = user) && user && beacon)
+ var/turf/T = get_turf(beacon)
var/turf/source = get_turf(user)
- if(is_blocked_turf(T))
+ if(is_blocked_turf(T, TRUE))
teleporting = FALSE
- to_chat(user, "The rune is blocked by something, preventing teleportation!")
+ to_chat(user, "The beacon is blocked by something, preventing teleportation!")
user.update_action_buttons_icon()
+ timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ beacon.icon_state = "hierophant_tele_off"
return
new /obj/effect/temp_visual/hierophant/telegraph(T, user)
new /obj/effect/temp_visual/hierophant/telegraph(source, user)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/magic/wand_teleport.ogg', 200, 1)
- playsound(source,'sound/magic/blink.ogg', 200, 1)
- //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
- if(!do_after(user, 3, target = user) || !rune) //no walking away shitlord
+ playsound(T,'sound/magic/wand_teleport.ogg', 200, TRUE)
+ playsound(source,'sound/machines/airlock_open.ogg', 200, TRUE)
+ if(!do_after(user, 3, target = user) || !user || !beacon || QDELETED(beacon)) //no walking away shitlord
teleporting = FALSE
if(user)
user.update_action_buttons_icon()
+ timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ if(beacon)
+ beacon.icon_state = "hierophant_tele_off"
return
- if(is_blocked_turf(T))
+ if(is_blocked_turf(T, TRUE))
teleporting = FALSE
- to_chat(user, "The rune is blocked by something, preventing teleportation!")
+ to_chat(user, "The beacon is blocked by something, preventing teleportation!")
user.update_action_buttons_icon()
+ timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ beacon.icon_state = "hierophant_tele_off"
return
- add_attack_logs(user, rune, "Teleported self from ([source.x],[source.y],[source.z]) to ([T.x],[T.y],[T.z])")
+ add_attack_logs(user, beacon, "Teleported self from ([AREACOORD(source)]) to ([AREACOORD(beacon)])")
new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, user)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, user)
for(var/t in RANGE_TURFS(1, T))
@@ -119,18 +194,24 @@
var/obj/effect/temp_visual/hierophant/blast/B = new /obj/effect/temp_visual/hierophant/blast(t, user, TRUE) //but absolutely will hurt enemies
B.damage = 30
for(var/mob/living/L in range(1, source))
- spawn(0)
- teleport_mob(source, L, T, user) //regardless, take all mobs near us along
+ INVOKE_ASYNC(src, .proc/teleport_mob, source, L, T, user) //regardless, take all mobs near us along
sleep(6) //at this point the blasts detonate
+ if(beacon)
+ beacon.icon_state = "hierophant_tele_off"
else
+ qdel(TE1)
+ qdel(TE2)
timer = world.time
+ INVOKE_ASYNC(src, .proc/prepare_icon_update)
+ if(beacon)
+ beacon.icon_state = "hierophant_tele_off"
teleporting = FALSE
if(user)
user.update_action_buttons_icon()
-/obj/item/hierophant_staff/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user)
+/obj/item/hierophant_club/proc/teleport_mob(turf/source, mob/M, turf/target, mob/user)
var/turf/turf_to_teleport_to = get_step(target, get_dir(source, M)) //get position relative to caster
- if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to))
+ if(!turf_to_teleport_to || is_blocked_turf(turf_to_teleport_to, TRUE))
return
animate(M, alpha = 0, time = 2, easing = EASE_OUT) //fade out
sleep(1)
@@ -152,19 +233,19 @@
if(user != M)
add_attack_logs(user, M, "Teleported from ([source.x],[source.y],[source.z])")
-/obj/item/hierophant_staff/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay
+/obj/item/hierophant_club/proc/cardinal_blasts(turf/T, mob/living/user) //fire cardinal cross blasts with a delay
if(!T)
return
new /obj/effect/temp_visual/hierophant/telegraph/cardinal(T, user)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
+ playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
sleep(2)
- new /obj/effect/temp_visual/hierophant/blast(T, user, friendly_fire_check)
+ var/obj/effect/temp_visual/hierophant/blast/B = new(T, user, friendly_fire_check)
+ B.damage = HIEROPHANT_CLUB_CARDINAL_DAMAGE
+ B.monster_damage_boost = FALSE
for(var/d in cardinal)
- spawn(0)
- blast_wall(T, d, user)
+ INVOKE_ASYNC(src, .proc/blast_wall, T, d, user)
-/obj/item/hierophant_staff/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long
+/obj/item/hierophant_club/proc/blast_wall(turf/T, dir, mob/living/user) //make a wall of blasts blast_range tiles long
if(!T)
return
var/range = blast_range
@@ -173,16 +254,20 @@
for(var/i in 1 to range)
if(!J)
return
- new /obj/effect/temp_visual/hierophant/blast(J, user, friendly_fire_check)
+ var/obj/effect/temp_visual/hierophant/blast/B = new(J, user, friendly_fire_check)
+ B.damage = HIEROPHANT_CLUB_CARDINAL_DAMAGE
+ B.monster_damage_boost = FALSE
previousturf = J
J = get_step(previousturf, dir)
-/obj/item/hierophant_staff/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target
+/obj/item/hierophant_club/proc/aoe_burst(turf/T, mob/living/user) //make a 3x3 blast around a target
if(!T)
return
new /obj/effect/temp_visual/hierophant/telegraph(T, user)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
+ playsound(T,'sound/effects/bin_close.ogg', 200, TRUE)
sleep(2)
for(var/t in RANGE_TURFS(1, T))
- new /obj/effect/temp_visual/hierophant/blast(t, user, friendly_fire_check)
+ var/obj/effect/temp_visual/hierophant/blast/B = new(t, user, friendly_fire_check)
+ B.damage = 15 //keeps monster damage boost due to lower damage
+
+#undef HIEROPHANT_CLUB_CARDINAL_DAMAGE
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/carbon.dm b/code/modules/mob/living/carbon/carbon.dm
index 00de5dfd550..c2c0d711743 100644
--- a/code/modules/mob/living/carbon/carbon.dm
+++ b/code/modules/mob/living/carbon/carbon.dm
@@ -1042,7 +1042,7 @@ var/list/ventcrawl_machinery = list(/obj/machinery/atmospherics/unary/vent_pump,
return 1
/mob/living/carbon/proc/forceFedAttackLog(var/obj/item/reagent_containers/food/toEat, mob/user)
- add_attack_logs(user, src, "Fed [toEat]. Reagents: [toEat.reagents.log_list(toEat)]", ATKLOG_MOST)
+ add_attack_logs(user, src, "Fed [toEat]. Reagents: [toEat.reagents.log_list(toEat)]", toEat.reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
if(!iscarbon(user))
LAssailant = null
else
diff --git a/code/modules/mob/living/carbon/human/death.dm b/code/modules/mob/living/carbon/human/death.dm
index 64d06dac4db..4ceedc5b49c 100644
--- a/code/modules/mob/living/carbon/human/death.dm
+++ b/code/modules/mob/living/carbon/human/death.dm
@@ -101,11 +101,11 @@
return FALSE
set_heartattack(FALSE)
-
+ SSmobs.cubemonkeys -= src
if(dna.species)
dna.species.handle_hud_icons(src)
//Handle species-specific deaths.
- dna.species.handle_death(src)
+ dna.species.handle_death(gibbed, src)
if(ishuman(LAssailant))
var/mob/living/carbon/human/H=LAssailant
diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm
index b3d320de913..36e1589989f 100644
--- a/code/modules/mob/living/carbon/human/human.dm
+++ b/code/modules/mob/living/carbon/human/human.dm
@@ -57,6 +57,7 @@
/mob/living/carbon/human/Destroy()
. = ..()
+ SSmobs.cubemonkeys -= src
QDEL_LIST(bodyparts)
splinted_limbs.Cut()
diff --git a/code/modules/mob/living/carbon/human/species/_species.dm b/code/modules/mob/living/carbon/human/species/_species.dm
index 87c9c90359b..b658124bb8f 100644
--- a/code/modules/mob/living/carbon/human/species/_species.dm
+++ b/code/modules/mob/living/carbon/human/species/_species.dm
@@ -304,10 +304,7 @@
/datum/species/proc/handle_dna(mob/living/carbon/human/H, remove) //Handles DNA mutations, as that doesn't work at init. Make sure you call genemutcheck on any blocks changed here
return
-/datum/species/proc/handle_death(mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
- return
-
-/datum/species/proc/spec_death(gibbed, mob/living/carbon/human/C)
+/datum/species/proc/handle_death(gibbed, mob/living/carbon/human/H) //Handles any species-specific death events (such as dionaea nymph spawns).
return
/datum/species/proc/apply_damage(damage = 0, damagetype = BRUTE, def_zone = null, blocked = 0, mob/living/carbon/human/H, sharp = 0, obj/used_weapon = null)
diff --git a/code/modules/mob/living/carbon/human/species/golem.dm b/code/modules/mob/living/carbon/human/species/golem.dm
index 672e546184c..f2208c3d373 100644
--- a/code/modules/mob/living/carbon/human/species/golem.dm
+++ b/code/modules/mob/living/carbon/human/species/golem.dm
@@ -410,7 +410,7 @@
prefix = "Sand"
special_names = list("Castle", "Bag", "Dune", "Worm", "Storm")
-/datum/species/golem/sand/handle_death(mob/living/carbon/human/H)
+/datum/species/golem/sand/handle_death(gibbed, mob/living/carbon/human/H)
H.visible_message("[H] turns into a pile of sand!")
for(var/obj/item/W in H)
H.unEquip(W)
@@ -442,7 +442,7 @@
prefix = "Glass"
special_names = list("Lens", "Prism", "Fiber", "Bead")
-/datum/species/golem/glass/handle_death(mob/living/carbon/human/H)
+/datum/species/golem/glass/handle_death(gibbed, mob/living/carbon/human/H)
playsound(H, "shatter", 70, 1)
H.visible_message("[H] shatters!")
for(var/obj/item/W in H)
@@ -679,7 +679,7 @@
active = null
..()
-/datum/species/golem/bananium/handle_death(mob/living/carbon/human/H)
+/datum/species/golem/bananium/handle_death(gibbed, mob/living/carbon/human/H)
playsound(get_turf(H), 'sound/misc/sadtrombone.ogg', 70, 0)
/datum/unarmed_attack/golem/bananium
diff --git a/code/modules/mob/living/carbon/human/species/machine.dm b/code/modules/mob/living/carbon/human/species/machine.dm
index 4f5a65c82a2..65852786b11 100644
--- a/code/modules/mob/living/carbon/human/species/machine.dm
+++ b/code/modules/mob/living/carbon/human/species/machine.dm
@@ -90,7 +90,7 @@
if(monitor)
monitor.Remove(H)
-/datum/species/machine/handle_death(mob/living/carbon/human/H)
+/datum/species/machine/handle_death(gibbed, mob/living/carbon/human/H)
var/obj/item/organ/external/head/head_organ = H.get_organ("head")
if(!head_organ)
return
diff --git a/code/modules/mob/living/carbon/human/species/nucleation.dm b/code/modules/mob/living/carbon/human/species/nucleation.dm
index fe8a5587017..cf9f5846193 100644
--- a/code/modules/mob/living/carbon/human/species/nucleation.dm
+++ b/code/modules/mob/living/carbon/human/species/nucleation.dm
@@ -34,7 +34,7 @@
H.light_color = "#1C1C00"
H.set_light(2)
-/datum/species/nucleation/handle_death(mob/living/carbon/human/H)
+/datum/species/nucleation/handle_death(gibbed, mob/living/carbon/human/H)
var/turf/T = get_turf(H)
H.visible_message("[H]'s body explodes, leaving behind a pile of microscopic crystals!")
explosion(T, 0, 0, 2, 2) // Create a small explosion burst upon death
diff --git a/code/modules/mob/living/carbon/human/species/tajaran.dm b/code/modules/mob/living/carbon/human/species/tajaran.dm
index f441d4fab4d..ee12ba34afe 100644
--- a/code/modules/mob/living/carbon/human/species/tajaran.dm
+++ b/code/modules/mob/living/carbon/human/species/tajaran.dm
@@ -55,5 +55,5 @@
"is twisting their own neck!",
"is holding their breath!")
-/datum/species/tajaran/handle_death(mob/living/carbon/human/H)
+/datum/species/tajaran/handle_death(gibbed, mob/living/carbon/human/H)
H.stop_tail_wagging(1)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/unathi.dm b/code/modules/mob/living/carbon/human/species/unathi.dm
index 6146f00fa6f..7ab0f9cbec9 100644
--- a/code/modules/mob/living/carbon/human/species/unathi.dm
+++ b/code/modules/mob/living/carbon/human/species/unathi.dm
@@ -102,7 +102,7 @@
to_chat(user, "You run out of momentum!")
return
-/datum/species/unathi/handle_death(mob/living/carbon/human/H)
+/datum/species/unathi/handle_death(gibbed, mob/living/carbon/human/H)
H.stop_tail_wagging(1)
/datum/species/unathi/ashwalker
diff --git a/code/modules/mob/living/carbon/human/species/vox.dm b/code/modules/mob/living/carbon/human/species/vox.dm
index f8485e8f9e9..3bbd732145b 100644
--- a/code/modules/mob/living/carbon/human/species/vox.dm
+++ b/code/modules/mob/living/carbon/human/species/vox.dm
@@ -81,7 +81,7 @@
speciesbox = /obj/item/storage/box/survival_vox
-/datum/species/vox/handle_death(mob/living/carbon/human/H)
+/datum/species/vox/handle_death(gibbed, mob/living/carbon/human/H)
H.stop_tail_wagging(1)
/datum/species/vox/after_equip_job(datum/job/J, mob/living/carbon/human/H)
diff --git a/code/modules/mob/living/carbon/human/species/vulpkanin.dm b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
index 2ff707ee020..15e25fa2ff5 100644
--- a/code/modules/mob/living/carbon/human/species/vulpkanin.dm
+++ b/code/modules/mob/living/carbon/human/species/vulpkanin.dm
@@ -49,5 +49,5 @@
"is twisting their own neck!",
"is holding their breath!")
-/datum/species/vulpkanin/handle_death(mob/living/carbon/human/H)
+/datum/species/vulpkanin/handle_death(gibbed, mob/living/carbon/human/H)
H.stop_tail_wagging(1)
\ No newline at end of file
diff --git a/code/modules/mob/living/carbon/human/species/wryn.dm b/code/modules/mob/living/carbon/human/species/wryn.dm
index 6069da28f84..450da31b591 100644
--- a/code/modules/mob/living/carbon/human/species/wryn.dm
+++ b/code/modules/mob/living/carbon/human/species/wryn.dm
@@ -49,7 +49,7 @@
default_hair = "Antennae"
-/datum/species/wryn/handle_death(mob/living/carbon/human/H)
+/datum/species/wryn/handle_death(gibbed, mob/living/carbon/human/H)
for(var/mob/living/carbon/C in GLOB.living_mob_list)
if(C.get_int_organ(/obj/item/organ/internal/wryn/hivenode))
to_chat(C, "Your antennae tingle as you are overcome with pain...")
diff --git a/code/modules/mob/living/carbon/human/species/zombies.dm b/code/modules/mob/living/carbon/human/species/zombies.dm
index 34dc3355f16..81a462d9fab 100644
--- a/code/modules/mob/living/carbon/human/species/zombies.dm
+++ b/code/modules/mob/living/carbon/human/species/zombies.dm
@@ -67,7 +67,7 @@
playsound(H, pick(spooks), 50, TRUE, 10)
//Congrats you somehow died so hard you stopped being a zombie
-/datum/species/zombie/infectious/spec_death(gibbed, mob/living/carbon/C)
+/datum/species/zombie/infectious/handle_death(gibbed, mob/living/carbon/C)
. = ..()
var/obj/item/organ/internal/zombie_infection/infection
infection = C.get_organ_slot("zombie_infection")
diff --git a/code/modules/mob/living/silicon/decoy/decoy.dm b/code/modules/mob/living/silicon/decoy/decoy.dm
index de6c372acfb..d8f82cf9d93 100644
--- a/code/modules/mob/living/silicon/decoy/decoy.dm
+++ b/code/modules/mob/living/silicon/decoy/decoy.dm
@@ -30,6 +30,8 @@
icon_state = "ai-magma"
/mob/living/silicon/decoy/syndicate/depot
+ universal_speak = TRUE
+ universal_understand = TRUE
var/raised_alert = FALSE
/mob/living/silicon/decoy/syndicate/depot/proc/raise_alert()
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 70c713b37eb..088d8631e77 100644
--- a/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
+++ b/code/modules/mob/living/simple_animal/hostile/megafauna/hierophant.dm
@@ -2,124 +2,422 @@
The Hierophant
-The Hierophant spawns in its arena, an area designed to make it harder to fight than it would otherwise be.
+The Hierophant spawns in its arena, which makes fighting it challenging but not impossible.
The text this boss speaks is ROT4, use ROT22 to decode
-The Hierophant's attacks are as follows, and INTENSIFY at a random chance based on Hierophant's health;
-- Creates a cardinal or diagonal blast(Cross Blast) under its target, exploding after a short time.
- INTENSITY EFFECT: Creates one of the cross blast types under itself instead of under the target.
- INTENSITY EFFECT: The created Cross Blast fires in all directions if below half health.
-- If no chasers exist, creates a chaser that will seek its target, leaving a trail of blasts.
- INTENSITY EFFECT: Creates a second, slower chaser.
-- Creates an expanding AoE burst.
-- INTENSE ATTACKS:
+The Hierophant's attacks are as follows;
+- These attacks happen at a random, increasing chance:
If target is at least 2 tiles away; Blinks to the target after a very brief delay, damaging everything near the start and end points.
As above, but does so multiple times if below half health.
- Rapidly creates Cross Blasts under a target.
- If chasers are off cooldown, creates four high-speed chasers.
-- IF TARGET WAS STRUCK IN MELEE: Creates a 3x3 square of blasts under the target.
+ Rapidly creates cardinal and diagonal Cross Blasts under a target.
+ If chasers are off cooldown, creates 4 chasers.
-Cross Blasts and the AoE burst gain additional range as the Hierophant loses health, while Chasers gain additional speed.
+- IF TARGET IS OUTSIDE THE ARENA: Creates an arena around the target for 10 seconds, blinking to the target if not in the created arena.
+ The arena has a 20 second cooldown, giving people a small window to get the fuck out.
-When The Hierophant dies, it leaves behind its staff, which, while much weaker than when wielded by The Hierophant itself, is still quite effective.
-- The staff can place a teleport rune, allowing the user to teleport themself and their allies to the rune.
+- If no chasers exist, creates a chaser that will seek its target, leaving a trail of blasts.
+ Is more likely to create a second, slower, chaser if hurt.
+- If the target is at least 2 tiles away, may Blink to the target after a very brief delay, damaging everything near the start and end points.
+- Creates a cardinal or diagonal blast(Cross Blast) under its target, exploding after a short time.
+ If below half health, the created Cross Blast may fire in all directions.
+- Creates an expanding AoE burst.
+
+- IF ATTACKING IN MELEE: Creates an expanding AoE burst.
+
+Cross Blasts and the AoE burst gain additional range as Hierophant loses health, while Chasers gain additional speed.
+
+When Hierophant dies, it stops trying to murder you and shrinks into a small form, which, while much weaker, is still quite effective.
+- The smaller club can place a teleport beacon, allowing the user to teleport themself and their allies to the beacon.
Difficulty: Hard
*/
/mob/living/simple_animal/hostile/megafauna/hierophant
- name = "Hierophant"
- desc = "An ancient, powerful priest-like being wielding a mighty staff."
+ name = "hierophant"
+ 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"
- //attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
- attack_sound = "swing_hit"
+ attack_sound = 'sound/weapons/sonic_jackhammer.ogg'
icon_state = "hierophant"
icon_living = "hierophant"
friendly = "stares down"
- icon = 'icons/mob/lavaland/hierophant.dmi'
+ 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 = 50
- melee_damage_lower = 10
- melee_damage_upper = 10
- speed = 1
+ melee_damage_lower = 15
+ melee_damage_upper = 15
+ speed = 10
move_to_delay = 10
- ranged = 1
- pixel_x = -16
+ ranged = TRUE
ranged_cooldown_time = 40
- aggro_vision_range = 23
- loot = list(/obj/item/hierophant_staff)
- crusher_loot = list(/obj/item/hierophant_staff, /obj/item/crusher_trophy/vortex_talisman)
+ aggro_vision_range = 21 //so it can see to one side of the arena to the other
+ loot = list(/obj/item/hierophant_club)
+ crusher_loot = list(/obj/item/hierophant_club, /obj/item/crusher_trophy/vortex_talisman)
wander = FALSE
- var/burst_range = 3 //range on burst aoe
- var/beam_range = 5 //range on cross blast beams
- var/chaser_speed = 3 //how fast chasers are currently
- var/chaser_cooldown = 101 //base cooldown/cooldown var between spawning chasers
- var/major_attack_cooldown = 60 //base cooldown for major attacks
- var/blinking = FALSE //if we're doing something that requires us to stand still and not attack
- var/obj/effect/hierophant/spawned_rune //the rune we teleport back to
- var/timeout_time = 15 //after this many Life() ticks with no target, we return to our rune
- var/did_reset = TRUE //if we timed out, returned to our rune, and healed some
- //var/list/kill_phrases = list("Wsyvgi sj irivkc xettih. Vitemvmrk...", "Irivkc wsyvgi jsyrh. Vitemvmrk...", "Jyip jsyrh. Egxmzexmrk vitemv gcgpiw...")
- //var/list/target_phrases = list("Xevkix psgexih.", "Iriqc jsyrh.", "Eguymvih xevkix.")
internal_type = /obj/item/gps/internal/hierophant
medal_type = BOSS_MEDAL_HIEROPHANT
score_type = HIEROPHANT_SCORE
del_on_death = TRUE
death_sound = 'sound/magic/repulse.ogg'
+ attack_action_types = list(/datum/action/innate/megafauna_attack/blink,
+ /datum/action/innate/megafauna_attack/chaser_swarm,
+ /datum/action/innate/megafauna_attack/cross_blasts,
+ /datum/action/innate/megafauna_attack/blink_spam)
+
+ var/burst_range = 3 //range on burst aoe
+ var/beam_range = 5 //range on cross blast beams
+ var/chaser_speed = 3 //how fast chasers are currently
+ var/chaser_cooldown = 101 //base cooldown/cooldown var between spawning chasers
+ var/major_attack_cooldown = 60 //base cooldown for major attacks
+ var/arena_cooldown = 200 //base cooldown/cooldown var for creating an arena
+ var/blinking = FALSE //if we're doing something that requires us to stand still and not attack
+ var/obj/effect/hierophant/spawned_beacon //the beacon we teleport back to
+ var/timeout_time = 15 //after this many Life() ticks with no target, we return to our beacon
+ var/did_reset = TRUE //if we timed out, returned to our beacon, and healed some
+ 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
/mob/living/simple_animal/hostile/megafauna/hierophant/Initialize(mapload)
. = ..()
- spawned_rune = new(loc)
+ spawned_beacon = new(loc)
-/mob/living/simple_animal/hostile/megafauna/hierophant/Life(seconds, times_fired)
+/datum/action/innate/megafauna_attack/blink
+ name = "Blink To Target"
+ icon_icon = 'icons/mob/actions/actions.dmi'
+ button_icon_state = "sniper_zoom"
+ chosen_message = "You are now blinking to your target."
+ chosen_attack_num = 1
+
+/datum/action/innate/megafauna_attack/chaser_swarm
+ name = "Chaser Swarm"
+ icon_icon = 'icons/effects/effects.dmi'
+ button_icon_state = "hierophant_squares_indefinite"
+ chosen_message = "You are firing a chaser swarm at your target."
+ chosen_attack_num = 2
+
+/datum/action/innate/megafauna_attack/cross_blasts
+ name = "Cross Blasts"
+ icon_icon = 'icons/effects/effects.dmi'
+ button_icon_state = "hierophant_blast_indefinite"
+ chosen_message = "You are now firing cross blasts at your target."
+ chosen_attack_num = 3
+
+/datum/action/innate/megafauna_attack/blink_spam
+ name = "Blink Chase"
+ icon_icon = 'icons/obj/lavaland/artefacts.dmi'
+ button_icon_state = "hierophant_club_ready_beacon"
+ chosen_message = "You are now repeatedly blinking at your target."
+ chosen_attack_num = 4
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
+ if(blinking)
+ return
+
+ calculate_rage()
+ var/blink_counter = 1 + round(anger_modifier * 0.08)
+ var/cross_counter = 1 + round(anger_modifier * 0.12)
+
+ arena_trap(target)
+ ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
+
+ var/target_slowness = 0
+ var/mob/living/L
+ if(isliving(target))
+ L = target
+ target_slowness += L.movement_delay()
+ if(client)
+ target_slowness += 1
+
+ target_slowness = max(target_slowness, 1)
+ chaser_speed = max(1, (3 - anger_modifier * 0.04) + ((target_slowness - 1) * 0.5))
+
+ if(client)
+ switch(chosen_attack)
+ if(1)
+ blink(target)
+ if(2)
+ chaser_swarm(blink_counter, target_slowness, cross_counter)
+ if(3)
+ cross_blast_spam(blink_counter, target_slowness, cross_counter)
+ if(4)
+ blink_spam(blink_counter, target_slowness, cross_counter)
+ return
+
+ if(L?.stat == DEAD && !blinking && get_dist(src, L) > 2)
+ blink(L)
+ return
+
+ if(prob(anger_modifier * 0.75)) //major ranged attack
+ var/list/possibilities = list()
+ if(cross_counter > 1)
+ possibilities += "cross_blast_spam"
+ if(get_dist(src, target) > 2)
+ possibilities += "blink_spam"
+ if(chaser_cooldown < world.time)
+ if(prob(anger_modifier * 2))
+ possibilities = list("chaser_swarm")
+ else
+ possibilities += "chaser_swarm"
+ if(possibilities.len)
+ switch(pick(possibilities))
+ if("blink_spam") //blink either once or multiple times.
+ blink_spam(blink_counter, target_slowness, cross_counter)
+ if("cross_blast_spam") //fire a lot of cross blasts at a target.
+ cross_blast_spam(blink_counter, target_slowness, cross_counter)
+ if("chaser_swarm") //fire four fucking chasers at a target and their friends.
+ chaser_swarm(blink_counter, target_slowness, cross_counter)
+ return
+
+ if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
+ var/obj/effect/temp_visual/hierophant/chaser/C = new /obj/effect/temp_visual/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
+ chaser_cooldown = world.time + initial(chaser_cooldown)
+ if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
+ var/obj/effect/temp_visual/hierophant/chaser/OC = new(loc, src, target, chaser_speed * 1.5, FALSE)
+ OC.moving = 4
+ OC.moving_dir = pick(cardinal - C.moving_dir)
+
+ else if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
+ blink(target)
+
+ else if(prob(70 - anger_modifier)) //a cross blast of some type
+ if(prob(anger_modifier * (2 / target_slowness)) && health < maxHealth * 0.5) //we're super angry do it at all dirs
+ INVOKE_ASYNC(src, .proc/blasts, target, alldirs)
+ else if(prob(60))
+ INVOKE_ASYNC(src, .proc/blasts, target, cardinal)
+ else
+ INVOKE_ASYNC(src, .proc/blasts, target, diagonals)
+ else //just release a burst of power
+ INVOKE_ASYNC(src, .proc/burst, get_turf(src))
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink_spam(var/blink_counter, var/target_slowness, var/cross_counter)
+ ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
+ if(health < maxHealth * 0.5 && blink_counter > 1)
+ visible_message("\"Mx ampp rsx iwgeti.\"")
+ var/oldcolor = color
+ animate(src, color = "#660099", time = 6)
+ 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
+ break
+ blink_counter--
+ blinking = FALSE
+ blink(target)
+ blinking = TRUE
+ SLEEP_CHECK_DEATH(4 + target_slowness)
+ animate(src, color = oldcolor, time = 8)
+ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
+ SLEEP_CHECK_DEATH(8)
+ blinking = FALSE
+ else
+ blink(target)
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cross_blast_spam(var/blink_counter, var/target_slowness, var/cross_counter)
+ ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
+ visible_message("\"Piezi mx rsalivi xs vyr.\"")
+ blinking = TRUE
+ var/oldcolor = color
+ animate(src, color = "#660099", time = 6)
+ SLEEP_CHECK_DEATH(6)
+ while(!QDELETED(target) && cross_counter)
+ cross_counter--
+ if(prob(60))
+ INVOKE_ASYNC(src, .proc/blasts, target, cardinal)
+ else
+ INVOKE_ASYNC(src, .proc/blasts, target, diagonals)
+ SLEEP_CHECK_DEATH(6 + target_slowness)
+ animate(src, color = oldcolor, time = 8)
+ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
+ SLEEP_CHECK_DEATH(8)
+ blinking = FALSE
+
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/chaser_swarm(var/blink_counter, var/target_slowness, var/cross_counter)
+ ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75)
+ visible_message("\"Mx gerrsx lmhi.\"")
+ blinking = TRUE
+ var/oldcolor = color
+ animate(src, color = "#660099", time = 6)
+ SLEEP_CHECK_DEATH(6)
+ var/list/targets = ListTargets()
+ var/list/cardinal_copy = cardinal.Copy()
+ while(targets.len && cardinal_copy.len)
+ var/mob/living/pickedtarget = pick(targets)
+ if(targets.len >= cardinal_copy.len)
+ pickedtarget = pick_n_take(targets)
+ if(!istype(pickedtarget) || pickedtarget.stat == DEAD)
+ pickedtarget = target
+ if(QDELETED(pickedtarget) || (istype(pickedtarget) && pickedtarget.stat == DEAD))
+ break //main target is dead and we're out of living targets, cancel out
+ var/obj/effect/temp_visual/hierophant/chaser/C = new(loc, src, pickedtarget, chaser_speed, FALSE)
+ C.moving = 3
+ C.moving_dir = pick_n_take(cardinal_copy)
+ SLEEP_CHECK_DEATH(8 + target_slowness)
+ chaser_cooldown = world.time + initial(chaser_cooldown)
+ animate(src, color = oldcolor, time = 8)
+ addtimer(CALLBACK(src, /atom/proc/update_atom_colour), 8)
+ SLEEP_CHECK_DEATH(8)
+ blinking = FALSE
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blasts(mob/victim, var/list/directions = cardinal) //fires cross blasts with a delay
+ var/turf/T = get_turf(victim)
+ if(!T)
+ return
+ if(directions == cardinal)
+ new /obj/effect/temp_visual/hierophant/telegraph/cardinal(T, src)
+ else if(directions == diagonals)
+ 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)
+ SLEEP_CHECK_DEATH(2)
+ new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
+ for(var/d in directions)
+ INVOKE_ASYNC(src, .proc/blast_wall, T, d)
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, set_dir) //make a wall of blasts beam_range tiles long
+ var/range = beam_range
+ var/turf/previousturf = T
+ var/turf/J = get_step(previousturf, set_dir)
+ for(var/i in 1 to range)
+ new /obj/effect/temp_visual/hierophant/blast(J, src, FALSE)
+ 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
+ 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
+ arena_cooldown = world.time + initial(arena_cooldown)
+ for(var/d in cardinal)
+ INVOKE_ASYNC(src, .proc/arena_squares, T, d)
+ for(var/t in RANGE_TURFS(11, T))
+ if(t && get_dist(t, T) == 11)
+ 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!
+ INVOKE_ASYNC(src, .proc/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
+ var/turf/previousturf = T
+ var/turf/J = get_step(previousturf, set_dir)
+ for(var/i in 1 to 10)
+ var/obj/effect/temp_visual/hierophant/squares/HS = new(J)
+ HS.setDir(set_dir)
+ previousturf = J
+ J = get_step(previousturf, set_dir)
+ SLEEP_CHECK_DEATH(0.5)
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
+ if(blinking || !victim)
+ return
+ var/turf/T = get_turf(victim)
+ 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)
+ blinking = TRUE
+ SLEEP_CHECK_DEATH(2) //short delay before we start...
+ new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src)
+ new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, src)
+ for(var/t in RANGE_TURFS(1, T))
+ var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
+ B.damage = 30
+ for(var/t in RANGE_TURFS(1, source))
+ var/obj/effect/temp_visual/hierophant/blast/B = new(t, src, FALSE)
+ B.damage = 30
+ animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
+ SLEEP_CHECK_DEATH(1)
+ visible_message("[src] fades out!")
+ density = FALSE
+ SLEEP_CHECK_DEATH(2)
+ forceMove(T)
+ SLEEP_CHECK_DEATH(1)
+ animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
+ SLEEP_CHECK_DEATH(1)
+ density = TRUE
+ visible_message("[src] fades in!")
+ SLEEP_CHECK_DEATH(1) //at this point the blasts we made detonate
+ blinking = FALSE
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target
+ if(!victim)
+ return
+ var/turf/T = get_turf(victim)
+ if(!T)
+ return
+ new /obj/effect/temp_visual/hierophant/telegraph(T, src)
+ playsound(T,'sound/effects/bin_close.ogg', 200, 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)
+ var/last_dist = 0
+ for(var/t in spiral_range_turfs(burst_range, original))
+ var/turf/T = t
+ if(!T)
+ continue
+ var/dist = get_dist(original, T)
+ if(dist > last_dist)
+ last_dist = dist
+ sleep(1 + min(burst_range - last_dist, 12) * spread_speed) //gets faster as it gets further out
+ new /obj/effect/temp_visual/hierophant/blast(T, caster, FALSE)
+
+/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/Life()
. = ..()
- if(. && spawned_rune && !client)
- if(target || loc == spawned_rune.loc)
+ if(. && spawned_beacon && !QDELETED(spawned_beacon) && !client)
+ if(target || loc == spawned_beacon.loc)
timeout_time = initial(timeout_time)
else
timeout_time--
if(timeout_time <= 0 && !did_reset)
did_reset = TRUE
- //visible_message("\"Vixyvrmrk xs fewi...\"")
- blink(spawned_rune)
- adjustHealth(min((health - maxHealth) * 0.5, -50)) //heal for 50% of our missing health
+ visible_message("\"Vixyvrmrk xs fewi...\"")
+ blink(spawned_beacon)
+ adjustHealth(min((health - maxHealth) * 0.5, -250)) //heal for 50% of our missing health, minimum 10% of maximum health
wander = FALSE
- /*if(health > maxHealth * 0.9)
+ if(health > maxHealth * 0.9)
visible_message("\"Vitemvw gsqtpixi. Stivexmrk ex qebmqyq ijjmgmirgc.\"")
else
- visible_message("\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"")*/
+ visible_message("\"Vitemvw gsqtpixi. Stivexmsrep ijjmgmirgc gsqtvsqmwih.\"")
/mob/living/simple_animal/hostile/megafauna/hierophant/death()
- if(!can_die())
- return FALSE
- blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
- animate(src, alpha = 0, color = "660099", time = 20, easing = EASE_OUT)
- burst_range = 10
- //visible_message("\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"")
- visible_message("[src] disappears in a massive burst of magic, leaving only its staff.")
- burst(get_turf(src))
- // Things are in this order due to `del_on_death`
- return ..()
+ if(health > 0 || stat == DEAD)
+ return
+ else
+ stat = DEAD
+ blinking = TRUE //we do a fancy animation, release a huge burst(), and leave our staff.
+ visible_message("\"Mrmxmexmrk wipj-hiwxvygx wiuyirgi...\"")
+ visible_message("[src] shrinks, releasing a massive burst of energy!")
+ for(var/mob/living/L in view(7, src))
+ stored_nearby += L // store the people to grant the achievements to once we die
+ hierophant_burst(null, get_turf(src), 10)
+ stat = CONSCIOUS // deathgasp wont run if dead, stupid
+ ..(/* force_grant = stored_nearby */)
/mob/living/simple_animal/hostile/megafauna/hierophant/Destroy()
- QDEL_NULL(spawned_rune)
+ QDEL_NULL(spawned_beacon)
return ..()
/mob/living/simple_animal/hostile/megafauna/hierophant/devour(mob/living/L)
for(var/obj/item/W in L)
if(!L.unEquip(W))
qdel(W)
- /*visible_message(
- "\"[pick(kill_phrases)]\"\n[src] annihilates [L]!",
- "You annihilate [L], restoring your health!")*/
- visible_message(
- "\"Caw.\"\n[src] annihilates [L]!",
- "You annihilate [L], restoring your health!")
+ visible_message("\"[pick(kill_phrases)]\"")
+ visible_message("[src] annihilates [L]!","You annihilate [L], restoring your health!")
adjustHealth(-L.maxHealth*0.5)
L.dust()
@@ -128,24 +426,36 @@ Difficulty: Hard
if(istype(the_target, /mob/living/simple_animal/hostile/asteroid/hivelordbrood)) //ignore temporary targets in favor of more permanent targets
return FALSE
-/*/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target)
+/mob/living/simple_animal/hostile/megafauna/hierophant/GiveTarget(new_target)
var/targets_the_same = (new_target == target)
. = ..()
if(. && target && !targets_the_same)
- visible_message("\"[pick(target_phrases)]\"")*/
+ visible_message("\"[pick(target_phrases)]\"")
+ if(spawned_beacon && loc == spawned_beacon.loc && did_reset)
+ arena_trap(src)
/mob/living/simple_animal/hostile/megafauna/hierophant/adjustHealth(amount, updating_health = TRUE)
. = ..()
- if(src && amount > 0 && !blinking)
+ if(src && . && !blinking)
wander = TRUE
did_reset = FALSE
/mob/living/simple_animal/hostile/megafauna/hierophant/AttackingTarget()
if(!blinking)
if(target && isliving(target))
- spawn(0)
- melee_blast(get_turf(target)) //melee attacks on living mobs produce a 3x3 blast
- return ..()
+ var/mob/living/L = target
+ if(L.stat != DEAD)
+ if(ranged_cooldown <= world.time)
+ calculate_rage()
+ ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75)
+ INVOKE_ASYNC(src, .proc/burst, get_turf(src))
+ else
+ burst_range = 3
+ INVOKE_ASYNC(src, .proc/burst, get_turf(src), 0.25) //melee attacks on living mobs cause it to release a fast burst if on cooldown
+ else
+ devour(L)
+ else
+ return ..()
/mob/living/simple_animal/hostile/megafauna/hierophant/DestroySurroundings()
if(!blinking)
@@ -153,9 +463,16 @@ Difficulty: Hard
/mob/living/simple_animal/hostile/megafauna/hierophant/Move()
if(!blinking)
- /*if(!stat)
- playsound(loc, 'sound/mecha/mechmove04.ogg', 150, 1, -4)*/
- ..()
+ . = ..()
+
+/mob/living/simple_animal/hostile/megafauna/hierophant/Moved(oldLoc, movement_dir)
+ . = ..()
+ 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)
+ if(target)
+ arena_trap(target)
/mob/living/simple_animal/hostile/megafauna/hierophant/Goto(target, delay, minimum_distance)
wander = TRUE
@@ -168,254 +485,59 @@ Difficulty: Hard
burst_range = initial(burst_range) + round(anger_modifier * 0.08)
beam_range = initial(beam_range) + round(anger_modifier * 0.12)
-/mob/living/simple_animal/hostile/megafauna/hierophant/OpenFire()
- calculate_rage()
- var/target_is_slow = FALSE
- if(isliving(target))
- var/mob/living/L = target
- if(!blinking && L.stat == DEAD && get_dist(src, L) > 2)
- blink(L)
- return
- if(L.movement_delay() > 1.5)
- target_is_slow = TRUE
- chaser_speed = max(1, (3 - anger_modifier * 0.04) + target_is_slow * 0.5)
- if(blinking)
- return
- ranged_cooldown = world.time + max(5, ranged_cooldown_time - anger_modifier * 0.75) //scale cooldown lower with high anger.
-
- if(prob(anger_modifier * 0.75)) //major ranged attack
- var/list/possibilities = list()
- var/cross_counter = 1 + round(anger_modifier * 0.12)
- if(cross_counter > 1)
- possibilities += "cross_blast_spam"
- if(get_dist(src, target) > 2)
- possibilities += "blink_spam"
- if(chaser_cooldown < world.time)
- if(prob(anger_modifier * 2))
- possibilities = list("chaser_swarm")
- else
- possibilities += "chaser_swarm"
- if(possibilities.len)
- ranged_cooldown = world.time + max(5, major_attack_cooldown - anger_modifier * 0.75) //we didn't cancel out of an attack, use the higher cooldown
- var/blink_counter = 1 + round(anger_modifier * 0.08)
- switch(pick(possibilities))
- if("blink_spam") //blink either once or multiple times.
- if(health < maxHealth * 0.5 && !target_is_slow && blink_counter > 1)
- //visible_message("\"Mx ampp rsx iwgeti.\"")
- animate(src, color = "#660099", time = 6)
- while(health && 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
- break
- blink_counter--
- blinking = FALSE
- blink(target)
- blinking = TRUE
- sleep(5)
- animate(src, color = initial(color), time = 8)
- sleep(8)
- blinking = FALSE
- else
- blink(target)
- if("cross_blast_spam") //fire a lot of cross blasts at a target.
- //visible_message("\"Piezi mx rsalivi xs vyr.\"")
- blinking = TRUE
- animate(src, color = "#660099", time = 6)
- while(health && target && cross_counter)
- cross_counter--
- var/delay = 6
- if(prob(60))
- spawn(0)
- cardinal_blasts(target)
- else
- spawn(0)
- diagonal_blasts(target)
- delay = 5 //this one isn't so mean, so do the next one faster(if there is one)
- sleep(delay)
- animate(src, color = initial(color), time = 8)
- sleep(8)
- blinking = FALSE
- if("chaser_swarm") //fire four fucking chasers at a target and their friends.
- //visible_message("\"Mx gerrsx lmhi.\"")
- blinking = TRUE
- animate(src, color = "#660099", time = 10)
- var/list/targets = ListTargets()
- var/list/cardinal_copy = cardinal.Copy()
- while(health && targets.len && cardinal_copy.len)
- var/mob/living/pickedtarget = pick(targets)
- if(targets.len > 4)
- pickedtarget = pick_n_take(targets)
- if(pickedtarget.stat == DEAD)
- pickedtarget = target
- var/obj/effect/temp_visual/hierophant/chaser/C = new /obj/effect/temp_visual/hierophant/chaser(loc, src, pickedtarget, chaser_speed, FALSE)
- C.moving = 3
- C.moving_dir = pick_n_take(cardinal_copy)
- sleep(10)
- chaser_cooldown = world.time + initial(chaser_cooldown)
- animate(src, color = initial(color), time = 8)
- sleep(8)
- blinking = FALSE
- return
-
- if(prob(10 + (anger_modifier * 0.5)) && get_dist(src, target) > 2)
- blink(target)
-
- else if(prob(70 - anger_modifier)) //a cross blast of some type
- if(prob(anger_modifier)) //at us?
- if(prob(anger_modifier * 2) && health < maxHealth * 0.5) //we're super angry do it at all dirs
- spawn(0)
- alldir_blasts(src)
- else if(prob(60))
- spawn(0)
- cardinal_blasts(src)
- else
- spawn(0)
- diagonal_blasts(src)
- else //at them?
- if(prob(anger_modifier * 2) && health < maxHealth * 0.5 && !target_is_slow) //we're super angry do it at all dirs
- spawn(0)
- alldir_blasts(target)
- else if(prob(60))
- spawn(0)
- cardinal_blasts(target)
- else
- spawn(0)
- diagonal_blasts(target)
- else if(chaser_cooldown < world.time) //if chasers are off cooldown, fire some!
- var/obj/effect/temp_visual/hierophant/chaser/C = new /obj/effect/temp_visual/hierophant/chaser(loc, src, target, chaser_speed, FALSE)
- chaser_cooldown = world.time + initial(chaser_cooldown)
- if((prob(anger_modifier) || target.Adjacent(src)) && target != src)
- var/obj/effect/temp_visual/hierophant/chaser/OC = new /obj/effect/temp_visual/hierophant/chaser(loc, src, target, max(1.5, 5 - anger_modifier * 0.07), FALSE)
- OC.moving = 4
- OC.moving_dir = pick(cardinal - C.moving_dir)
- else //just release a burst of power
- spawn(0)
- burst(get_turf(src))
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/diagonal_blasts(mob/victim) //fire diagonal cross blasts with a delay
- var/turf/T = get_turf(victim)
- if(!T)
- return
- new /obj/effect/temp_visual/hierophant/telegraph/diagonal(T, src)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
- sleep(2)
- new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
- for(var/d in diagonals)
- spawn(0)
- blast_wall(T, d)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/cardinal_blasts(mob/victim) //fire cardinal cross blasts with a delay
- var/turf/T = get_turf(victim)
- if(!T)
- return
- new /obj/effect/temp_visual/hierophant/telegraph/cardinal(T, src)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
- sleep(2)
- new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
- for(var/d in cardinal)
- spawn(0)
- blast_wall(T, d)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/alldir_blasts(mob/victim) //fire alldir cross blasts with a delay
- var/turf/T = get_turf(victim)
- if(!T)
- return
- new /obj/effect/temp_visual/hierophant/telegraph(T, src)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
- sleep(2)
- new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
- for(var/d in alldirs)
- spawn(0)
- blast_wall(T, d)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blast_wall(turf/T, dir) //make a wall of blasts beam_range tiles long
- var/range = beam_range
- var/turf/previousturf = T
- var/turf/J = get_step(previousturf, dir)
- for(var/i in 1 to range)
- new /obj/effect/temp_visual/hierophant/blast(J, src, FALSE)
- previousturf = J
- J = get_step(previousturf, dir)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/blink(mob/victim) //blink to a target
- if(blinking || !victim)
- return
- var/turf/T = get_turf(victim)
- 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/blink.ogg', 200, 1)
- //playsound(T,'sound/magic/wand_teleport.ogg', 200, 1)
- playsound(source,'sound/magic/blink.ogg', 200, 1)
- //playsound(source,'sound/machines/AirlockOpen.ogg', 200, 1)
- blinking = TRUE
- sleep(2) //short delay before we start...
- new /obj/effect/temp_visual/hierophant/telegraph/teleport(T, src)
- new /obj/effect/temp_visual/hierophant/telegraph/teleport(source, src)
- for(var/t in RANGE_TURFS(1, T))
- var/obj/effect/temp_visual/hierophant/blast/B = new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
- B.damage = 30
- for(var/t in RANGE_TURFS(1, source))
- var/obj/effect/temp_visual/hierophant/blast/B = new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
- B.damage = 30
- animate(src, alpha = 0, time = 2, easing = EASE_OUT) //fade out
- sleep(1)
- visible_message("[src] fades out!")
- density = FALSE
- sleep(2)
- forceMove(T)
- sleep(1)
- animate(src, alpha = 255, time = 2, easing = EASE_IN) //fade IN
- sleep(1)
- density = TRUE
- visible_message("[src] fades in!")
- sleep(1) //at this point the blasts we made detonate
- blinking = FALSE
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/melee_blast(mob/victim) //make a 3x3 blast around a target
- if(!victim)
- return
- var/turf/T = get_turf(victim)
- if(!T)
- return
- new /obj/effect/temp_visual/hierophant/telegraph(T, src)
- playsound(T,'sound/magic/blink.ogg', 200, 1)
- //playsound(T,'sound/effects/bin_close.ogg', 200, 1)
- sleep(2)
- for(var/t in RANGE_TURFS(1, T))
- new /obj/effect/temp_visual/hierophant/blast(t, src, FALSE)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/proc/burst(turf/original) //release a wave of blasts
- playsound(original,'sound/magic/blink.ogg', 200, 1)
- //playsound(original,'sound/machines/AirlockOpen.ogg', 200, 1)
- var/last_dist = 0
- for(var/t in spiral_range_turfs(burst_range, original))
- var/turf/T = t
- if(!T)
- continue
- var/dist = get_dist(original, T)
- if(dist > last_dist)
- last_dist = dist
- sleep(1 + (burst_range - last_dist) * 0.5) //gets faster as it gets further out
- new /obj/effect/temp_visual/hierophant/blast(T, src, FALSE)
-
-/mob/living/simple_animal/hostile/megafauna/hierophant/AltClickOn(atom/A) //player control handler(don't give this to a player holy fuck)
- if(!istype(A) || get_dist(A, src) <= 2)
- return
- blink(A)
-
//Hierophant overlays
/obj/effect/temp_visual/hierophant
- layer = MOB_LAYER - 0.1
+ name = "vortex energy"
+ layer = BELOW_MOB_LAYER
var/mob/living/caster //who made this, anyway
-/obj/effect/temp_visual/hierophant/New(loc, new_caster)
- ..()
+/obj/effect/temp_visual/hierophant/Initialize(mapload, new_caster)
+ . = ..()
if(new_caster)
caster = new_caster
+/obj/effect/temp_visual/hierophant/squares
+ icon_state = "hierophant_squares"
+ duration = 3
+ light_range = MINIMUM_USEFUL_LIGHT_RANGE
+ randomdir = FALSE
+
+/obj/effect/temp_visual/hierophant/squares/Initialize(mapload, new_caster)
+ . = ..()
+ if(ismineralturf(loc))
+ var/turf/simulated/mineral/M = loc
+ M.gets_drilled(caster)
+
+/obj/effect/temp_visual/hierophant/wall //smoothing and pooling were not friends, but pooling is dead.
+ name = "vortex wall"
+ icon = 'icons/turf/walls/hierophant_wall_temp.dmi'
+ icon_state = "wall"
+ light_range = MINIMUM_USEFUL_LIGHT_RANGE
+ duration = 100
+ smooth = SMOOTH_TRUE
+
+/obj/effect/temp_visual/hierophant/wall/Initialize(mapload, new_caster)
+ . = ..()
+ queue_smooth_neighbors(src)
+ queue_smooth(src)
+
+/obj/effect/temp_visual/hierophant/wall/Destroy()
+ queue_smooth_neighbors(src)
+ return ..()
+
+/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target)
+ if(QDELETED(caster))
+ return FALSE
+ if(mover == caster.pulledby)
+ return TRUE
+ if(istype(mover, /obj/item/projectile))
+ var/obj/item/projectile/P = mover
+ if(P.firer == caster)
+ return TRUE
+ if(mover == caster)
+ return TRUE
+ return FALSE
+
/obj/effect/temp_visual/hierophant/chaser //a hierophant's chaser. follows target around, moving and producing a blast every speed deciseconds.
duration = 98
var/mob/living/target //what it's following
@@ -429,15 +551,16 @@ Difficulty: Hard
var/speed = 3 //how many deciseconds between each step
var/currently_seeking = FALSE
var/friendly_fire_check = FALSE //if blasts produced apply friendly fire
+ var/monster_damage_boost = TRUE
+ var/damage = 10
-/obj/effect/temp_visual/hierophant/chaser/New(loc, new_caster, new_target, new_speed, is_friendly_fire)
- ..()
+/obj/effect/temp_visual/hierophant/chaser/Initialize(mapload, new_caster, new_target, new_speed, is_friendly_fire)
+ . = ..()
target = new_target
friendly_fire_check = is_friendly_fire
if(new_speed)
speed = new_speed
- spawn(0)
- seek_target()
+ addtimer(CALLBACK(src, .proc/seek_target), 1)
/obj/effect/temp_visual/hierophant/chaser/proc/get_target_dir()
. = get_cardinal_dir(src, targetturf)
@@ -475,7 +598,9 @@ Difficulty: Hard
targetturf = get_turf(target)
/obj/effect/temp_visual/hierophant/chaser/proc/make_blast()
- new /obj/effect/temp_visual/hierophant/blast(loc, caster, friendly_fire_check)
+ var/obj/effect/temp_visual/hierophant/blast/B = new(loc, caster, friendly_fire_check)
+ B.damage = damage
+ B.monster_damage_boost = monster_damage_boost
/obj/effect/temp_visual/hierophant/telegraph
icon = 'icons/effects/96x96.dmi'
@@ -499,132 +624,117 @@ Difficulty: Hard
duration = 40
/obj/effect/temp_visual/hierophant/blast
- icon = 'icons/effects/effects.dmi'
icon_state = "hierophant_blast"
name = "vortex blast"
- layer = 3.9 // between LYING_MOB_LAYER and ABOVE_MOB_LAYER
- luminosity = 1
+ light_range = 2
+ light_power = 2
desc = "Get out of the way!"
duration = 9
var/damage = 10 //how much damage do we do?
+ var/monster_damage_boost = TRUE //do we deal extra damage to monsters? Used by the boss
var/list/hit_things = list() //we hit these already, ignore them
var/friendly_fire_check = FALSE
var/bursting = FALSE //if we're bursting and need to hit anyone crossing us
-/obj/effect/temp_visual/hierophant/blast/New(loc, new_caster, friendly_fire)
- ..()
+/obj/effect/temp_visual/hierophant/blast/Initialize(mapload, new_caster, friendly_fire)
+ . = ..()
friendly_fire_check = friendly_fire
if(new_caster)
hit_things += new_caster
if(ismineralturf(loc)) //drill mineral turfs
var/turf/simulated/mineral/M = loc
M.gets_drilled(caster)
- spawn(0)
- blast()
+ INVOKE_ASYNC(src, .proc/blast)
/obj/effect/temp_visual/hierophant/blast/proc/blast()
var/turf/T = get_turf(src)
if(!T)
return
- playsound(T,'sound/magic/blind.ogg', 125, 1, -5) //make a sound
+ playsound(T,'sound/magic/blind.ogg', 125, TRUE, -5) //make a sound
sleep(6) //wait a little
bursting = TRUE
do_damage(T) //do damage and mark us as bursting
sleep(1.3) //slightly forgiving; the burst animation is 1.5 deciseconds
bursting = FALSE //we no longer damage crossers
-/obj/effect/temp_visual/hierophant/blast/Crossed(atom/movable/AM, oldloc)
+/obj/effect/temp_visual/hierophant/blast/Crossed(atom/movable/AM)
..()
if(bursting)
do_damage(get_turf(src))
/obj/effect/temp_visual/hierophant/blast/proc/do_damage(turf/T)
+ if(!damage)
+ return
for(var/mob/living/L in T.contents - hit_things) //find and damage mobs...
hit_things += L
if((friendly_fire_check && caster && caster.faction_check_mob(L)) || L.stat == DEAD)
continue
if(L.client)
flash_color(L.client, "#660099", 1)
- playsound(L,'sound/weapons/sear.ogg', 50, 1, -4)
+ playsound(L,'sound/weapons/sear.ogg', 50, TRUE, -4)
to_chat(L, "You're struck by a [name]!")
- var/limb_to_hit = pick("head", "chest", "r_arm", "l_arm", "r_leg", "l_leg")
+ 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))
var/armor = L.run_armor_check(limb_to_hit, "melee", "Your armor absorbs [src]!", "Your armor blocks part of [src]!", 50, "Your armor was penetrated by [src]!")
L.apply_damage(damage, BURN, limb_to_hit, armor)
- if(ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid))
+ if(ishostile(L))
+ var/mob/living/simple_animal/hostile/H = L //mobs find and damage you...
+ if(H.stat == CONSCIOUS && !H.target && H.AIStatus != AI_OFF && !H.client)
+ if(!QDELETED(caster))
+ if(get_dist(H, caster) <= H.aggro_vision_range)
+ H.FindTarget(list(caster), 1)
+ else
+ H.Goto(get_turf(caster), H.move_to_delay, 3)
+ if(monster_damage_boost && (ismegafauna(L) || istype(L, /mob/living/simple_animal/hostile/asteroid)))
L.adjustBruteLoss(damage)
- add_attack_logs(caster, L, "Struck with a [name]")
- for(var/obj/mecha/M in T.contents - hit_things) //and mechs.
+ if(caster)
+ add_attack_logs(caster, L, "Struck with a [name]")
+ for(var/obj/mecha/M in T.contents - hit_things) //also damage mechs.
hit_things += M
if(M.occupant)
if(friendly_fire_check && caster && caster.faction_check_mob(M.occupant))
continue
to_chat(M.occupant, "Your [M.name] is struck by a [name]!")
- playsound(M,'sound/weapons/sear.ogg', 50, 1, -4)
+ playsound(M,'sound/weapons/sear.ogg', 50, TRUE, -4)
M.take_damage(damage, BURN, 0, 0)
-/obj/effect/temp_visual/hierophant/wall //smoothing and pooling were not friends, but pooling is dead.
- name = "vortex wall"
- icon = 'icons/turf/walls/hierophant_wall_temp.dmi'
- icon_state = "wall"
- light_range = MINIMUM_USEFUL_LIGHT_RANGE
- duration = 100
- smooth = SMOOTH_TRUE
-
-/obj/effect/temp_visual/hierophant/wall/New(loc, new_caster)
- ..()
- queue_smooth_neighbors(src)
- queue_smooth(src)
-
-/obj/effect/temp_visual/hierophant/wall/Destroy()
- queue_smooth_neighbors(src)
- return ..()
-
-/obj/effect/temp_visual/hierophant/wall/CanPass(atom/movable/mover, turf/target)
- if(QDELETED(caster))
- return FALSE
- if(mover == caster.pulledby)
- return TRUE
- if(istype(mover, /obj/item/projectile))
- var/obj/item/projectile/P = mover
- if(P.firer == caster)
- return TRUE
- if(mover == caster)
- return TRUE
- return FALSE
-
-
/obj/effect/hierophant
- name = "hierophant rune"
- desc = "A powerful magic mark allowing whomever attunes themself to it to return to it at will."
- icon = 'icons/obj/rune.dmi'
- icon_state = "hierophant"
- layer = 2.5
+ name = "hierophant beacon"
+ desc = "A strange beacon, allowing mass teleportation for those able to use it."
+ icon = 'icons/obj/lavaland/artefacts.dmi'
+ icon_state = "hierophant_tele_off"
+ light_range = 2
+ layer = LOW_OBJ_LAYER
anchored = TRUE
- color = "#CC00FF"
+
+/obj/effect/hierophant/ex_act()
+ return
/obj/effect/hierophant/attackby(obj/item/I, mob/user, params)
- if(istype(I, /obj/item/hierophant_staff))
- var/obj/item/hierophant_staff/H = I
- if(H.rune == src)
- to_chat(user, "You start removing your hierophant rune...")
+ if(istype(I, /obj/item/hierophant_club))
+ var/obj/item/hierophant_club/H = I
+ if(H.timer > world.time)
+ return
+ if(H.beacon == src)
+ to_chat(user, "You start removing your hierophant beacon...")
H.timer = world.time + 51
+ INVOKE_ASYNC(H, /obj/item/hierophant_club.proc/prepare_icon_update)
if(do_after(user, 50, target = src))
- playsound(src,'sound/magic/blind.ogg', 200, 1, -4)
+ playsound(src,'sound/magic/blind.ogg', 200, TRUE, -4)
new /obj/effect/temp_visual/hierophant/telegraph/teleport(get_turf(src), user)
- to_chat(user, "You touch the rune with the staff, dispelling it!")
- H.rune = null
+ to_chat(user, "You collect [src], reattaching it to the club!")
+ H.beacon = null
user.update_action_buttons_icon()
qdel(src)
else
H.timer = world.time
+ INVOKE_ASYNC(H, /obj/item/hierophant_club.proc/prepare_icon_update)
else
- to_chat(user, "You touch the rune with the staff, but nothing happens.")
-
+ to_chat(user, "You touch the beacon with the club, but nothing happens.")
else
- ..()
+ return ..()
/obj/item/gps/internal/hierophant
icon_state = null
gpstag = "Zealous Signal"
desc = "Heed its words."
- invisibility = 100
+ invisibility = 100
\ No newline at end of file
diff --git a/code/modules/mob/living/simple_animal/hostile/netherworld.dm b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
index 96c0bf632ac..487123b1a2d 100644
--- a/code/modules/mob/living/simple_animal/hostile/netherworld.dm
+++ b/code/modules/mob/living/simple_animal/hostile/netherworld.dm
@@ -1,15 +1,15 @@
/mob/living/simple_animal/hostile/netherworld
name = "creature"
desc = "A sanity-destroying otherthing from the netherworld."
- icon_state = "otherthing"
- icon_living = "otherthing"
- icon_dead = "otherthing-dead"
+ icon_state = "otherthing-pink"
+ icon_living = "otherthing-pink"
+ icon_dead = "otherthing-pink-dead"
health = 80
maxHealth = 80
obj_damage = 100
melee_damage_lower = 25
melee_damage_upper = 50
- attacktext = "slashes"
+ attacktext = "chomps"
attack_sound = 'sound/weapons/bladeslice.ogg'
faction = list("creature")
speak_emote = list("screams")
@@ -33,7 +33,7 @@
/mob/living/simple_animal/hostile/netherworld/migo/Initialize()
. = ..()
- migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/voice/bcreep.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/mpatchedup.ogg', 'sound/voice/mfeelbetter.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clownstep2.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heartbeat.ogg', 'sound/effects/hyperspace_begin.ogg', 'sound/effects/hyperspace_end.ogg', 'sound/goonstation/effects/screech.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/goonstation/misc/airraid_loop.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/chainsaw.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gunshots/gunshot_silenced.ogg', 'sound/weapons/gunshots/gunshot.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kenetic_accel.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlock_close.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlock_open.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/ambience/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/outbreak5.ogg', 'sound/ai/outbreak7.ogg', 'sound/ai/poweroff.ogg', 'sound/ai/radiation.ogg', 'sound/ai/shuttlecalled.ogg', 'sound/ai/shuttledock.ogg', 'sound/ai/shuttlerecalled.ogg', 'sound/ai/aimalf.ogg') //hahahaha fuck you code divers
+ migo_sounds = list('sound/items/bubblewrap.ogg', 'sound/items/change_jaws.ogg', 'sound/items/crowbar.ogg', 'sound/items/drink.ogg', 'sound/items/deconstruct.ogg', 'sound/items/change_drill.ogg', 'sound/items/dodgeball.ogg', 'sound/items/eatfood.ogg', 'sound/items/screwdriver.ogg', 'sound/items/weeoo1.ogg', 'sound/items/wirecutter.ogg', 'sound/items/welder.ogg', 'sound/items/zip.ogg', 'sound/items/rped.ogg', 'sound/items/ratchet.ogg', 'sound/items/polaroid1.ogg', 'sound/items/pshoom.ogg', 'sound/items/airhorn.ogg', 'sound/voice/bcreep.ogg', 'sound/voice/biamthelaw.ogg', 'sound/voice/ed209_20sec.ogg', 'sound/voice/hiss3.ogg', 'sound/voice/hiss6.ogg', 'sound/voice/mpatchedup.ogg', 'sound/voice/mfeelbetter.ogg', 'sound/weapons/sear.ogg', 'sound/ambience/antag/tatoralert.ogg', 'sound/mecha/nominal.ogg', 'sound/mecha/weapdestr.ogg', 'sound/mecha/critdestr.ogg', 'sound/mecha/imag_enh.ogg', 'sound/effects/adminhelp.ogg', 'sound/effects/alert.ogg', 'sound/effects/attackblob.ogg', 'sound/effects/bamf.ogg', 'sound/effects/blobattack.ogg', 'sound/effects/break_stone.ogg', 'sound/effects/bubbles.ogg', 'sound/effects/bubbles2.ogg', 'sound/effects/clang.ogg', 'sound/effects/clownstep2.ogg', 'sound/effects/dimensional_rend.ogg', 'sound/effects/doorcreaky.ogg', 'sound/effects/empulse.ogg', 'sound/effects/explosionfar.ogg', 'sound/effects/explosion1.ogg', 'sound/effects/grillehit.ogg', 'sound/effects/genetics.ogg', 'sound/effects/heartbeat.ogg', 'sound/effects/hyperspace_begin.ogg', 'sound/effects/hyperspace_end.ogg', 'sound/goonstation/effects/screech.ogg', 'sound/effects/phasein.ogg', 'sound/effects/picaxe1.ogg', 'sound/effects/sparks1.ogg', 'sound/effects/smoke.ogg', 'sound/effects/splat.ogg', 'sound/effects/snap.ogg', 'sound/effects/tendril_destroyed.ogg', 'sound/effects/supermatter.ogg', 'sound/misc/desceration-01.ogg', 'sound/misc/desceration-02.ogg', 'sound/misc/desceration-03.ogg', 'sound/misc/bloblarm.ogg', 'sound/goonstation/misc/airraid_loop.ogg', 'sound/misc/interference.ogg', 'sound/misc/notice1.ogg', 'sound/misc/notice2.ogg', 'sound/misc/sadtrombone.ogg', 'sound/misc/slip.ogg', 'sound/weapons/armbomb.ogg', 'sound/weapons/chainsaw.ogg', 'sound/weapons/emitter.ogg', 'sound/weapons/emitter2.ogg', 'sound/weapons/blade1.ogg', 'sound/weapons/bladeslice.ogg', 'sound/weapons/blastcannon.ogg', 'sound/weapons/blaster.ogg', 'sound/weapons/bulletflyby3.ogg', 'sound/weapons/circsawhit.ogg', 'sound/weapons/cqchit2.ogg', 'sound/weapons/drill.ogg', 'sound/weapons/genhit1.ogg', 'sound/weapons/gunshots/gunshot_silenced.ogg', 'sound/weapons/gunshots/gunshot.ogg', 'sound/weapons/handcuffs.ogg', 'sound/weapons/homerun.ogg', 'sound/weapons/kenetic_accel.ogg', 'sound/machines/fryer/deep_fryer_emerge.ogg', 'sound/machines/airlock_alien_prying.ogg', 'sound/machines/airlock_close.ogg', 'sound/machines/airlockforced.ogg', 'sound/machines/airlock_open.ogg', 'sound/machines/alarm.ogg', 'sound/machines/blender.ogg', 'sound/machines/boltsdown.ogg', 'sound/machines/boltsup.ogg', 'sound/machines/buzz-sigh.ogg', 'sound/machines/buzz-two.ogg', 'sound/machines/chime.ogg', 'sound/machines/defib_charge.ogg', 'sound/machines/defib_failed.ogg', 'sound/machines/defib_ready.ogg', 'sound/machines/defib_zap.ogg', 'sound/machines/deniedbeep.ogg', 'sound/machines/ding.ogg', 'sound/machines/disposalflush.ogg', 'sound/machines/door_close.ogg', 'sound/machines/door_open.ogg', 'sound/machines/engine_alert1.ogg', 'sound/machines/engine_alert2.ogg', 'sound/machines/hiss.ogg', 'sound/machines/honkbot_evil_laugh.ogg', 'sound/machines/juicer.ogg', 'sound/machines/ping.ogg', 'sound/ambience/signal.ogg', 'sound/machines/synth_no.ogg', 'sound/machines/synth_yes.ogg', 'sound/machines/terminal_alert.ogg', 'sound/machines/twobeep.ogg', 'sound/machines/ventcrawl.ogg', 'sound/machines/warning-buzzer.ogg', 'sound/ai/outbreak5.ogg', 'sound/ai/outbreak7.ogg', 'sound/ai/poweroff.ogg', 'sound/ai/radiation.ogg', 'sound/ai/shuttlecalled.ogg', 'sound/ai/shuttledock.ogg', 'sound/ai/shuttlerecalled.ogg', 'sound/ai/aimalf.ogg', 'sound/ambience/ambigen1.ogg', 'sound/ambience/ambigen3.ogg', 'sound/ambience/ambigen4.ogg', 'sound/ambience/ambigen5.ogg', 'sound/ambience/ambigen6.ogg', 'sound/ambience/ambigen10.ogg', 'sound/hallucinations/over_here1.ogg', 'sound/hallucinations/over_here2.ogg', 'sound/hallucinations/over_here3.ogg') //hahahaha fuck you code divers
/mob/living/simple_animal/hostile/netherworld/migo/say(message, bubble_type, var/list/spans = list(), sanitize = TRUE, datum/language/language = null, ignore_spam = FALSE, forced = null)
..()
diff --git a/code/modules/mob/living/simple_animal/hostile/pirate.dm b/code/modules/mob/living/simple_animal/hostile/pirate.dm
index 34a224ca5ce..4e3f71b30b1 100644
--- a/code/modules/mob/living/simple_animal/hostile/pirate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/pirate.dm
@@ -1,9 +1,10 @@
/mob/living/simple_animal/hostile/pirate
name = "Pirate"
desc = "Does what he wants cause a pirate is free."
+ icon = 'icons/mob/simple_human.dmi'
icon_state = "piratemelee"
icon_living = "piratemelee"
- icon_dead = "piratemelee_dead"
+ icon_dead = "piratemelee_dead" // Does not actually exist. del_on_death.
speak_chance = 0
turns_per_move = 5
response_help = "pushes the"
@@ -33,7 +34,7 @@
name = "Pirate Gunner"
icon_state = "pirateranged"
icon_living = "pirateranged"
- icon_dead = "piratemelee_dead"
+ icon_dead = "piratemelee_dead" // Does not actually exist. del_on_death.
projectilesound = 'sound/weapons/laser.ogg'
ranged = 1
rapid = 2
diff --git a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
index 6f6317ec839..5a278a65b24 100644
--- a/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
+++ b/code/modules/mob/living/simple_animal/hostile/retaliate/clown.dm
@@ -1,6 +1,7 @@
/mob/living/simple_animal/hostile/retaliate/clown
name = "Clown"
desc = "A denizen of clown planet"
+ icon = 'icons/mob/simple_human.dmi'
icon_state = "clown"
icon_living = "clown"
icon_dead = "clown_dead"
@@ -32,6 +33,7 @@
/mob/living/simple_animal/hostile/retaliate/clown/goblin
+ icon = 'icons/mob/animal.dmi'
name = "clown goblin"
desc = "A tiny walking mask and clown shoes. You want to honk his nose!"
icon_state = "clowngoblin"
diff --git a/code/modules/mob/living/simple_animal/hostile/russian.dm b/code/modules/mob/living/simple_animal/hostile/russian.dm
index 0c5f2647ae8..37ae67cfef5 100644
--- a/code/modules/mob/living/simple_animal/hostile/russian.dm
+++ b/code/modules/mob/living/simple_animal/hostile/russian.dm
@@ -1,10 +1,11 @@
/mob/living/simple_animal/hostile/russian
name = "Russian"
desc = "For the Motherland!"
+ icon = 'icons/mob/simple_human.dmi'
icon_state = "russianmelee"
icon_living = "russianmelee"
- icon_dead = "russianmelee_dead"
- icon_gib = "syndicate_gib"
+ icon_dead = "russianmelee_dead" // Does not actually exist. del_on_death.
+ icon_gib = "russianmelee_gib" // Does not actually exist. del_on_death.
speak_chance = 0
turns_per_move = 5
response_help = "pokes the"
diff --git a/code/modules/mob/living/simple_animal/hostile/skeleton.dm b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
index 011c47b2c24..ffa51b15bde 100644
--- a/code/modules/mob/living/simple_animal/hostile/skeleton.dm
+++ b/code/modules/mob/living/simple_animal/hostile/skeleton.dm
@@ -1,7 +1,7 @@
/mob/living/simple_animal/hostile/skeleton
name = "reanimated skeleton"
desc = "A real bonefied skeleton, doesn't seem like it wants to socialize."
- icon = 'icons/mob/animal.dmi'
+ icon = 'icons/mob/simple_human.dmi'
icon_state = "skeleton"
icon_living = "skeleton"
turns_per_move = 5
diff --git a/code/modules/mob/living/simple_animal/hostile/syndicate.dm b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
index 3d1bc42a190..f98b918e4ed 100644
--- a/code/modules/mob/living/simple_animal/hostile/syndicate.dm
+++ b/code/modules/mob/living/simple_animal/hostile/syndicate.dm
@@ -1,10 +1,11 @@
/mob/living/simple_animal/hostile/syndicate
name = "Syndicate Operative"
desc = "Death to Nanotrasen."
+ icon = 'icons/mob/simple_human.dmi'
icon_state = "syndicate"
icon_living = "syndicate"
- icon_dead = "syndicate_dead"
- icon_gib = "syndicate_gib"
+ icon_dead = "syndicate_dead" // Does not actually exist. del_on_death.
+ icon_gib = "syndicate_gib" // Does not actually exist. del_on_death.
speak_chance = 0
turns_per_move = 5
response_help = "pokes the"
@@ -32,14 +33,15 @@
/mob/living/simple_animal/hostile/syndicate/melee
melee_damage_lower = 20
melee_damage_upper = 25
- icon_state = "syndicatemelee"
- icon_living = "syndicatemelee"
+ icon_state = "syndicate_sword"
+ icon_living = "syndicate_sword"
attacktext = "slashes"
attack_sound = 'sound/weapons/bladeslice.ogg'
armour_penetration = 28
status_flags = 0
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier, /obj/item/melee/energy/sword/saber/red, /obj/item/shield/energy)
var/melee_block_chance = 20
+ var/ranged_block_chance = 35
/mob/living/simple_animal/hostile/syndicate/melee/attackby(var/obj/item/O as obj, var/mob/user as mob, params)
user.changeNext_move(CLICK_CD_MELEE)
@@ -63,12 +65,13 @@
/mob/living/simple_animal/hostile/syndicate/melee/bullet_act(var/obj/item/projectile/Proj)
- if(!Proj) return
- if(prob(65))
+ if(!Proj)
+ return
+ if(prob(ranged_block_chance))
+ visible_message("[src] blocks [Proj] with its shield!")
+ else
if((Proj.damage_type == BRUTE || Proj.damage_type == BURN))
adjustHealth(Proj.damage)
- else
- visible_message("[src] blocks [Proj] with its shield!")
return 0
/mob/living/simple_animal/hostile/syndicate/melee/autogib
@@ -80,7 +83,10 @@
robust_searching = 1 // Together with stat_attack, ensures dionae/etc that regen are killed properly
stat_attack = UNCONSCIOUS
universal_speak = 1
- melee_block_chance = 40
+ icon_state = "syndicate_swordonly"
+ icon_living = "syndicate_swordonly"
+ melee_block_chance = 0
+ ranged_block_chance = 0
del_on_death = 1
var/area/syndicate_depot/core/depotarea
var/raised_alert = FALSE
@@ -103,15 +109,21 @@
depotarea = areaMaster
spawn_turf = get_turf(src)
+
+/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/ListTargetsLazy()
+ // The normal ListTargetsLazy ignores walls, which is very bad in the case of depot mobs. So we override it.
+ return ListTargets()
+
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/Aggro()
. = ..()
if(target && istype(depotarea))
if(!seen_enemy)
seen_enemy = TRUE
- playsound(loc, 'sound/weapons/saberon.ogg', 35, 1)
+ if(!ranged)
+ playsound(loc, 'sound/weapons/saberon.ogg', 35, 1)
if(alert_on_shield_breach)
if(depotarea.shield_list.len)
- raise_alert("[name] reports that an intruder is trying to breach the armory shield!")
+ raise_alert("[name] reports that [target] is trying to breach the armory shield!")
alert_on_shield_breach = FALSE
raised_alert = FALSE
alert_on_death = TRUE
@@ -134,9 +146,8 @@
// This prevents someone from aggroing a depot mob, then hiding in a locker, perfectly safe, while the mob stands there getting killed by their friends.
LoseTarget()
-/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/handle_automated_action()
- if(!..())
- return
+/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/handle_automated_movement()
+ . = ..()
if(seen_enemy)
aggro_cycles++
if(alert_on_timeout && !raised_alert && aggro_cycles >= 60)
@@ -198,22 +209,61 @@
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/officer
name = "Syndicate Officer"
+ icon_state = "syndicate_sword"
+ icon_living = "syndicate_sword"
+ melee_block_chance = 20
+ ranged_block_chance = 35
alert_on_death = TRUE
- melee_block_chance = 60
+
+/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/officer/Initialize(mapload)
+ . = ..()
+ if(prob(50))
+ // 50% chance of switching to ranged variant.
+ // Designed to counter players taking cover behind reinforced plasmasglass.
+ // Does almost no danage in melee, but decent damage at range, and its shots go through glass.
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attacktext = "punches"
+ attack_sound = 'sound/weapons/punch1.ogg'
+ ranged = 1
+ rapid = 3
+ retreat_distance = 3
+ minimum_distance = 3
+ melee_block_chance = 0
+ ranged_block_chance = 0
+ icon_state = "syndicate_pistol"
+ icon_living = "syndicate_pistol"
+ projectiletype = /obj/item/projectile/beam/laser
+ projectilesound = 'sound/weapons/laser.ogg'
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory
name = "Syndicate Quartermaster"
- icon_state = "syndicatemeleespace"
- icon_living = "syndicatemeleespace"
+ icon_state = "syndicate_stormtrooper_sword"
+ icon_living = "syndicate_stormtrooper_sword"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
- maxHealth = 250
- health = 250
- melee_block_chance = 80
+ maxHealth = 200
+ health = 200
+ melee_block_chance = 40
alert_on_shield_breach = TRUE
-/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/Initialize()
+/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/Initialize(mapload)
..()
+ if(prob(50))
+ // 50% chance of switching to extremely dangerous ranged variant
+ melee_damage_lower = 10
+ melee_damage_upper = 10
+ attacktext = "punches"
+ attack_sound = 'sound/weapons/punch1.ogg'
+ ranged = 1
+ retreat_distance = 3
+ minimum_distance = 3
+ melee_block_chance = 0
+ ranged_block_chance = 0
+ icon_state = "syndicate_stormtrooper_shotgun"
+ icon_living = "syndicate_stormtrooper_shotgun"
+ projectiletype = /obj/item/projectile/bullet/sniper/penetrator // Ignores cover.
+ projectilesound = 'sound/weapons/gunshots/gunshot_sniper.ogg'
return INITIALIZE_HINT_LATELOAD
/mob/living/simple_animal/hostile/syndicate/melee/autogib/depot/armory/LateInitialize()
@@ -231,8 +281,8 @@
name = "Syndicate Backup"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
- icon_state = "syndicatemeleespace"
- icon_living = "syndicatemeleespace"
+ icon_state = "syndicate_space_sword"
+ icon_living = "syndicate_space_sword"
speed = 1
wander = 0
alert_on_spacing = FALSE
@@ -246,8 +296,8 @@
name = "Syndicate Commando"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
- icon_state = "syndicatemeleespace"
- icon_living = "syndicatemeleespace"
+ icon_state = "syndicate_space_sword"
+ icon_living = "syndicate_space_sword"
speed = 1
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatecommando, /obj/item/melee/energy/sword/saber/red, /obj/item/shield/energy)
@@ -260,15 +310,15 @@
rapid = 2
retreat_distance = 5
minimum_distance = 5
- icon_state = "syndicateranged"
- icon_living = "syndicateranged"
+ icon_state = "syndicate_smg"
+ icon_living = "syndicate_smg"
projectilesound = 'sound/weapons/gunshots/gunshot.ogg'
casingtype = /obj/item/ammo_casing/c45
loot = list(/obj/effect/mob_spawn/human/corpse/syndicatesoldier, /obj/item/gun/projectile/automatic/c20r)
/mob/living/simple_animal/hostile/syndicate/ranged/space
- icon_state = "syndicaterangedpsace"
- icon_living = "syndicaterangedpsace"
+ icon_state = "syndicate_space_smg"
+ icon_living = "syndicate_space_smg"
name = "Syndicate Commando"
atmos_requirements = list("min_oxy" = 0, "max_oxy" = 0, "min_tox" = 0, "max_tox" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0)
minbodytemp = 0
diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm
index ad6d00d88aa..0e1a19da662 100644
--- a/code/modules/mob/living/status_procs.dm
+++ b/code/modules/mob/living/status_procs.dm
@@ -576,8 +576,10 @@
"visible_message" = message, "self_message" = self_message, "examine_message" = examine_message)
/mob/living/proc/absorb_stun(amount, ignoring_flag_presence)
- if(!amount || amount <= 0 || stat || ignoring_flag_presence || !islist(stun_absorption))
+ if(amount < 0 || stat || ignoring_flag_presence || !islist(stun_absorption))
return FALSE
+ if(!amount)
+ amount = 0
var/priority_absorb_key
var/highest_priority
for(var/i in stun_absorption)
@@ -585,12 +587,13 @@
priority_absorb_key = stun_absorption[i]
highest_priority = priority_absorb_key["priority"]
if(priority_absorb_key)
- if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
- if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
- else if(priority_absorb_key["visible_message"])
- visible_message("[src][priority_absorb_key["visible_message"]]")
- else if(priority_absorb_key["self_message"])
- to_chat(src, "[priority_absorb_key["self_message"]]")
- priority_absorb_key["stuns_absorbed"] += amount
+ if(amount) //don't spam up the chat for continuous stuns
+ if(priority_absorb_key["visible_message"] || priority_absorb_key["self_message"])
+ if(priority_absorb_key["visible_message"] && priority_absorb_key["self_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]", "[priority_absorb_key["self_message"]]")
+ else if(priority_absorb_key["visible_message"])
+ visible_message("[src][priority_absorb_key["visible_message"]]")
+ else if(priority_absorb_key["self_message"])
+ to_chat(src, "[priority_absorb_key["self_message"]]")
+ priority_absorb_key["stuns_absorbed"] += amount
return TRUE
\ No newline at end of file
diff --git a/code/modules/power/lighting.dm b/code/modules/power/lighting.dm
index 203ff8c0d90..950ed7413f0 100644
--- a/code/modules/power/lighting.dm
+++ b/code/modules/power/lighting.dm
@@ -110,7 +110,8 @@
src.transfer_fingerprints_to(newlight)
qdel(src)
return
- ..()
+ else
+ return ..()
/obj/machinery/light_construct/small
name = "small light fixture frame"
@@ -299,17 +300,15 @@
// attack with item - insert light (if right type), otherwise try to break the light
/obj/machinery/light/attackby(obj/item/W, mob/living/user, params)
- user.changeNext_move(CLICK_CD_MELEE) //does not call parent requires manual definition
//Light replacer code
if(istype(W, /obj/item/lightreplacer))
var/obj/item/lightreplacer/LR = W
LR.ReplaceLight(src, user)
// attempt to insert light
- if(istype(W, /obj/item/light))
+ else if(istype(W, /obj/item/light))
if(status != LIGHT_EMPTY)
to_chat(user, "There is a [fitting] already inserted.")
- return
else
src.add_fingerprint(user)
var/obj/item/light/L = W
@@ -388,6 +387,8 @@
do_sparks(3, 1, src)
if(prob(75))
electrocute_mob(user, get_area(src), src, rand(0.7, 1), TRUE)
+ else
+ return ..()
/obj/machinery/light/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1)
@@ -687,8 +688,7 @@
// attack bulb/tube with object
// if a syringe, can inject plasma to make it explode
-/obj/item/light/attackby(var/obj/item/I, var/mob/user, params)
- ..()
+/obj/item/light/attackby(obj/item/I, mob/user, params)
if(istype(I, /obj/item/reagent_containers/syringe))
var/obj/item/reagent_containers/syringe/S = I
@@ -703,8 +703,7 @@
S.reagents.clear_reagents()
else
- ..()
- return
+ return ..()
// called after an attack with a light item
// shatter light, unless it was an attempt to put it in a light socket
diff --git a/code/modules/projectiles/guns/magic.dm b/code/modules/projectiles/guns/magic.dm
index 75f94dd83d0..c2dc67f5773 100644
--- a/code/modules/projectiles/guns/magic.dm
+++ b/code/modules/projectiles/guns/magic.dm
@@ -23,7 +23,6 @@
righthand_file = 'icons/mob/inhands/items_righthand.dmi'
/obj/item/gun/magic/afterattack(atom/target, mob/living/user, flag)
- newshot()
if(no_den_usage)
var/area/A = get_area(user)
if(istype(A, /area/wizard_station))
@@ -37,10 +36,14 @@
return charges
/obj/item/gun/magic/newshot(params)
- if(charges && chambered)
+ if(charges && chambered && !chambered.BB)
chambered.newshot(params)
return
+/obj/item/gun/magic/process_fire()
+ newshot()
+ return ..()
+
/obj/item/gun/magic/process_chamber()
if(chambered && !chambered.BB) //if BB is null, i.e the shot has been fired...
charges--//... drain a charge
diff --git a/code/modules/reagents/chemistry/holder.dm b/code/modules/reagents/chemistry/holder.dm
index 9b64161f58b..331e5d9ca8f 100644
--- a/code/modules/reagents/chemistry/holder.dm
+++ b/code/modules/reagents/chemistry/holder.dm
@@ -750,6 +750,13 @@ var/const/INGEST = 2
//Using IDs because SOME chemicals (I'm looking at you, chlorhydrate-beer) have the same names as other chemicals.
return english_list(data)
+//helper for attack logs, tells you if all reagents are harmless or not. returns true if harmless.
+/datum/reagents/proc/harmless_helper()
+ for(var/datum/reagent/r in reagent_list)
+ if(!r.harmless)
+ return FALSE
+ return TRUE
+
//two helper functions to preserve data across reactions (needed for xenoarch)
/datum/reagents/proc/get_data(reagent_id)
for(var/datum/reagent/D in reagent_list)
diff --git a/code/modules/reagents/chemistry/reagents.dm b/code/modules/reagents/chemistry/reagents.dm
index b1aca9820b5..195a6efec90 100644
--- a/code/modules/reagents/chemistry/reagents.dm
+++ b/code/modules/reagents/chemistry/reagents.dm
@@ -16,6 +16,7 @@
//Processing flags, defines the type of mobs the reagent will affect
//By default, all reagents will ONLY affect organics, not synthetics. Re-define in the reagent's definition if the reagent is meant to affect synths
var/process_flags = ORGANIC
+ var/harmless = FALSE //flag used for attack logs
var/can_synth = TRUE //whether or not a mech syringe gun and synthesize this reagent
var/overdose_threshold = 0
var/addiction_chance = 0
diff --git a/code/modules/reagents/chemistry/reagents/drink_base.dm b/code/modules/reagents/chemistry/reagents/drink_base.dm
index 8f15156753e..d945fa4bc13 100644
--- a/code/modules/reagents/chemistry/reagents/drink_base.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_base.dm
@@ -4,6 +4,7 @@
description = "Uh, some kind of drink."
reagent_state = LIQUID
color = "#E78108" // rgb: 231, 129, 8
+ harmless = TRUE
taste_description = "something which should not exist"
var/adj_dizzy = 0
var/adj_drowsy = 0
diff --git a/code/modules/reagents/chemistry/reagents/drink_cold.dm b/code/modules/reagents/chemistry/reagents/drink_cold.dm
index ac7adf3eadf..eb2cf6ac4f4 100644
--- a/code/modules/reagents/chemistry/reagents/drink_cold.dm
+++ b/code/modules/reagents/chemistry/reagents/drink_cold.dm
@@ -64,6 +64,7 @@
drink_icon = "nuka_colaglass"
drink_name = "Nuka Cola"
drink_desc = "Don't cry, Don't raise your eye, It's only nuclear wasteland"
+ harmless = FALSE
taste_description = "radioactive cola"
/datum/reagent/consumable/drink/cold/nuka_cola/on_mob_life(mob/living/M)
diff --git a/code/modules/reagents/chemistry/reagents/food.dm b/code/modules/reagents/chemistry/reagents/food.dm
index 4dcc8f15a42..4d6303f490c 100644
--- a/code/modules/reagents/chemistry/reagents/food.dm
+++ b/code/modules/reagents/chemistry/reagents/food.dm
@@ -5,6 +5,7 @@
/datum/reagent/consumable
name = "Consumable"
id = "consumable"
+ harmless = TRUE
taste_description = "generic food"
taste_mult = 4
var/nutriment_factor = 1 * REAGENTS_METABOLISM
@@ -287,6 +288,7 @@
description = "Sodium chloride, common table salt."
reagent_state = SOLID
color = "#B1B0B0"
+ harmless = FALSE
overdose_threshold = 100
taste_mult = 2
taste_description = "salt"
@@ -604,6 +606,7 @@
color = "#AB5D5D"
metabolization_rate = 0.2
overdose_threshold = 133
+ harmless = FALSE
taste_description = "bacon"
/datum/reagent/consumable/porktonium/overdose_process(mob/living/M, severity)
@@ -648,6 +651,7 @@
reagent_state = LIQUID
color = "#B2B139"
overdose_threshold = 50
+ harmless = FALSE
taste_description = "cheese?"
/datum/reagent/consumable/fake_cheese/overdose_process(mob/living/M, severity)
@@ -714,6 +718,7 @@
color = "#B1B0B0"
metabolization_rate = 0.2
overdose_threshold = 75
+ harmless = FALSE
taste_description = "oil"
/datum/reagent/consumable/hydrogenated_soybeanoil/on_mob_life(mob/living/M)
diff --git a/code/modules/reagents/chemistry/reagents/medicine.dm b/code/modules/reagents/chemistry/reagents/medicine.dm
index 01ccfa36dbb..c297716c1a7 100644
--- a/code/modules/reagents/chemistry/reagents/medicine.dm
+++ b/code/modules/reagents/chemistry/reagents/medicine.dm
@@ -2,6 +2,7 @@
name = "Medicine"
id = "medicine"
taste_description = "bitterness"
+ harmless = TRUE
/datum/reagent/medicine/on_mob_life(mob/living/M)
current_cycle++
@@ -44,6 +45,7 @@
reagent_state = LIQUID
color = "#FA46FA"
overdose_threshold = 40
+ harmless = FALSE
taste_description = "stimulant"
/datum/reagent/medicine/synaptizine/on_mob_life(mob/living/M)
@@ -135,6 +137,7 @@
reagent_state = SOLID
color = "#669900" // rgb: 102, 153, 0
overdose_threshold = 30
+ harmless = FALSE
taste_description = "reformation"
/datum/reagent/medicine/rezadone/on_mob_life(mob/living/M)
@@ -173,6 +176,7 @@
reagent_state = LIQUID
color = "#F0C814"
metabolization_rate = 3
+ harmless = FALSE //toxic if ingested, and I am NOT going to account for the difference
taste_description = "burn cream"
/datum/reagent/medicine/silver_sulfadiazine/on_mob_life(mob/living/M)
@@ -199,6 +203,7 @@
reagent_state = LIQUID
color = "#C8A5DC"
metabolization_rate = 3
+ harmless = FALSE
taste_description = "wound cream"
/datum/reagent/medicine/styptic_powder/on_mob_life(mob/living/M)
@@ -289,6 +294,7 @@
metabolization_rate = 0.2
overdose_threshold = 30
addiction_chance = 5
+ harmless = FALSE
taste_description = "health"
/datum/reagent/medicine/omnizine/on_mob_life(mob/living/M)
@@ -345,6 +351,7 @@
reagent_state = LIQUID
color = "#22AB35"
metabolization_rate = 0.8
+ harmless = FALSE
taste_description = "a painful cleansing"
/datum/reagent/medicine/calomel/on_mob_life(mob/living/M)
@@ -377,6 +384,7 @@
description = "Pentetic Acid is an aggressive chelation agent. May cause tissue damage. Use with caution."
reagent_state = LIQUID
color = "#C8A5DC"
+ harmless = FALSE
taste_description = "a purge"
/datum/reagent/medicine/pen_acid/on_mob_life(mob/living/M)
@@ -401,6 +409,7 @@
metabolization_rate = 0.1
shock_reduction = 25
overdose_threshold = 25
+ harmless = FALSE
taste_description = "relief"
/datum/reagent/medicine/sal_acid/on_mob_life(mob/living/M)
@@ -432,6 +441,7 @@
color = "#C8A5DC"
metabolization_rate = 0.2
addiction_chance = 20
+ harmless = FALSE
taste_description = "oxygenation"
/datum/reagent/medicine/perfluorodecalin/on_mob_life(mob/living/carbon/human/M)
@@ -453,6 +463,7 @@
metabolization_rate = 0.3
overdose_threshold = 35
addiction_chance = 25
+ harmless = FALSE
taste_description = "stimulation"
/datum/reagent/medicine/ephedrine/on_mob_life(mob/living/M)
@@ -502,6 +513,7 @@
reagent_state = LIQUID
color = "#5BCBE1"
addiction_chance = 10
+ harmless = FALSE
taste_description = "antihistamine"
/datum/reagent/medicine/diphenhydramine/on_mob_life(mob/living/M)
@@ -525,6 +537,7 @@
overdose_threshold = 20
addiction_chance = 50
shock_reduction = 50
+ harmless = FALSE
taste_description = "a delightful numbing"
/datum/reagent/medicine/morphine/on_mob_life(mob/living/M)
@@ -579,6 +592,7 @@
color = "#000000"
metabolization_rate = 0.2
overdose_threshold = 25
+ harmless = FALSE
taste_description = "a moment of respite"
/datum/reagent/medicine/atropine/on_mob_life(mob/living/M)
@@ -607,6 +621,7 @@
color = "#96B1AE"
metabolization_rate = 0.2
overdose_threshold = 20
+ harmless = FALSE
taste_description = "borrowed time"
/datum/reagent/medicine/epinephrine/on_mob_life(mob/living/M)
@@ -664,6 +679,7 @@
color = "#A0E85E"
metabolization_rate = 0.2
taste_description = "life"
+ harmless = FALSE
var/revive_type = SENTIENCE_ORGANIC //So you can't revive boss monsters or robots with it
/datum/reagent/medicine/strange_reagent/on_mob_life(mob/living/M)
@@ -781,6 +797,7 @@
id = "stimulants"
description = "Increases run speed and eliminates stuns, can heal minor damage. If overdosed it will deal toxin damage and stun."
color = "#C8A5DC"
+ harmless = FALSE
can_synth = FALSE
taste_description = "an unstoppable force"
@@ -819,6 +836,7 @@
color = "#C8A5DC"
metabolization_rate = 0.5 * REAGENTS_METABOLISM
overdose_threshold = 60
+ harmless = FALSE
can_synth = FALSE
/datum/reagent/medicine/stimulative_agent/on_mob_life(mob/living/M)
@@ -914,6 +932,7 @@
reagent_state = LIQUID
color = "#96DEDE"
metabolization_rate = 0.1
+ harmless = FALSE
taste_description = "sleepiness"
/datum/reagent/medicine/ether/on_mob_life(mob/living/M)
@@ -957,6 +976,7 @@
color = "#DCDCDC"
overdose_threshold = 30
metabolization_rate = 0.1
+ harmless = FALSE
taste_description = "faint hope"
/datum/reagent/medicine/omnizine_diluted/godblood
@@ -1041,6 +1061,7 @@
reagent_state = LIQUID
color = "#C8A5DC"
overdose_threshold = 30
+ harmless = FALSE
taste_description = "knitting wounds"
/datum/reagent/medicine/bicaridine/on_mob_life(mob/living/M)
@@ -1060,6 +1081,7 @@
reagent_state = LIQUID
color = "#C8A5DC"
overdose_threshold = 30
+ harmless = FALSE
taste_description = "soothed burns"
/datum/reagent/medicine/kelotane/on_mob_life(mob/living/M)
@@ -1079,6 +1101,7 @@
description = "Ichor from an extremely powerful plant. Great for restoring wounds, but it's a little heavy on the brain."
color = "#FFAF00"
overdose_threshold = 25
+ harmless = FALSE
taste_description = "a gift from nature"
/datum/reagent/medicine/earthsblood/on_mob_life(mob/living/M)
@@ -1116,6 +1139,7 @@
color = "#9b3401"
metabolization_rate = 0.5
can_synth = FALSE
+ harmless = FALSE
taste_description = "wholeness"
/datum/reagent/medicine/nanocalcium/on_mob_life(mob/living/carbon/human/M)
@@ -1155,6 +1179,7 @@
description = "An extract of lavaland atmospheric and mineral elements. Heals the user in small doses, but is extremely toxic otherwise."
color = "#C8A5DC" // rgb: 200, 165, 220
overdose_threshold = 3 //To prevent people stacking massive amounts of a very strong healing reagent
+ harmless = FALSE
can_synth = FALSE
/datum/reagent/medicine/lavaland_extract/on_mob_life(mob/living/carbon/M)
diff --git a/code/modules/reagents/chemistry/reagents/water.dm b/code/modules/reagents/chemistry/reagents/water.dm
index f77aac0133b..76ae7f49d9f 100644
--- a/code/modules/reagents/chemistry/reagents/water.dm
+++ b/code/modules/reagents/chemistry/reagents/water.dm
@@ -40,6 +40,7 @@
description = "Lubricant is a substance introduced between two moving surfaces to reduce the friction and wear between them. giggity."
reagent_state = LIQUID
color = "#1BB1AB"
+ harmless = TRUE
taste_description = "cherry"
/datum/reagent/lube/reaction_turf(turf/simulated/T, volume)
@@ -53,6 +54,7 @@
description = "A compound used to clean things. Now with 50% more sodium hypochlorite!"
reagent_state = LIQUID
color = "#61C2C2"
+ harmless = TRUE
taste_description = "floor cleaner"
/datum/reagent/space_cleaner/reaction_obj(obj/O, volume)
diff --git a/code/modules/reagents/reagent_containers/borghydro.dm b/code/modules/reagents/reagent_containers/borghydro.dm
index 6e15090ea88..e15e6316cb1 100644
--- a/code/modules/reagents/reagent_containers/borghydro.dm
+++ b/code/modules/reagents/reagent_containers/borghydro.dm
@@ -85,7 +85,7 @@
var/datum/reagent/injected = GLOB.chemical_reagents_list[reagent_ids[mode]]
var/contained = injected.name
var/trans = R.trans_to(M, amount_per_transfer_from_this)
- add_attack_logs(user, M, "Injected with [name] containing [contained], transfered [trans] units")
+ add_attack_logs(user, M, "Injected with [name] containing [contained], transfered [trans] units", injected.harmless ? ATKLOG_ALMOSTALL : null)
M.LAssailant = user
to_chat(user, "[trans] units injected. [R.total_volume] units remaining.")
return
diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm
index d03c591261a..be184753f14 100644
--- a/code/modules/reagents/reagent_containers/hypospray.dm
+++ b/code/modules/reagents/reagent_containers/hypospray.dm
@@ -45,7 +45,7 @@
var/contained = english_list(injected)
- add_attack_logs(user, M, "Injected with [src] containing ([contained])")
+ add_attack_logs(user, M, "Injected with [src] containing ([contained])", reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
return TRUE
diff --git a/code/modules/reagents/reagent_containers/syringes.dm b/code/modules/reagents/reagent_containers/syringes.dm
index 0d3d4f17252..349e3bc0910 100644
--- a/code/modules/reagents/reagent_containers/syringes.dm
+++ b/code/modules/reagents/reagent_containers/syringes.dm
@@ -146,7 +146,7 @@
rinject += R.name
var/contained = english_list(rinject)
- add_attack_logs(user, L, "Injected with [name] containing [contained], transfered [amount_per_transfer_from_this] units")
+ add_attack_logs(user, L, "Injected with [name] containing [contained], transfered [amount_per_transfer_from_this] units", reagents.harmless_helper() ? ATKLOG_ALMOSTALL : null)
var/fraction = min(amount_per_transfer_from_this/reagents.total_volume, 1)
reagents.reaction(L, INGEST, fraction)
diff --git a/code/modules/research/xenobiology/xenobio_camera.dm b/code/modules/research/xenobiology/xenobio_camera.dm
index b695ca3a1b4..2889a68c75b 100644
--- a/code/modules/research/xenobiology/xenobio_camera.dm
+++ b/code/modules/research/xenobiology/xenobio_camera.dm
@@ -217,8 +217,12 @@
var/obj/machinery/computer/camera_advanced/xenobio/X = target
if(cameranet.checkTurfVis(remote_eye.loc))
- if(X.monkeys >= 1)
+ if(LAZYLEN(SSmobs.cubemonkeys) >= config.cubemonkeycap)
+ to_chat(owner, "Bluespace harmonics prevent the spawning of more than [config.cubemonkeycap] monkeys on the station at one time!")
+ return
+ else if(X.monkeys >= 1)
var/mob/living/carbon/human/monkey/food = new /mob/living/carbon/human/monkey(remote_eye.loc)
+ SSmobs.cubemonkeys += food
food.LAssailant = C
X.monkeys --
to_chat(owner, "[X] now has [X.monkeys] monkeys left.")
diff --git a/config/example/config.txt b/config/example/config.txt
index 183f85437f0..7dfdc1e413a 100644
--- a/config/example/config.txt
+++ b/config/example/config.txt
@@ -439,6 +439,8 @@ HIGH_POP_MC_MODE_AMOUNT 65
##Disengage high pop mode if player count drops below this
DISABLE_HIGH_POP_MC_MODE_AMOUNT 60
+##Developer options
+
##Uncomment to enable developer start. Auto starts the server after initialization
##DEVELOPER_EXPRESS_START
@@ -447,3 +449,6 @@ DISABLE_HIGH_POP_MC_MODE_AMOUNT 60
## Uncomment to give a confirmation before hitting start now
#START_NOW_CONFIRMATION
+
+## If uncommented, all gamemodes will respect the number of required players. Defaults to no.
+#ENABLE_GAMEMODE_PLAYER_LIMIT
\ No newline at end of file
diff --git a/config/example/game_options.txt b/config/example/game_options.txt
index 31ee950243a..b05023098a1 100644
--- a/config/example/game_options.txt
+++ b/config/example/game_options.txt
@@ -72,4 +72,8 @@ ENABLE_NIGHT_SHIFTS
# a less lootfilled or smaller or less round effecting ruin costs less to
# spawn, while the converse is true. Alter this number to affect the amount
# of ruins.
-LAVALAND_BUDGET 60
\ No newline at end of file
+LAVALAND_BUDGET 60
+
+## Cube monkey limit
+# Amount of cube monkeys that can be spawned before the game limits them
+CUBEMONKEY_CAP 32
\ No newline at end of file
diff --git a/goon/browserassets/css/browserOutput-dark.css b/goon/browserassets/css/browserOutput-dark.css
index 426493dfc88..7a2c6123383 100644
--- a/goon/browserassets/css/browserOutput-dark.css
+++ b/goon/browserassets/css/browserOutput-dark.css
@@ -404,8 +404,8 @@ h1.alert, h2.alert {color: #FFF;}
/* MEGAFAUNA */
.colossus {color: #7F282A; font-size: 175%;}
-.hierophant {color: #660099; font-weight: bold; font-size: 150%;}
-.hierophant_warning {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #660099; font-style: italic;}
/* EMOJI STUFF */
.emoji {max-height: 16px; max-width: 16px}
@@ -413,3 +413,5 @@ h1.alert, h2.alert {color: #FFF;}
/* ADMIN TICKETS */
.adminticket {color: #3daf21; font-weight: bold}
+
+.adminticketalt {color: #ccb847; font-weight: bold}
diff --git a/goon/browserassets/css/browserOutput.css b/goon/browserassets/css/browserOutput.css
index 07ae914de62..87de7558ab9 100644
--- a/goon/browserassets/css/browserOutput.css
+++ b/goon/browserassets/css/browserOutput.css
@@ -401,12 +401,14 @@ h1.alert, h2.alert {color: #000000;}
/* MEGAFAUNA */
.colossus {color: #7F282A; font-size: 175%;}
-.hierophant {color: #660099; font-weight: bold; font-size: 150%;}
-.hierophant_warning {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant {color: #660099; font-weight: bold; font-style: italic;}
+.hierophant_warning {color: #660099; font-style: italic;}
/* EMOJI STUFF */
.emoji {max-height: 16px; max-width: 16px}
/* ADMIN TICKETS */
-.adminticket {color: #3daf21; font-weight: bold}
+.adminticket {color: #3e7336; font-weight: bold}
+
+.adminticketalt {color: #014c8a; font-weight: bold}
diff --git a/html/changelogs/AutoChangeLog-pr-11677.yml b/html/changelogs/AutoChangeLog-pr-11677.yml
new file mode 100644
index 00000000000..6a8dcdc1e24
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-11677.yml
@@ -0,0 +1,7 @@
+author: "Kyep"
+delete-after: True
+changes:
+ - bugfix: "Fixed bug that made the syndicate depot impossibly difficult."
+ - tweak: "Various improvements to syndi depot, such as use of plastitanium walls, and nerfs to some cheese strategies."
+ - rscadd: "Ported TG's simple_human.dmi, a sprite file of humanoid sprites (including syndicates)."
+ - rscadd: "Added a few extra syndi sprites from FoS."
diff --git a/html/changelogs/AutoChangeLog-pr-12183.yml b/html/changelogs/AutoChangeLog-pr-12183.yml
new file mode 100644
index 00000000000..cc6ebc526dd
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12183.yml
@@ -0,0 +1,4 @@
+author: "Emanthealmighty"
+delete-after: True
+changes:
+ - tweak: "Updated the netherworld creatures' sprites."
diff --git a/html/changelogs/AutoChangeLog-pr-12237.yml b/html/changelogs/AutoChangeLog-pr-12237.yml
new file mode 100644
index 00000000000..024cc25e5f7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12237.yml
@@ -0,0 +1,4 @@
+author: "variableundefined"
+delete-after: True
+changes:
+ - rscadd: "Config option to let gamemode ignore the number of required players."
diff --git a/html/changelogs/AutoChangeLog-pr-12278.yml b/html/changelogs/AutoChangeLog-pr-12278.yml
new file mode 100644
index 00000000000..242c925c3e4
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12278.yml
@@ -0,0 +1,4 @@
+author: "Shadow-Quill"
+delete-after: True
+changes:
+ - tweak: "Blobs now get a audio notification roundstart (like traitors do.)"
diff --git a/html/changelogs/AutoChangeLog-pr-12285.yml b/html/changelogs/AutoChangeLog-pr-12285.yml
new file mode 100644
index 00000000000..952df794846
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12285.yml
@@ -0,0 +1,4 @@
+author: "TDSSS"
+delete-after: True
+changes:
+ - tweak: "lowered attack log level of self-harm"
diff --git a/html/changelogs/AutoChangeLog-pr-12289.yml b/html/changelogs/AutoChangeLog-pr-12289.yml
new file mode 100644
index 00000000000..3f7723d5aed
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12289.yml
@@ -0,0 +1,4 @@
+author: "Ty-Omaha"
+delete-after: True
+changes:
+ - bugfix: "SSD players no longer drown in shallow water"
diff --git a/html/changelogs/AutoChangeLog-pr-12291.yml b/html/changelogs/AutoChangeLog-pr-12291.yml
new file mode 100644
index 00000000000..71c9a090ebb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12291.yml
@@ -0,0 +1,6 @@
+author: "Fox McCloud"
+delete-after: True
+changes:
+ - rscadd: "Hierophant has been updated--it'll be a bit tougher and will attempt to trap you if you run for it."
+ - tweak: "Heirophant is no longer a weird bird thing, but a massive, indecipherable piece of machinery that will make you dance to ITS tune"
+ - tweak: "Hierophant club is weaker up front, but becomes stronger the lower health you are"
diff --git a/html/changelogs/AutoChangeLog-pr-12293.yml b/html/changelogs/AutoChangeLog-pr-12293.yml
new file mode 100644
index 00000000000..ca16286dcf1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12293.yml
@@ -0,0 +1,4 @@
+author: "variableundefined"
+delete-after: True
+changes:
+ - rscadd: "Officer starter pack to cargo. For 30 cargo points you can equip an officer just like an officer closet! Backpack not included due to budget cut."
diff --git a/html/changelogs/AutoChangeLog-pr-12295.yml b/html/changelogs/AutoChangeLog-pr-12295.yml
new file mode 100644
index 00000000000..d9b6f07b340
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12295.yml
@@ -0,0 +1,5 @@
+author: "Kyep"
+delete-after: True
+changes:
+ - tweak: "Brig timers now display the job of brigged people. E.g. \"Joe Schmoe (Chemist) was incarcerated\" as opposed to just \"Joe Schmoe was incarcerated\"."
+ - rscadd: "Brig timers now notify a person's boss via PDA when they are incarcerated. E.g. if a chemist is temporarily brigged, the CMO is notified of the brigging via PDA."
diff --git a/html/changelogs/AutoChangeLog-pr-12296.yml b/html/changelogs/AutoChangeLog-pr-12296.yml
new file mode 100644
index 00000000000..ba0962cb610
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12296.yml
@@ -0,0 +1,6 @@
+author: "Couls"
+delete-after: True
+changes:
+ - rscadd: "configurable limit to amount of monkeys that can be spawned by monkey cubes"
+ - tweak: "handle_death is passed the gibbed variable"
+ - tweak: "spec_death replaced with handle_death in romerol"
diff --git a/html/changelogs/AutoChangeLog-pr-12298.yml b/html/changelogs/AutoChangeLog-pr-12298.yml
new file mode 100644
index 00000000000..154c7092b45
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12298.yml
@@ -0,0 +1,6 @@
+author: "Ty-Omaha"
+delete-after: True
+changes:
+ - rscadd: "Admins can now autoreply with common answers to common questions / issues."
+ - soundadd: "Opening an adminhelp/mentorhelp ticket will play a sound"
+ - tweak: "Adminhelp ticket information color changed from neon green to a more toned down green"
diff --git a/html/changelogs/AutoChangeLog-pr-12300.yml b/html/changelogs/AutoChangeLog-pr-12300.yml
new file mode 100644
index 00000000000..4495825a34c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12300.yml
@@ -0,0 +1,4 @@
+author: "kazboo"
+delete-after: True
+changes:
+ - bugfix: "candle boxes on the station are now properly filled"
diff --git a/html/changelogs/AutoChangeLog-pr-12302.yml b/html/changelogs/AutoChangeLog-pr-12302.yml
new file mode 100644
index 00000000000..b54ccd292eb
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12302.yml
@@ -0,0 +1,4 @@
+author: "TDSSS"
+delete-after: True
+changes:
+ - tweak: "certain harmless chems and food have reduced attack log logging levels"
diff --git a/html/changelogs/AutoChangeLog-pr-12303.yml b/html/changelogs/AutoChangeLog-pr-12303.yml
new file mode 100644
index 00000000000..9790e520eff
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12303.yml
@@ -0,0 +1,6 @@
+author: "TheMadTrickster"
+delete-after: True
+changes:
+ - bugfix: "fixed wonky/bugged sprites for custom guitar and hair gel"
+ - rscadd: "new improved clean sprites for custom items"
+ - rscdel: "old messy sprites for custom items"
diff --git a/html/changelogs/AutoChangeLog-pr-12304.yml b/html/changelogs/AutoChangeLog-pr-12304.yml
new file mode 100644
index 00000000000..fdadcf8dd3d
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12304.yml
@@ -0,0 +1,4 @@
+author: "Fox McCloud"
+delete-after: True
+changes:
+ - bugfix: "Fixes tendrils spawning inside ruins"
diff --git a/html/changelogs/AutoChangeLog-pr-12307.yml b/html/changelogs/AutoChangeLog-pr-12307.yml
new file mode 100644
index 00000000000..c0c4d6c6a22
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12307.yml
@@ -0,0 +1,4 @@
+author: "Fox McCloud"
+delete-after: True
+changes:
+ - bugfix: "Fixes light replacers breaking/hitting lights"
diff --git a/html/changelogs/AutoChangeLog-pr-12311.yml b/html/changelogs/AutoChangeLog-pr-12311.yml
new file mode 100644
index 00000000000..85cec632477
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12311.yml
@@ -0,0 +1,4 @@
+author: "Ty-Omaha"
+delete-after: True
+changes:
+ - tweak: "Global admin midis will now silence lobby music for those who have midis enabled."
diff --git a/html/changelogs/AutoChangeLog-pr-12313.yml b/html/changelogs/AutoChangeLog-pr-12313.yml
new file mode 100644
index 00000000000..171b66fae2e
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12313.yml
@@ -0,0 +1,5 @@
+author: "Ionward"
+delete-after: True
+changes:
+ - bugfix: "Plasmamen Librarians now have visible helmets."
+ - bugfix: "Atmos Hardsuits now have inhand sprites again."
diff --git a/html/changelogs/AutoChangeLog-pr-12315.yml b/html/changelogs/AutoChangeLog-pr-12315.yml
new file mode 100644
index 00000000000..55889b64637
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12315.yml
@@ -0,0 +1,4 @@
+author: "TDSSS"
+delete-after: True
+changes:
+ - bugfix: "the most grave of wrong tips"
diff --git a/html/changelogs/AutoChangeLog-pr-12316.yml b/html/changelogs/AutoChangeLog-pr-12316.yml
new file mode 100644
index 00000000000..5753740f092
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12316.yml
@@ -0,0 +1,5 @@
+author: "SteelSlayer"
+delete-after: True
+changes:
+ - bugfix: "Fixes a runtime preventing walls from being repaired properly"
+ - rscadd: "Adds the ability to repair and remove bullet holes from reinforced walls that have no structural damage"
diff --git a/html/changelogs/AutoChangeLog-pr-12318.yml b/html/changelogs/AutoChangeLog-pr-12318.yml
new file mode 100644
index 00000000000..4d909a474ab
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12318.yml
@@ -0,0 +1,4 @@
+author: "Dave-TH"
+delete-after: True
+changes:
+ - bugfix: "Magical weapons can now be properly dual-wielded."
diff --git a/html/changelogs/AutoChangeLog-pr-12320.yml b/html/changelogs/AutoChangeLog-pr-12320.yml
new file mode 100644
index 00000000000..aab73091f37
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12320.yml
@@ -0,0 +1,5 @@
+author: "Fox McCloud"
+delete-after: True
+changes:
+ - bugfix: "Fixes blood drunk buff not making you slow immune"
+ - rscadd: "Regenerative core will give you 1 minute of slow immunity on application"
diff --git a/html/changelogs/AutoChangeLog-pr-12321.yml b/html/changelogs/AutoChangeLog-pr-12321.yml
new file mode 100644
index 00000000000..d7343993f95
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12321.yml
@@ -0,0 +1,4 @@
+author: "Dave-TH"
+delete-after: True
+changes:
+ - bugfix: "Fixes the description of energy shields, which said they block things that they do not."
diff --git a/html/changelogs/AutoChangeLog-pr-12328.yml b/html/changelogs/AutoChangeLog-pr-12328.yml
new file mode 100644
index 00000000000..eb42442208b
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-12328.yml
@@ -0,0 +1,4 @@
+author: "Couls"
+delete-after: True
+changes:
+ - bugfix: "recycled monkeys were not being subtracted from the monkey cap"
diff --git a/icons/effects/effects.dmi b/icons/effects/effects.dmi
index 89f57b2517d..7e1bb227ef3 100644
Binary files a/icons/effects/effects.dmi and b/icons/effects/effects.dmi differ
diff --git a/icons/mob/animal.dmi b/icons/mob/animal.dmi
index 6666d3cf4d2..b11298ab66e 100644
Binary files a/icons/mob/animal.dmi and b/icons/mob/animal.dmi differ
diff --git a/icons/mob/back.dmi b/icons/mob/back.dmi
index 36025c083b4..2e3c9f7cae0 100644
Binary files a/icons/mob/back.dmi and b/icons/mob/back.dmi differ
diff --git a/icons/mob/head.dmi b/icons/mob/head.dmi
index 0fe42126ef0..97134b52a3a 100644
Binary files a/icons/mob/head.dmi and b/icons/mob/head.dmi differ
diff --git a/icons/mob/inhands/64x64_lefthand.dmi b/icons/mob/inhands/64x64_lefthand.dmi
index 69b9922f140..f0b5ec6f0e7 100644
Binary files a/icons/mob/inhands/64x64_lefthand.dmi and b/icons/mob/inhands/64x64_lefthand.dmi differ
diff --git a/icons/mob/inhands/64x64_righthand.dmi b/icons/mob/inhands/64x64_righthand.dmi
index 09cef64e2b0..36f930193d2 100644
Binary files a/icons/mob/inhands/64x64_righthand.dmi and b/icons/mob/inhands/64x64_righthand.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_lefthand.dmi b/icons/mob/inhands/equipment/instruments_lefthand.dmi
index 4ffaa7d8c05..225f1768d99 100644
Binary files a/icons/mob/inhands/equipment/instruments_lefthand.dmi and b/icons/mob/inhands/equipment/instruments_lefthand.dmi differ
diff --git a/icons/mob/inhands/equipment/instruments_righthand.dmi b/icons/mob/inhands/equipment/instruments_righthand.dmi
index 68899a4a7db..cc1df97183a 100644
Binary files a/icons/mob/inhands/equipment/instruments_righthand.dmi and b/icons/mob/inhands/equipment/instruments_righthand.dmi differ
diff --git a/icons/mob/inhands/fluff_lefthand.dmi b/icons/mob/inhands/fluff_lefthand.dmi
index c2604c8b57c..0415f69679f 100644
Binary files a/icons/mob/inhands/fluff_lefthand.dmi and b/icons/mob/inhands/fluff_lefthand.dmi differ
diff --git a/icons/mob/inhands/fluff_righthand.dmi b/icons/mob/inhands/fluff_righthand.dmi
index b75a67a7d8e..1ccd153af00 100644
Binary files a/icons/mob/inhands/fluff_righthand.dmi and b/icons/mob/inhands/fluff_righthand.dmi differ
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 7d0961fc449..3a0c32e68b4 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 5850e4d8d8c..6cf43537d88 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/mob/lavaland/hierophant_new.dmi b/icons/mob/lavaland/hierophant_new.dmi
new file mode 100644
index 00000000000..84348700324
Binary files /dev/null and b/icons/mob/lavaland/hierophant_new.dmi differ
diff --git a/icons/mob/screen_alert.dmi b/icons/mob/screen_alert.dmi
index 2b29cad5b0c..2fe2c7cd21c 100644
Binary files a/icons/mob/screen_alert.dmi and b/icons/mob/screen_alert.dmi differ
diff --git a/icons/mob/simple_human.dmi b/icons/mob/simple_human.dmi
new file mode 100644
index 00000000000..9ab1c9a1796
Binary files /dev/null and b/icons/mob/simple_human.dmi differ
diff --git a/icons/mob/species/plasmaman/helmet.dmi b/icons/mob/species/plasmaman/helmet.dmi
index ebcb096aa7b..88c3e51c70c 100644
Binary files a/icons/mob/species/plasmaman/helmet.dmi and b/icons/mob/species/plasmaman/helmet.dmi differ
diff --git a/icons/mob/sprite_accessories/human/human_hair.dmi b/icons/mob/sprite_accessories/human/human_hair.dmi
index 4534c797cc3..7085dd1ff4e 100644
Binary files a/icons/mob/sprite_accessories/human/human_hair.dmi and b/icons/mob/sprite_accessories/human/human_hair.dmi differ
diff --git a/icons/mob/suit.dmi b/icons/mob/suit.dmi
index 1427b5aaf10..9bcabb11e78 100644
Binary files a/icons/mob/suit.dmi and b/icons/mob/suit.dmi differ
diff --git a/icons/obj/clothing/species/plasmaman/hats.dmi b/icons/obj/clothing/species/plasmaman/hats.dmi
index 60282c030fe..3a24c20bd93 100644
Binary files a/icons/obj/clothing/species/plasmaman/hats.dmi and b/icons/obj/clothing/species/plasmaman/hats.dmi differ
diff --git a/icons/obj/custom_items.dmi b/icons/obj/custom_items.dmi
index 9315f8223af..b632964978d 100644
Binary files a/icons/obj/custom_items.dmi and b/icons/obj/custom_items.dmi differ
diff --git a/icons/obj/lavaland/artefacts.dmi b/icons/obj/lavaland/artefacts.dmi
index 8e91b20368f..bc95bbc1fe3 100644
Binary files a/icons/obj/lavaland/artefacts.dmi and b/icons/obj/lavaland/artefacts.dmi differ
diff --git a/icons/turf/floors/hierophant_floor.dmi b/icons/turf/floors/hierophant_floor.dmi
new file mode 100644
index 00000000000..365f887bfa4
Binary files /dev/null and b/icons/turf/floors/hierophant_floor.dmi differ
diff --git a/icons/turf/walls/hierophant_wall.dmi b/icons/turf/walls/hierophant_wall.dmi
index c51880ddef2..8963db4e996 100644
Binary files a/icons/turf/walls/hierophant_wall.dmi and b/icons/turf/walls/hierophant_wall.dmi differ
diff --git a/sound/effects/adminticketopen.ogg b/sound/effects/adminticketopen.ogg
new file mode 100644
index 00000000000..82e0729d881
Binary files /dev/null and b/sound/effects/adminticketopen.ogg differ
diff --git a/strings/tips.txt b/strings/tips.txt
index 5237b9ab547..b2df1c17482 100644
--- a/strings/tips.txt
+++ b/strings/tips.txt
@@ -182,7 +182,7 @@ As a Devil, you gain power for every three souls you control, however you also b
As a Devil, as long as you control at least one other soul, you will automatically resurrect, as long as a banishment ritual is not performed.
At which time a Devil's nameth is spake on the tongue of man, the Devil may appeareth.
As a Security Officer, remember that correlation does not equal causation. Someone may have just been at the wrong place at the wrong time!
-As a Security Officer, remember that you can attach a sec-lite to your taser or your helmet!
+As a Security Officer, remember that you can attach a sec-lite to your taser!
As a Terror Spider, leave wrapping of corpses to green spiders unless absolutely necessary. They need it to lay eggs!
As a Prince of Terror, you are powerful but usually on your own. Consider hit and run tactics to regenerate your health between engagements.
As a Brown Terror Spider, focus on smashing welded vents. You are weak in direct combat, but you can enable your comrades to go almost anywhere.