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
diff --git a/icons/mob/inhands/equipment/security_righthand.dmi b/icons/mob/inhands/equipment/security_righthand.dmi
index 7d8787e3fe68e642d6bb1374d5562b8ca100671f..c6d26854eb6dacddbe6f0e33ba59dd6674c52a79 100644
GIT binary patch
literal 10396
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
literal 3400
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
PYXn$X*g`R9-5>o6fa6I`
diff --git a/icons/obj/weapons/baton.dmi b/icons/obj/weapons/baton.dmi
index 2d5100ec4d414e571ef40938d318d3a3e5fb90b3..6b7cbd8544ac36c737b2b43be79a94bbe4909918 100644
GIT binary patch
literal 3836
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
Q{hb9&jm!-z3~q(~2S5p`q5uE@
literal 3005
zcmV;u3qtgXP)004jp1^@s6jALRO0002IdQ@0+L}hbh
za%pgMX>V=-0C=30jX?^7Fc3x8$teciN~u=pDx0Dd7kULrWY5=dv}aHS{jZO000WSNklZEO_R6^7r1
z1evOcVjQnY3o2@48R5Ee)fQAmT|+C?s)U*q*j}&{c~K)`tf-BZl2sz=xCrE;NTmgT
zsZ#7eA&Wx`6;kB(2l7Hy1vRP(qK&mpvS2_9#4%Qd)i~%E&h*DKm
zg;*>`eJIiuYT8NqLzj*32?J`)H!v{Zqdp#)3N`IiDl02(%Xhs2*?g6Vof}ya2n3{`
z`vU(@6}?7$R~wMcH(z}9Yropxp~xD?TJxhU+J+02-Fp0|WE>2I*nFwt1HgsK?!Ygf
zZH>p{h@N;)__fI312E#dvIDaD%oSf6{|9wXjQFlIAe+y8@rCg(|gO9?^pLYk;n$Pd|BbiJ}Hy<$HdB?`aq?_+Ruu*xw<}uoKFIy-C75~-J(kFo2
zHJ>iOh|Zgr0n^QQ@!~}c4-ZQ?C23?)zxl$f5((68-puApU3}(S
zD_sND*VikdPzXpQFbH_wd`64xcs$PhB4s#&W3drU!s{_GC1%T8AznA&8
zG9b%)a>WNyS-M=ri=
zUdzm-z{cJllttT61_Ult_QW3iVXsX7@V;FN0Ms8oF75V8s_1nM?f$pctXqfhF37&M
zbGx>@^F%|tztM;nqCeW@wv~Pf%;k
z_m?gI0RSB8>XY{AZ4JM1=#^WBeBlOM$cHP7wo!~g-F&)D@itk&R)JI1DRpI
zmd}2O-~IF-0Dy+=&5G!8oX-FGpTBF!7iz$a_g2fIZTQBwMIy8FRZWJvWsKl-^IgCH
z2nVBQWQ@TK^EDpzL+ykjm0I`hHOm)fK%|d>}HD7IcXTYfV
z<%e(L)AN;YjZSoke3ARMI(D`Ep;vC{@`Y?d-0;SJF(T}I3oA{2smb|Gk1X?L;ST}m(c@b-f}NhyRIKb~zW)9$pSs(WVZ3a70M8g5
zgC!l1y7-I6e(HXo*UcxBT@1hI4rr@2A5hfTSD#h@=AT%w`HJHgWk6f5`3mIs?hYzj
ztJeYm5;rGJ{Tnu4@%(~!!ERjhsm4o8&MxYPdSdfg!!O8yr-MNyH1~jP&9}g}aO_{d
z{|M*DXK?oNHEgY3i}e*{h9+e5S;x=YfL79c=FYs~|E>pRQQ{mvYs%Sxn1go)_urLnJ`sFVBUsG}Q6n4FXs+H%B~~1RE%|!m7@##@>FNqh|946jRti6-0o|TY
zmrdy=q&DAY@qc6H?j5P!Pc%QP0lkn_}ZeU|K4f*j5XkVKHOb|<{lLK
zJ&O`GAD}fK0IXOFQ^g17JCL>`IgOt&g1wecmoD|aT`KdbQj4k8+!;0xV^WaiWTMCz>#3Vv;Q=Z?{dj+0dUv}3V7Ut|ZgOFo@c
zzMlDH@wJ`TDc9dp1FEBsBA+gOsMx_vC=Z#J$%
z#Px7$T!$qiI2WAKd?^X(cxL$`mmFsJqE!sPXahRoX5513Km6GvD6)f<~}gPM-Pn{Jd_%X!GH&CTR2NnC}k0X#;BW;b!jM
zAvt;GyN_>b1iLw(j`_6woCfq#P!99u^RpVz?I+KCdcL6ny>Rl(r|0V$&?_g;e0qMy
zF4$}Nbj+va>pltbQa&B?Y5BS%*h~3z%%|n+8gL-`u5ZQC#jUnsdnP;_YF4a1dFFeI
zpYy{AZqKJKtbSxIBEPW}-iK?rsqdo*ri#s5TRBS*NsiYY2P*maO>He3m&0&j*xUd}=-`
zKMBnTwDNm9fzQfcmUTet;#2ckg-J?2plDI^S%u5C`G97hTCn+?t)dJlviMgMS8|$=
z&F6d-Y(UY)@9*#Oy%BlYXJkS)pF3pxe84v%FZ=fFi7YZ9o6kLRL_T1Df0u91o`^E{
zcm@=FmN=R2fa)9bt5%mnSpw
Date: Tue, 21 Jan 2025 23:26:21 +0000
Subject: [PATCH 18/35] Automatic changelog for PR #88830 [ci skip]
---
html/changelogs/AutoChangeLog-pr-88830.yml | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-88830.yml
diff --git a/html/changelogs/AutoChangeLog-pr-88830.yml b/html/changelogs/AutoChangeLog-pr-88830.yml
new file mode 100644
index 0000000000000..a55f9e30c3bd1
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-88830.yml
@@ -0,0 +1,7 @@
+author: "necromanceranne"
+delete-after: True
+changes:
+ - balance: "Batons now respect the armor worn by targets. Analog batons respect MELEE armor. Cell-type batons respect ENERGY armor."
+ - balance: "Various batons have differing amounts of armour penetration based on what type of baton it is."
+ - balance: "Heads of staff have color graded batons to denote penetration power. Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent to Gold."
+ - balance: "Cell-type batons gain armor penetration based on their cell's quality. The better it is, the more it penetrates."
\ No newline at end of file
From cb2bbbeb2cc8460ac96ed58b60c14179f1119f3e Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 00:27:44 +0000
Subject: [PATCH 19/35] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-88830.yml | 7 -------
html/changelogs/AutoChangeLog-pr-89113.yml | 4 ----
html/changelogs/AutoChangeLog-pr-89141.yml | 4 ----
html/changelogs/AutoChangeLog-pr-89143.yml | 4 ----
html/changelogs/AutoChangeLog-pr-89144.yml | 4 ----
html/changelogs/AutoChangeLog-pr-89148.yml | 4 ----
html/changelogs/archive/2025-01.yml | 24 ++++++++++++++++++++++
7 files changed, 24 insertions(+), 27 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-88830.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-89113.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-89141.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-89143.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-89144.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-89148.yml
diff --git a/html/changelogs/AutoChangeLog-pr-88830.yml b/html/changelogs/AutoChangeLog-pr-88830.yml
deleted file mode 100644
index a55f9e30c3bd1..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-88830.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: "necromanceranne"
-delete-after: True
-changes:
- - balance: "Batons now respect the armor worn by targets. Analog batons respect MELEE armor. Cell-type batons respect ENERGY armor."
- - balance: "Various batons have differing amounts of armour penetration based on what type of baton it is."
- - balance: "Heads of staff have color graded batons to denote penetration power. Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent to Gold."
- - balance: "Cell-type batons gain armor penetration based on their cell's quality. The better it is, the more it penetrates."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-89113.yml b/html/changelogs/AutoChangeLog-pr-89113.yml
deleted file mode 100644
index a11767ec7085f..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-89113.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "kuricityy"
-delete-after: True
-changes:
- - bugfix: "Blob's can no longer place their core in ruins on Icebox."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-89141.yml b/html/changelogs/AutoChangeLog-pr-89141.yml
deleted file mode 100644
index a7315cab3523a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-89141.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - bugfix: "pockets update their icons correctly when removing items that have storage (e.g. box of bandages) from them"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-89143.yml b/html/changelogs/AutoChangeLog-pr-89143.yml
deleted file mode 100644
index 9edd1450dccd6..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-89143.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "the-og-gear"
-delete-after: True
-changes:
- - bugfix: "Deluxe Donk Pockets (and their no-carb and vegan variants) are no longer craftable without collecting the recipe."
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-89144.yml b/html/changelogs/AutoChangeLog-pr-89144.yml
deleted file mode 100644
index f0551ec98139a..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-89144.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "SyncIt21"
-delete-after: True
-changes:
- - bugfix: "fishing rod auto reel won't rip of intercoms or other anchored/immovable objects"
\ No newline at end of file
diff --git a/html/changelogs/AutoChangeLog-pr-89148.yml b/html/changelogs/AutoChangeLog-pr-89148.yml
deleted file mode 100644
index ebd628d99c136..0000000000000
--- a/html/changelogs/AutoChangeLog-pr-89148.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: "necromanceranne"
-delete-after: True
-changes:
- - bugfix: "The Big Bess cargo hauler no longer magically becomes (visually) a standard Ripley exosuit."
\ No newline at end of file
diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml
index f1115177d0d77..0fca94159883d 100644
--- a/html/changelogs/archive/2025-01.yml
+++ b/html/changelogs/archive/2025-01.yml
@@ -559,3 +559,27 @@
Rhials:
- rscadd: You can now ctrl-click IDs to set your Honorific, which will change your
display name to reflect your TITLE as a WORKING MAN on SPACE STATION 13.
+2025-01-22:
+ SyncIt21:
+ - bugfix: pockets update their icons correctly when removing items that have storage
+ (e.g. box of bandages) from them
+ - bugfix: fishing rod auto reel won't rip of intercoms or other anchored/immovable
+ objects
+ kuricityy:
+ - bugfix: Blob's can no longer place their core in ruins on Icebox.
+ necromanceranne:
+ - balance: Batons now respect the armor worn by targets. Analog batons respect MELEE
+ armor. Cell-type batons respect ENERGY armor.
+ - balance: Various batons have differing amounts of armour penetration based on
+ what type of baton it is.
+ - balance: Heads of staff have color graded batons to denote penetration power.
+ Bronze (Quartermaster), Silver (Chief Engineer, Chief Medical Officer, Head
+ of Personnel, Research Director), Gold (Captain). Contractor batons are equivalent
+ to Gold.
+ - balance: Cell-type batons gain armor penetration based on their cell's quality.
+ The better it is, the more it penetrates.
+ - bugfix: The Big Bess cargo hauler no longer magically becomes (visually) a standard
+ Ripley exosuit.
+ the-og-gear:
+ - bugfix: Deluxe Donk Pockets (and their no-carb and vegan variants) are no longer
+ craftable without collecting the recipe.
From c5396ab66cae51b2ecc8442172a7ae477f31be7e Mon Sep 17 00:00:00 2001
From: Jacquerel
Date: Wed, 22 Jan 2025 01:36:13 +0000
Subject: [PATCH 20/35] Basic Mob Zombies (#89153)
## About The Pull Request
Simple to Basic ruin zombies.
Zombies are about as simple as you can get so I am surprised they
weren't converted already.
I didn't make any particular changes, except canonising a commonly-used
map varedit into a subtype and made them groan occasionally.
It's a little weird that the default zombie wears a doctor's outfit but
no point changing it until/unless it actually causes a problem.
## Why It's Good For The Game
2025 year of no more simple animals.
## Changelog
:cl:
refactor: NPC zombies found in ruins now use the basic mob framework.
Please make an issue report if they exhibit any unusual behaviour.
/:cl:
---
_maps/RandomRuins/SpaceRuins/interdyne.dmm | 12 +--
_maps/RandomRuins/SpaceRuins/meatderelict.dmm | 2 +-
.../map_files/NebulaStation/NebulaStation.dmm | 16 +---
_maps/shuttles/whiteship_box.dmm | 38 +-------
_maps/shuttles/whiteship_personalshuttle.dmm | 30 +-----
_maps/virtual_domains/psyker_zombies.dmm | 2 +-
code/_globalvars/phobias.dm | 2 +-
.../mob/living/basic/ruin_defender/zombie.dm | 93 +++++++++++++++++++
.../living/simple_animal/hostile/zombie.dm | 51 ----------
.../unit_tests/simple_animal_freeze.dm | 1 -
tgstation.dme | 2 +-
.../Scripts/89153_simple_to_basic_zombies.txt | 3 +
12 files changed, 116 insertions(+), 136 deletions(-)
create mode 100644 code/modules/mob/living/basic/ruin_defender/zombie.dm
delete mode 100644 code/modules/mob/living/simple_animal/hostile/zombie.dm
create mode 100644 tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt
diff --git a/_maps/RandomRuins/SpaceRuins/interdyne.dmm b/_maps/RandomRuins/SpaceRuins/interdyne.dmm
index 46e22d19fb67b..b115c323a356e 100644
--- a/_maps/RandomRuins/SpaceRuins/interdyne.dmm
+++ b/_maps/RandomRuins/SpaceRuins/interdyne.dmm
@@ -104,7 +104,7 @@
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
"eJ" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/obj/structure/cable,
@@ -496,7 +496,7 @@
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
"uy" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
"vd" = (
@@ -656,7 +656,7 @@
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/space/has_grav/interdyne)
"By" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2,
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/space/has_grav/interdyne)
@@ -672,7 +672,7 @@
/turf/open/floor/iron/smooth,
/area/ruin/space/has_grav/interdyne)
"DA" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4,
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
@@ -719,7 +719,7 @@
/area/ruin/space/has_grav/interdyne)
"Ft" = (
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/obj/structure/cable,
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
@@ -732,7 +732,7 @@
/turf/open/floor/mineral/plastitanium/red,
/area/ruin/space/has_grav/interdyne)
"FC" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/obj/structure/cable,
/turf/open/floor/mineral/plastitanium,
/area/ruin/space/has_grav/interdyne)
diff --git a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
index 96959954e2678..e3cdb52cad39e 100644
--- a/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
+++ b/_maps/RandomRuins/SpaceRuins/meatderelict.dmm
@@ -1008,7 +1008,7 @@
/area/ruin/space/has_grav/powered/biooutpost)
"tv" = (
/obj/effect/decal/cleanable/blood/tracks,
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/turf/open/indestructible/white{
icon_state = "showroomfloor"
},
diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm
index a0a228bf5fe86..a386fe33b1a97 100644
--- a/_maps/map_files/NebulaStation/NebulaStation.dmm
+++ b/_maps/map_files/NebulaStation/NebulaStation.dmm
@@ -81457,12 +81457,6 @@
/obj/item/reagent_containers/cup/rag,
/turf/open/floor/iron/white/textured_large,
/area/station/maintenance/department/medical)
-"mdT" = (
-/obj/structure/disposalpipe/segment{
- dir = 4
- },
-/turf/closed/wall,
-/area/station/maintenance/fore/lesser)
"mec" = (
/obj/effect/turf_decal/siding/wood{
dir = 6
@@ -118778,10 +118772,6 @@
/obj/effect/turf_decal/siding/thinplating_new/dark/corner,
/turf/open/floor/iron/dark/herringbone,
/area/station/service/chapel/funeral)
-"rDY" = (
-/obj/structure/disposalpipe/segment,
-/turf/closed/wall,
-/area/station/maintenance/fore/greater)
"rEc" = (
/obj/effect/turf_decal/stripes/line{
dir = 5
@@ -196595,7 +196585,7 @@ fQE
cUZ
xGl
pjP
-mdT
+iEt
xnA
pQW
hAK
@@ -266242,7 +266232,7 @@ bzt
jkE
nLg
cij
-rDY
+bYy
loK
kCi
nKp
@@ -294174,4 +294164,4 @@ txW
txW
txW
txW
-"}
\ No newline at end of file
+"}
diff --git a/_maps/shuttles/whiteship_box.dmm b/_maps/shuttles/whiteship_box.dmm
index 9a20e38ebcd5d..c800243246908 100644
--- a/_maps/shuttles/whiteship_box.dmm
+++ b/_maps/shuttles/whiteship_box.dmm
@@ -273,15 +273,7 @@
dir = 9
},
/obj/structure/cable,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass";
- outfit = /datum/outfit/corpse_assistant
- },
+/mob/living/basic/zombie/rotten/assistant,
/turf/open/floor/iron/white/corner{
dir = 1
},
@@ -360,14 +352,7 @@
/obj/effect/decal/cleanable/blood/old,
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass"
- },
+/mob/living/basic/zombie/rotten,
/turf/open/floor/iron,
/area/shuttle/abandoned/crew)
"aQ" = (
@@ -841,14 +826,7 @@
},
/obj/effect/decal/cleanable/blood/old,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass"
- },
+/mob/living/basic/zombie/rotten,
/turf/open/floor/iron,
/area/shuttle/abandoned/medbay)
"bT" = (
@@ -1449,15 +1427,7 @@
},
/obj/effect/decal/cleanable/blood/gibs/old,
/obj/structure/cable,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass";
- outfit = /datum/outfit/corpse_assistant
- },
+/mob/living/basic/zombie/rotten/assistant,
/turf/open/floor/iron,
/area/shuttle/abandoned/medbay)
"dc" = (
diff --git a/_maps/shuttles/whiteship_personalshuttle.dmm b/_maps/shuttles/whiteship_personalshuttle.dmm
index 7666f6c63add1..0316e7f3aeab0 100644
--- a/_maps/shuttles/whiteship_personalshuttle.dmm
+++ b/_maps/shuttles/whiteship_personalshuttle.dmm
@@ -162,15 +162,7 @@
/obj/structure/cable,
/obj/effect/decal/cleanable/blood/splatter,
/obj/effect/decal/cleanable/dirt,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass";
- outfit = /datum/outfit/corpse_assistant
- },
+/mob/living/basic/zombie/rotten/assistant,
/turf/open/floor/mineral/titanium,
/area/shuttle/abandoned/engine)
"gG" = (
@@ -195,15 +187,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/structure/cable,
/obj/effect/decal/cleanable/blood/splatter,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass";
- outfit = /datum/outfit/corpse_assistant
- },
+/mob/living/basic/zombie/rotten/assistant,
/turf/open/floor/plating,
/area/shuttle/abandoned/engine)
"nI" = (
@@ -260,15 +244,7 @@
/obj/effect/decal/cleanable/dirt,
/obj/effect/decal/cleanable/blood/splatter,
/obj/structure/chair/comfy/shuttle,
-/mob/living/simple_animal/hostile/zombie{
- desc = "This undead fiend looks to be badly decomposed.";
- environment_smash = 0;
- health = 60;
- melee_damage_lower = 11;
- melee_damage_upper = 11;
- name = "Rotting Carcass";
- outfit = /datum/outfit/corpse_assistant
- },
+/mob/living/basic/zombie/rotten/assistant,
/turf/open/floor/mineral/plastitanium,
/area/shuttle/abandoned/bridge)
"pS" = (
diff --git a/_maps/virtual_domains/psyker_zombies.dmm b/_maps/virtual_domains/psyker_zombies.dmm
index 4ca97f8ef6315..c532e87189f9c 100644
--- a/_maps/virtual_domains/psyker_zombies.dmm
+++ b/_maps/virtual_domains/psyker_zombies.dmm
@@ -114,7 +114,7 @@
/turf/open/indestructible/dark,
/area/virtual_domain)
"X" = (
-/mob/living/simple_animal/hostile/zombie,
+/mob/living/basic/zombie,
/turf/open/indestructible/dark,
/area/virtual_domain)
"Y" = (
diff --git a/code/_globalvars/phobias.dm b/code/_globalvars/phobias.dm
index d6677a213a48a..6c93c07bbb83a 100644
--- a/code/_globalvars/phobias.dm
+++ b/code/_globalvars/phobias.dm
@@ -107,9 +107,9 @@ GLOBAL_LIST_INIT(phobia_mobs, list(
/mob/living/basic/shade,
/mob/living/basic/skeleton,
/mob/living/basic/wizard,
+ /mob/living/basic/zombie,
/mob/living/simple_animal/bot/mulebot/paranormal,
/mob/living/simple_animal/hostile/dark_wizard,
- /mob/living/simple_animal/hostile/zombie,
)),
))
diff --git a/code/modules/mob/living/basic/ruin_defender/zombie.dm b/code/modules/mob/living/basic/ruin_defender/zombie.dm
new file mode 100644
index 0000000000000..b77920af8d154
--- /dev/null
+++ b/code/modules/mob/living/basic/ruin_defender/zombie.dm
@@ -0,0 +1,93 @@
+/// Everyone knows what a zombie is
+/mob/living/basic/zombie
+ name = "Shambling Corpse"
+ desc = "When there is no more room in hell, the dead will walk in outer space."
+ icon = 'icons/mob/simple/simple_human.dmi'
+ mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
+ sentience_type = SENTIENCE_HUMANOID
+ maxHealth = 100
+ health = 100
+ melee_damage_lower = 21
+ melee_damage_upper = 21
+ attack_verb_continuous = "bites"
+ attack_verb_simple = "bite"
+ attack_sound = 'sound/effects/hallucinations/growl1.ogg'
+ attack_vis_effect = ATTACK_EFFECT_BITE
+ combat_mode = TRUE
+ speed = 4
+ status_flags = CANPUSH
+ death_message = "rapidly decays into a pile of bones!"
+ unsuitable_atmos_damage = 0
+ unsuitable_cold_damage = 0
+ faction = list(FACTION_HOSTILE)
+ basic_mob_flags = DEL_ON_DEATH
+ ai_controller = /datum/ai_controller/basic_controller/zombie
+ /// Outfit the zombie spawns with for visuals.
+ var/outfit = /datum/outfit/corpse_doctor
+ /// Chance to spread zombieism on hit
+ /// Only for admins because we don't actually want romerol to get into the round from space ruins generally speaking
+ var/infection_chance = 0
+
+/mob/living/basic/zombie/Initialize(mapload)
+ . = ..()
+ apply_dynamic_human_appearance(src, outfit, /datum/species/zombie, bloody_slots = ITEM_SLOT_OCLOTHING)
+ AddElement(/datum/element/death_drops, string_list(list(/obj/effect/decal/remains/human)))
+
+/mob/living/basic/zombie/melee_attack(atom/target, list/modifiers, ignore_cooldown)
+ . = ..()
+ if (!. || !infection_chance || !ishuman(target) || !prob(infection_chance))
+ return
+ try_to_zombie_infect(target)
+
+/// Weaker variant used if you want to put more of them in one place, won't attack obstacles
+/mob/living/basic/zombie/rotten
+ name = "Rotting Carcass"
+ desc = "This undead fiend looks to be badly decomposed."
+ health = 60
+ melee_damage_lower = 11
+ melee_damage_upper = 11
+ ai_controller = /datum/ai_controller/basic_controller/zombie/stupid
+
+/mob/living/basic/zombie/rotten/assistant
+ outfit = /datum/outfit/corpse_assistant
+
+/datum/outfit/corpse_doctor
+ name = "Corpse Doctor"
+ suit = /obj/item/clothing/suit/toggle/labcoat
+ uniform = /obj/item/clothing/under/rank/medical/doctor
+ shoes = /obj/item/clothing/shoes/sneakers/white
+ back = /obj/item/storage/backpack/medic
+
+/datum/outfit/corpse_assistant
+ name = "Corpse Assistant"
+ mask = /obj/item/clothing/mask/gas
+ uniform = /obj/item/clothing/under/color/grey
+ shoes = /obj/item/clothing/shoes/sneakers/black
+ back = /obj/item/storage/backpack
+
+/datum/ai_planning_subtree/random_speech/zombie
+ speech_chance = 1
+ emote_hear = list("groans.", "moans.", "grunts.")
+ emote_see = list("twitches.", "shudders.")
+
+/datum/ai_controller/basic_controller/zombie
+ blackboard = list(
+ BB_TARGET_MINIMUM_STAT = HARD_CRIT,
+ BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic,
+ )
+
+ ai_movement = /datum/ai_movement/basic_avoidance
+ idle_behavior = /datum/idle_behavior/idle_random_walk
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/zombie,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/attack_obstacle_in_path,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
+ )
+
+/datum/ai_controller/basic_controller/zombie/stupid
+ planning_subtrees = list(
+ /datum/ai_planning_subtree/random_speech/zombie,
+ /datum/ai_planning_subtree/simple_find_target,
+ /datum/ai_planning_subtree/basic_melee_attack_subtree,
+ )
diff --git a/code/modules/mob/living/simple_animal/hostile/zombie.dm b/code/modules/mob/living/simple_animal/hostile/zombie.dm
deleted file mode 100644
index 45bcf6cd3acd7..0000000000000
--- a/code/modules/mob/living/simple_animal/hostile/zombie.dm
+++ /dev/null
@@ -1,51 +0,0 @@
-/mob/living/simple_animal/hostile/zombie
- name = "Shambling Corpse"
- desc = "When there is no more room in hell, the dead will walk in outer space."
- icon = 'icons/mob/simple/simple_human.dmi'
- mob_biotypes = MOB_ORGANIC|MOB_HUMANOID
- sentience_type = SENTIENCE_HUMANOID
- speak_chance = 0
- stat_attack = HARD_CRIT //braains
- maxHealth = 100
- health = 100
- harm_intent_damage = 5
- melee_damage_lower = 21
- melee_damage_upper = 21
- attack_verb_continuous = "bites"
- attack_verb_simple = "bite"
- attack_sound = 'sound/effects/hallucinations/growl1.ogg'
- attack_vis_effect = ATTACK_EFFECT_BITE
- combat_mode = TRUE
- atmos_requirements = null
- minbodytemp = 0
- status_flags = CANPUSH
- death_message = "collapses, flesh gone in a pile of bones!"
- del_on_death = TRUE
- loot = list(/obj/effect/decal/remains/human)
- /// The probability that we give people real zombie infections on hit.
- var/infection_chance = 0
- /// Outfit the zombie spawns with for visuals.
- var/outfit = /datum/outfit/corpse_doctor
-
-/mob/living/simple_animal/hostile/zombie/Initialize(mapload)
- . = ..()
- apply_dynamic_human_appearance(src, outfit, /datum/species/zombie, bloody_slots = ITEM_SLOT_OCLOTHING)
-
-/mob/living/simple_animal/hostile/zombie/AttackingTarget(atom/attacked_target)
- . = ..()
- if(. && ishuman(target) && prob(infection_chance))
- try_to_zombie_infect(target)
-
-/datum/outfit/corpse_doctor
- name = "Corpse Doctor"
- suit = /obj/item/clothing/suit/toggle/labcoat
- uniform = /obj/item/clothing/under/rank/medical/doctor
- shoes = /obj/item/clothing/shoes/sneakers/white
- back = /obj/item/storage/backpack/medic
-
-/datum/outfit/corpse_assistant
- name = "Corpse Assistant"
- mask = /obj/item/clothing/mask/gas
- uniform = /obj/item/clothing/under/color/grey
- shoes = /obj/item/clothing/shoes/sneakers/black
- back = /obj/item/storage/backpack
diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm
index e82a607a9bfb8..ac4f911b26bfa 100644
--- a/code/modules/unit_tests/simple_animal_freeze.dm
+++ b/code/modules/unit_tests/simple_animal_freeze.dm
@@ -64,7 +64,6 @@
/mob/living/simple_animal/hostile/retaliate/goose,
/mob/living/simple_animal/hostile/retaliate/goose/vomit,
/mob/living/simple_animal/hostile/vatbeast,
- /mob/living/simple_animal/hostile/zombie,
/mob/living/simple_animal/soulscythe,
// DO NOT ADD NEW ENTRIES TO THIS LIST
// READ THE COMMENT ABOVE
diff --git a/tgstation.dme b/tgstation.dme
index b7f67bf487db3..1d960899caeb8 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -5072,6 +5072,7 @@
#include "code\modules\mob\living\basic\ruin_defender\mad_piano.dm"
#include "code\modules\mob\living\basic\ruin_defender\skeleton.dm"
#include "code\modules\mob\living\basic\ruin_defender\stickman.dm"
+#include "code\modules\mob\living\basic\ruin_defender\zombie.dm"
#include "code\modules\mob\living\basic\ruin_defender\mimic\mimic.dm"
#include "code\modules\mob\living\basic\ruin_defender\mimic\mimic_ai.dm"
#include "code\modules\mob\living\basic\ruin_defender\wizard\wizard.dm"
@@ -5352,7 +5353,6 @@
#include "code\modules\mob\living\simple_animal\hostile\illusion.dm"
#include "code\modules\mob\living\simple_animal\hostile\ooze.dm"
#include "code\modules\mob\living\simple_animal\hostile\vatbeast.dm"
-#include "code\modules\mob\living\simple_animal\hostile\zombie.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\_megafauna.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\blood_drunk_miner.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\bubblegum.dm"
diff --git a/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt b/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt
new file mode 100644
index 0000000000000..dbb408b60cd69
--- /dev/null
+++ b/tools/UpdatePaths/Scripts/89153_simple_to_basic_zombies.txt
@@ -0,0 +1,3 @@
+/mob/living/simple_animal/hostile/zombie{health=60;name="Rotting Carcass";outfit=/datum/outfit/corpse_assistant} : /mob/living/basic/zombie/rotten/assistant
+/mob/living/simple_animal/hostile/zombie{health=60;name="Rotting Carcass"} : /mob/living/basic/zombie/rotten
+/mob/living/simple_animal/hostile/zombie : /mob/living/basic/zombie{@OLD}
From 85cbc4cbae1ff4712cc1efe9b3c8a9d1e6e7dff2 Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 01:36:35 +0000
Subject: [PATCH 21/35] Automatic changelog for PR #89153 [ci skip]
---
html/changelogs/AutoChangeLog-pr-89153.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-89153.yml
diff --git a/html/changelogs/AutoChangeLog-pr-89153.yml b/html/changelogs/AutoChangeLog-pr-89153.yml
new file mode 100644
index 0000000000000..acd9df2a8fd46
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-89153.yml
@@ -0,0 +1,4 @@
+author: "Jacquerel"
+delete-after: True
+changes:
+ - refactor: "NPC zombies found in ruins now use the basic mob framework. Please make an issue report if they exhibit any unusual behaviour."
\ No newline at end of file
From 89538067db572e4f904b61a0f6b5c88445876804 Mon Sep 17 00:00:00 2001
From: Jacquerel
Date: Wed, 22 Jan 2025 01:38:47 +0000
Subject: [PATCH 22/35] Remove totally unused blob curse (#89154)
## About The Pull Request
We have a mob called `simple_animal/hostile/curseblob` which was used
only for the `necropolis_curse` status effect.
From the git history, this seems to have been added in a PR merged eight
years ago where the PR author came up with a cool set of curses to apply
to cursed objects and PRed it to the game as a concept to be used later.
Subsequently, nobody used it.
Well, to be more accurate, _two_ things apply the necropolis curse
debuff right now but they only collectively use three of the four
possibilities.
The fourth, which spawns a mob with weird behaviour, is unused and so
rather than spend my time bringing it up to standard I just removed it.
Because this is dead code.
To be quite honest I am not totally certain that `necropolis_curse`
should be a single status effect either and it would plausibly be better
off being two different status effects for the two different sources it
is currently invoked (helbital overdose, and being sacrificed by a
heretic).
**Fun Fact!**
Being sacrificed by a heretic doses you with 1 minute worth of
_Helgrasp_ which spawns a frightening hand to attack you once per
second, and also applies the Necropolis Curse which spawns a frightening
hand to attack you once per ten seconds. This means that if you have
anything in your mob which affects metabolic rate your sacrificial
experience may be somewhat different, as quite a lot of the danger
actually just comes from a chemical in your body.
One of these effects spawns the hands slightly further away than the
other, and you actually spend _2.5 minutes_ in the spooky hand room, so
in that second (longer) half you'll only be tormented by very occasional
spectral groping. Personally I would not do it this way I think.
However rather than removing and replacing it, which would probably have
some kind of aftereffect on the heretic sacrifice minigame that I would
rather make larger changes to, I just touched up some of the code to
avoid single-letter vars and to use a helper proc we already use in
other heretic-related places.
## Why It's Good For The Game
This wasn't maintained, isn't used, and was on our to-do mob conversion
list.
## Changelog
Not player facing
---
code/__DEFINES/status_effects.dm | 6 +-
code/datums/status_effects/debuffs/debuffs.dm | 58 ++++----
.../sacrifice_knowledge/sacrifice_buff.dm | 6 +-
.../hostile/mining_mobs/curse_blob.dm | 132 ------------------
.../unit_tests/simple_animal_freeze.dm | 1 -
tgstation.dme | 1 -
6 files changed, 29 insertions(+), 175 deletions(-)
delete mode 100644 code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
index e2fdf01e9aaba..46987974d8049 100644
--- a/code/__DEFINES/status_effects.dm
+++ b/code/__DEFINES/status_effects.dm
@@ -26,12 +26,10 @@
//several flags for the Necropolis curse status effect
///makes the edges of the target's screen obscured
#define CURSE_BLINDING (1<<0)
-///spawns creatures that attack the target only
-#define CURSE_SPAWNING (1<<1)
///causes gradual damage
-#define CURSE_WASTING (1<<2)
+#define CURSE_WASTING (1<<1)
///hands reach out from the sides of the screen, doing damage and stunning if they hit the target
-#define CURSE_GRASPING (1<<3)
+#define CURSE_GRASPING (1<<2)
//Incapacitated status effect flags
/// If the mob is normal incapacitated. Should never need this, just avoids issues if we ever overexpand this
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
index 006a2a527dfb3..7627d16b66f45 100644
--- a/code/datums/status_effects/debuffs/debuffs.dm
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -461,26 +461,32 @@
/datum/status_effect/neck_slice/get_examine_text()
return span_warning("[owner.p_Their()] neck is cut and is bleeding profusely!")
+/// Applies a curse with various possible effects
/mob/living/proc/apply_necropolis_curse(set_curse)
- var/datum/status_effect/necropolis_curse/C = has_status_effect(/datum/status_effect/necropolis_curse)
+ var/datum/status_effect/necropolis_curse/curse = has_status_effect(/datum/status_effect/necropolis_curse)
if(!set_curse)
- set_curse = pick(CURSE_BLINDING, CURSE_SPAWNING, CURSE_WASTING, CURSE_GRASPING)
- if(QDELETED(C))
+ set_curse = pick(CURSE_BLINDING, CURSE_WASTING, CURSE_GRASPING)
+ if(QDELETED(curse))
apply_status_effect(/datum/status_effect/necropolis_curse, set_curse)
else
- C.apply_curse(set_curse)
- C.duration += 3000 //time added by additional curses
- return C
+ curse.apply_curse(set_curse)
+ curse.duration += 5 MINUTES //time added by additional curses
+ return curse
+/// A curse that does up to three nasty things to you
/datum/status_effect/necropolis_curse
id = "necrocurse"
duration = 10 MINUTES //you're cursed for 10 minutes have fun
tick_interval = 5 SECONDS
alert_type = null
+ /// Which nasty things are we doing? [CURSE_BLINDING / CURSE_WASTING / CURSE_GRASPING]]
var/curse_flags = NONE
- var/effect_last_activation = 0
- var/effect_cooldown = 100
- var/obj/effect/temp_visual/curse/wasting_effect = new
+ /// When should we next throw hands?
+ var/effect_next_activation = 0
+ /// How long between throwing hands?
+ var/effect_cooldown = 10 SECONDS
+ /// Visuals for the wasting effect
+ var/obj/effect/temp_visual/curse/wasting_effect
/datum/status_effect/necropolis_curse/on_creation(mob/living/new_owner, set_curse)
. = ..()
@@ -500,6 +506,8 @@
curse_flags |= set_curse
if(curse_flags & CURSE_BLINDING)
owner.overlay_fullscreen("curse", /atom/movable/screen/fullscreen/curse, 1)
+ if(curse_flags & CURSE_WASTING && !wasting_effect)
+ wasting_effect = new
/datum/status_effect/necropolis_curse/proc/remove_curse(remove_curse)
if(remove_curse & CURSE_BLINDING)
@@ -509,6 +517,7 @@
/datum/status_effect/necropolis_curse/tick(seconds_between_ticks)
if(owner.stat == DEAD)
return
+
if(curse_flags & CURSE_WASTING)
wasting_effect.forceMove(owner.loc)
wasting_effect.setDir(owner.dir)
@@ -517,31 +526,12 @@
animate(wasting_effect, alpha = 0, time = 32)
playsound(owner, 'sound/effects/curse/curse5.ogg', 20, TRUE, -1)
owner.adjustFireLoss(0.75)
- if(effect_last_activation <= world.time)
- effect_last_activation = world.time + effect_cooldown
- if(curse_flags & CURSE_SPAWNING)
- var/turf/spawn_turf
- var/sanity = 10
- while(!spawn_turf && sanity)
- spawn_turf = locate(owner.x + pick(rand(10, 15), rand(-10, -15)), owner.y + pick(rand(10, 15), rand(-10, -15)), owner.z)
- sanity--
- if(spawn_turf)
- var/mob/living/simple_animal/hostile/asteroid/curseblob/C = new (spawn_turf)
- C.set_target = owner
- C.GiveTarget()
- if(curse_flags & CURSE_GRASPING)
- var/grab_dir = turn(owner.dir, pick(-90, 90, 180, 180)) //grab them from a random direction other than the one faced, favoring grabbing from behind
- var/turf/spawn_turf = get_ranged_target_turf(owner, grab_dir, 5)
- if(spawn_turf)
- grasp(spawn_turf)
-
-/datum/status_effect/necropolis_curse/proc/grasp(turf/spawn_turf)
- set waitfor = FALSE
- new/obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, owner.dir)
- playsound(spawn_turf, 'sound/effects/curse/curse2.ogg', 80, TRUE, -1)
- var/obj/projectile/curse_hand/C = new (spawn_turf)
- C.aim_projectile(owner, spawn_turf)
- C.fire()
+
+ if(curse_flags & CURSE_GRASPING)
+ if(effect_next_activation > world.time)
+ return
+ effect_next_activation = world.time + effect_cooldown
+ fire_curse_hand(owner, range = 5, projectile_type = /obj/projectile/curse_hand) // This one stuns people
/obj/effect/temp_visual/curse
icon_state = "curse"
diff --git a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
index 4238b54f91543..618ee9e6f667e 100644
--- a/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
+++ b/code/modules/antagonists/heretic/knowledge/sacrifice_knowledge/sacrifice_buff.dm
@@ -109,15 +109,15 @@
bloodiest_wound.adjust_blood_flow(-0.5 * seconds_between_ticks)
/// Torment the target with a frightening hand
-/proc/fire_curse_hand(mob/living/carbon/victim, turf/forced_turf)
+/proc/fire_curse_hand(mob/living/carbon/victim, turf/forced_turf, range = 8, projectile_type = /obj/projectile/curse_hand/hel)
var/grab_dir = turn(victim.dir, pick(-90, 90, 180, 180)) // Not in front, favour behind
- var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, 8)
+ var/turf/spawn_turf = get_ranged_target_turf(victim, grab_dir, range)
spawn_turf = forced_turf ? forced_turf : spawn_turf
if (isnull(spawn_turf))
return
new /obj/effect/temp_visual/dir_setting/curse/grasp_portal(spawn_turf, victim.dir)
playsound(spawn_turf, 'sound/effects/curse/curse2.ogg', 80, TRUE, -1)
- var/obj/projectile/curse_hand/hel/hand = new (spawn_turf)
+ var/obj/projectile/hand = new projectile_type(spawn_turf)
hand.aim_projectile(victim, spawn_turf)
if (QDELETED(hand)) // safety check if above fails - above has a stack trace if it does fail
return
diff --git a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm b/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
deleted file mode 100644
index 5fbd6cda5cbfb..0000000000000
--- a/code/modules/mob/living/simple_animal/hostile/mining_mobs/curse_blob.dm
+++ /dev/null
@@ -1,132 +0,0 @@
-/mob/living/simple_animal/hostile/asteroid/curseblob
- name = "curse mass"
- desc = "A mass of purple... smoke?"
- icon = 'icons/mob/simple/lavaland/lavaland_monsters.dmi'
- icon_state = "curseblob"
- icon_living = "curseblob"
- icon_aggro = "curseblob"
- mob_biotypes = MOB_SPIRIT
- move_to_delay = 5
- vision_range = 20
- aggro_vision_range = 20
- maxHealth = 40 //easy to kill, but oh, will you be seeing a lot of them.
- health = 40
- melee_damage_lower = 10
- melee_damage_upper = 10
- melee_damage_type = BURN
- attack_verb_continuous = "slashes"
- attack_verb_simple = "slash"
- attack_sound = 'sound/effects/curse/curseattack.ogg'
- attack_vis_effect = ATTACK_EFFECT_SLASH
- throw_message = "passes through the smokey body of"
- obj_damage = 0
- environment_smash = ENVIRONMENT_SMASH_NONE
- sentience_type = SENTIENCE_BOSS
- layer = LARGE_MOB_LAYER
- var/mob/living/set_target
- var/datum/move_loop/has_target/force_move/our_loop
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/Initialize(mapload)
- . = ..()
- QDEL_IN(src, 60 SECONDS)
- AddElement(/datum/element/simple_flying)
- playsound(src, 'sound/effects/curse/curse1.ogg', 100, TRUE, -1)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/Destroy()
- new /obj/effect/temp_visual/dir_setting/curse/blob(loc, dir)
- set_target = null
- return ..()
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/Goto(move_target, delay, minimum_distance) //Observe
- if(check_for_target())
- return
- move_loop(target, delay)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/move_loop(move_target, delay)
- if(our_loop)
- return
- our_loop = GLOB.move_manager.force_move(src, move_target, delay, priority = MOVEMENT_ABOVE_SPACE_PRIORITY)
- if(!our_loop)
- return
- RegisterSignal(move_target, COMSIG_MOB_STATCHANGE, PROC_REF(stat_change))
- RegisterSignal(move_target, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(target_z_change))
- RegisterSignal(src, COMSIG_MOVABLE_Z_CHANGED, PROC_REF(our_z_change))
- RegisterSignal(our_loop, COMSIG_QDELETING, PROC_REF(handle_loop_end))
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/stat_change(datum/source, new_stat)
- SIGNAL_HANDLER
- if(new_stat != CONSCIOUS)
- qdel(src)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/target_z_change(datum/source, old_z, new_z)
- SIGNAL_HANDLER
- qdel(src)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/our_z_change(datum/source, old_z, new_z)
- SIGNAL_HANDLER
- qdel(src)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/handle_loop_end()
- SIGNAL_HANDLER
- if(QDELETED(src))
- return
- qdel(src)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/handle_target_del(datum/source)
- . = ..()
- qdel(src)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/proc/check_for_target()
- if(QDELETED(src) || !set_target)
- return TRUE
- if(set_target.stat != CONSCIOUS)
- return TRUE
- if(set_target.z != z)
- return TRUE
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/GiveTarget(new_target)
- if(check_for_target())
- return
- new_target = set_target
- . = ..()
- Goto(target, move_to_delay)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/LoseTarget() //we can't lose our target!
- if(check_for_target())
- return
-
-//if it's not our target, we ignore it
-/mob/living/simple_animal/hostile/asteroid/curseblob/CanAllowThrough(atom/movable/mover, border_dir)
- . = ..()
- if(mover == set_target)
- return FALSE
- if(isprojectile(mover))
- var/obj/projectile/proj = mover
- if(proj.firer == set_target)
- return FALSE
-
-#define IGNORE_PROC_IF_NOT_TARGET(X) /mob/living/simple_animal/hostile/asteroid/curseblob/##X(AM) { if (AM == set_target) return ..(); }
-
-IGNORE_PROC_IF_NOT_TARGET(attack_hand)
-
-IGNORE_PROC_IF_NOT_TARGET(attack_hulk)
-
-IGNORE_PROC_IF_NOT_TARGET(attack_paw)
-
-IGNORE_PROC_IF_NOT_TARGET(attack_alien)
-
-IGNORE_PROC_IF_NOT_TARGET(attack_larva)
-
-IGNORE_PROC_IF_NOT_TARGET(attack_animal)
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/bullet_act(obj/projectile/proj)
- if(proj.firer != set_target)
- return BULLET_ACT_BLOCK
- return ..()
-
-/mob/living/simple_animal/hostile/asteroid/curseblob/attacked_by(obj/item/I, mob/living/L)
- if(L != set_target)
- return
- return ..()
-
-#undef IGNORE_PROC_IF_NOT_TARGET
diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm
index ac4f911b26bfa..70f3b82885d23 100644
--- a/code/modules/unit_tests/simple_animal_freeze.dm
+++ b/code/modules/unit_tests/simple_animal_freeze.dm
@@ -21,7 +21,6 @@
/mob/living/simple_animal/bot/secbot/pingsky,
/mob/living/simple_animal/hostile,
/mob/living/simple_animal/hostile/asteroid,
- /mob/living/simple_animal/hostile/asteroid/curseblob,
/mob/living/simple_animal/hostile/asteroid/elite,
/mob/living/simple_animal/hostile/asteroid/elite/broodmother,
/mob/living/simple_animal/hostile/asteroid/elite/broodmother_child,
diff --git a/tgstation.dme b/tgstation.dme
index 1d960899caeb8..07b101102de89 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -5363,7 +5363,6 @@
#include "code\modules\mob\living\simple_animal\hostile\megafauna\hierophant.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\legion.dm"
#include "code\modules\mob\living\simple_animal\hostile\megafauna\wendigo.dm"
-#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\curse_blob.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\mining_mobs.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\polarbear.dm"
#include "code\modules\mob\living\simple_animal\hostile\mining_mobs\elites\elite.dm"
From 37ad103c5ec79f3f521e16b3a274428369971d93 Mon Sep 17 00:00:00 2001
From: SmArtKar <44720187+SmArtKar@users.noreply.github.com>
Date: Wed, 22 Jan 2025 02:43:26 +0100
Subject: [PATCH 23/35] Implements /Exited() for clipboards (#89156)
## About The Pull Request
Moved visual updates upon pen/paper removal into /Exited(), thanks to
Ephe for the idea
## Why It's Good For The Game
Makes sure that we don't hang onto references if our pen/paper gets
removed via less-than-normal methods, like instant recall
## Changelog
:cl:
fix: Clipboards should no longer retain pens that got removed via
Instant Recall
/:cl:
---
code/modules/paperwork/clipboard.dm | 67 +++++++++++++----------------
1 file changed, 31 insertions(+), 36 deletions(-)
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index 435cfc3e7c74a..ec81574628d21 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -26,13 +26,11 @@
/// Is the pen integrated?
var/integrated_pen = FALSE
/**
- * Weakref of the topmost piece of paper
- *
+ * Topmost piece of paper
* This is used for the paper displayed on the clipboard's icon
* and it is the one attacked, when attacking the clipboard.
- * (As you can't organise contents directly in BYOND)
*/
- var/datum/weakref/toppaper_ref
+ var/obj/item/paper/top_paper
/obj/item/clipboard/suicide_act(mob/living/carbon/user)
user.visible_message(span_suicide("[user] begins putting [user.p_their()] head into the clip of \the [src]! It looks like [user.p_theyre()] trying to commit suicide!"))
@@ -50,9 +48,8 @@
. = ..()
if(!integrated_pen && pen)
. += span_notice("Alt-click to remove [pen].")
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
- if(toppaper)
- . += span_notice("Right-click to remove [toppaper].")
+ if(top_paper)
+ . += span_notice("Right-click to remove [top_paper].")
/// Take out the topmost paper
/obj/item/clipboard/proc/remove_paper(obj/item/paper/paper, mob/user)
@@ -61,22 +58,24 @@
paper.forceMove(user.loc)
user.put_in_hands(paper)
to_chat(user, span_notice("You remove [paper] from [src]."))
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
- if(paper == toppaper)
- UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
- toppaper_ref = null
- var/obj/item/paper/newtop = locate(/obj/item/paper) in src
- if(newtop && (newtop != paper))
- toppaper_ref = WEAKREF(newtop)
- else
- toppaper_ref = null
- update_icon()
/obj/item/clipboard/proc/remove_pen(mob/user)
pen.forceMove(user.loc)
user.put_in_hands(pen)
to_chat(user, span_notice("You remove [pen] from [src]."))
- pen = null
+
+/obj/item/clipboard/Exited(atom/movable/gone, direction)
+ . = ..()
+ if (gone == pen)
+ pen = null
+ update_icon()
+ return
+
+ if (gone != top_paper)
+ return
+
+ UnregisterSignal(top_paper, COMSIG_ATOM_UPDATED_ICON)
+ top_paper = locate(/obj/item/paper) in src
update_icon()
/obj/item/clipboard/click_alt(mob/user)
@@ -100,32 +99,29 @@
. += "clipboard_over"
/obj/item/clipboard/proc/get_paper_overlay()
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
- if(isnull(toppaper))
+ if(isnull(top_paper))
return
- var/mutable_appearance/paper_overlay = mutable_appearance(icon, toppaper.icon_state, offset_spokesman = src, appearance_flags = KEEP_APART)
- paper_overlay = toppaper.color_atom_overlay(paper_overlay)
- paper_overlay.overlays += toppaper.overlays
+ var/mutable_appearance/paper_overlay = mutable_appearance(icon, top_paper.icon_state, offset_spokesman = src, appearance_flags = KEEP_APART)
+ paper_overlay = top_paper.color_atom_overlay(paper_overlay)
+ paper_overlay.overlays += top_paper.overlays
return paper_overlay
/obj/item/clipboard/attack_hand(mob/user, list/modifiers)
if(LAZYACCESS(modifiers, RIGHT_CLICK))
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
- remove_paper(toppaper, user)
+ remove_paper(top_paper, user)
return TRUE
. = ..()
/obj/item/clipboard/attackby(obj/item/weapon, mob/user, params)
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
if(istype(weapon, /obj/item/paper))
//Add paper into the clipboard
if(!user.transferItemToLoc(weapon, src))
return
- if(toppaper)
- UnregisterSignal(toppaper, COMSIG_ATOM_UPDATED_ICON)
+ if(top_paper)
+ UnregisterSignal(top_paper, COMSIG_ATOM_UPDATED_ICON)
RegisterSignal(weapon, COMSIG_ATOM_UPDATED_ICON, PROC_REF(on_top_paper_change))
- toppaper_ref = WEAKREF(weapon)
+ top_paper = weapon
to_chat(user, span_notice("You clip [weapon] onto [src]."))
else if(istype(weapon, /obj/item/pen) && !pen)
//Add a pen into the clipboard, attack (write) if there is already one
@@ -133,8 +129,8 @@
return
pen = weapon
to_chat(usr, span_notice("You slot [weapon] into [src]."))
- else if(toppaper)
- toppaper.attackby(user.get_active_held_item(), user)
+ else if(top_paper)
+ top_paper.attackby(user.get_active_held_item(), user)
update_appearance()
/obj/item/clipboard/attack_self(mob/user)
@@ -154,14 +150,13 @@
data["pen"] = "[pen]"
data["integrated_pen"] = integrated_pen
- var/obj/item/paper/toppaper = toppaper_ref?.resolve()
- data["top_paper"] = "[toppaper]"
- data["top_paper_ref"] = "[REF(toppaper)]"
+ data["top_paper"] = "[top_paper]"
+ data["top_paper_ref"] = "[REF(top_paper)]"
data["paper"] = list()
data["paper_ref"] = list()
for(var/obj/item/paper/paper in src)
- if(paper == toppaper)
+ if(paper == top_paper)
continue
data["paper"] += "[paper]"
data["paper_ref"] += "[REF(paper)]"
@@ -202,7 +197,7 @@
if("move_top_paper")
var/obj/item/paper/paper = locate(params["ref"]) in src
if(istype(paper))
- toppaper_ref = WEAKREF(paper)
+ top_paper = paper
to_chat(usr, span_notice("You move [paper] to the top."))
update_icon()
. = TRUE
From b028b40f3767f5257f9aca65483fef40c36c3f23 Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 01:43:46 +0000
Subject: [PATCH 24/35] Automatic changelog for PR #89156 [ci skip]
---
html/changelogs/AutoChangeLog-pr-89156.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-89156.yml
diff --git a/html/changelogs/AutoChangeLog-pr-89156.yml b/html/changelogs/AutoChangeLog-pr-89156.yml
new file mode 100644
index 0000000000000..43ad3a8538258
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-89156.yml
@@ -0,0 +1,4 @@
+author: "SmArtKar"
+delete-after: True
+changes:
+ - bugfix: "Clipboards should no longer retain pens that got removed via Instant Recall"
\ No newline at end of file
From 00297eaee6110d5cdd59454bee31444e68a4b60c Mon Sep 17 00:00:00 2001
From: MrMelbert <51863163+MrMelbert@users.noreply.github.com>
Date: Tue, 21 Jan 2025 19:43:51 -0600
Subject: [PATCH 25/35] Fix all decap'd heads looking brainless (#89157)
## About The Pull Request
Order of operations thing (I think)
- `drop_limb`
- `update_limb`
- It correctly updates the limb `show_debrained = FALSE`
- Remove from limb
- `death`
- `update_body_parts`
- `update_limb`
- Now the head is still associated with the mob, but the organs are
gone, so technically, we have no brain
- It updates the limb `show_debrained = TRUE`
- `update_owner(null)`
- Head is only NOW disassociated with the mob after we've wrongly
assumed the mob has no brain
- `update_icon_dropped` (with the incorrect values)
Moving to after we have been disassociated with the owner entirely seems
to fix it, might have knock on effects though. Didn't seem to in (short)
testing but yeah
Maybe fixes #87971
## Changelog
:cl: Melbert
fix: Heads with brains no longer look debrained
/:cl:
---
code/modules/surgery/bodyparts/dismemberment.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/surgery/bodyparts/dismemberment.dm b/code/modules/surgery/bodyparts/dismemberment.dm
index 52bc11e3cab27..bd4a5306fa0d5 100644
--- a/code/modules/surgery/bodyparts/dismemberment.dm
+++ b/code/modules/surgery/bodyparts/dismemberment.dm
@@ -87,7 +87,6 @@
SEND_SIGNAL(owner, COMSIG_CARBON_REMOVE_LIMB, src, special, dismembered)
SEND_SIGNAL(src, COMSIG_BODYPART_REMOVED, owner, special, dismembered)
- update_limb(dropping_limb = TRUE)
bodypart_flags &= ~BODYPART_IMPLANTED //limb is out and about, it can't really be considered an implant
owner.remove_bodypart(src, special)
@@ -96,6 +95,7 @@
LAZYREMOVE(owner.all_scars, scar)
var/mob/living/carbon/phantom_owner = update_owner(null) // so we can still refer to the guy who lost their limb after said limb forgets 'em
+ update_limb(dropping_limb = TRUE)
for(var/datum/wound/wound as anything in wounds)
wound.remove_wound(TRUE)
From 3169ff920a605ea7bc0a0e6493fb10097ae8b4ba Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 01:44:12 +0000
Subject: [PATCH 26/35] Automatic changelog for PR #89157 [ci skip]
---
html/changelogs/AutoChangeLog-pr-89157.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-89157.yml
diff --git a/html/changelogs/AutoChangeLog-pr-89157.yml b/html/changelogs/AutoChangeLog-pr-89157.yml
new file mode 100644
index 0000000000000..b4ab02618c6ac
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-89157.yml
@@ -0,0 +1,4 @@
+author: "Melbert"
+delete-after: True
+changes:
+ - bugfix: "Heads with brains no longer look debrained"
\ No newline at end of file
From d3f7ff3e7157fd1f1f5ae2f132cc9d98b813001a Mon Sep 17 00:00:00 2001
From: Bloop <13398309+vinylspiders@users.noreply.github.com>
Date: Tue, 21 Jan 2025 20:44:43 -0500
Subject: [PATCH 27/35] Fixes a fishy CI failure caused by a hard delete
(#89138)
## About The Pull Request
Likely caused by a race condition with a `load_trophy_fish()` occurring
after the item is deleted somehow. I erred on the side of caution and
just made sure we can never get any fish being added to the trophy after
its deletion.
![image](https://github.com/user-attachments/assets/1968ee5a-78e8-428e-9421-2416860962bc)
## Why It's Good For The Game
Too many spurious CI failures lately
## Changelog
N/A
---
code/modules/fishing/fish_mount.dm | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/code/modules/fishing/fish_mount.dm b/code/modules/fishing/fish_mount.dm
index d2334910e2a55..4649f2e9125c2 100644
--- a/code/modules/fishing/fish_mount.dm
+++ b/code/modules/fishing/fish_mount.dm
@@ -78,7 +78,7 @@
if(fish_path.fish_id_redirect_path)
fish_path = fish_path.fish_id_redirect_path
var/fluff_name = pick("John Trasen III", "a nameless intern", "Pun Pun", AQUARIUM_COMPANY, "Unknown", "Central Command")
- add_fish(new fish_path(src), from_persistence = TRUE, catcher = fluff_name)
+ add_fish(new fish_path(loc), from_persistence = TRUE, catcher = fluff_name)
mounted_fish.randomize_size_and_weight()
mounted_fish.set_status(FISH_DEAD)
SSpersistence.save_trophy_fish(src)
@@ -108,6 +108,11 @@
return ITEM_INTERACT_SUCCESS
/obj/structure/fish_mount/proc/add_fish(obj/item/fish/fish, from_persistence = FALSE, catcher)
+ if(QDELETED(src)) // don't ever try to add a fish to one of these that's already been deleted - and get rid of the one that was created
+ qdel(fish)
+ return
+ if(QDELETED(fish)) // no adding deleted fishies either
+ return
if(mounted_fish)
mounted_fish.forceMove(loc)
fish.forceMove(src)
From 4a1fedf64f3b97cba4b725f5ca415e0dcc3c4cd7 Mon Sep 17 00:00:00 2001
From: Bloop <13398309+vinylspiders@users.noreply.github.com>
Date: Tue, 21 Jan 2025 21:03:46 -0500
Subject: [PATCH 28/35] Fixes an UpdatePaths script that was written backwards
(#89128)
## About The Pull Request
Tin. This script when run would actually undo any instances of the thing
and revert it back to the invalid version. I found this out after
running it and becoming confused when it seemingly undid their pr.
## Why It's Good For The Game
Working scripts for downstreams are nice. I think.
## Changelog
N/a
---
tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt b/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt
index 28ad97efff1ab..0b6f5a9f39eb9 100644
--- a/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt
+++ b/tools/UpdatePaths/Scripts/88095_repaths_a357_to_c357.txt
@@ -1,3 +1,3 @@
#comment Repaths instances of a357 with c357, so as to acknowledge that it is consistent with other casings.
-/obj/item/ammo_casing/c357 : /obj/item/ammo_casing/a357{@OLD}
+/obj/item/ammo_casing/a357 : /obj/item/ammo_casing/c357{@OLD}
From 86e06b1b293f7ee2a67f783806c3c66b7a7220ab Mon Sep 17 00:00:00 2001
From: Bloop <13398309+vinylspiders@users.noreply.github.com>
Date: Tue, 21 Jan 2025 21:07:12 -0500
Subject: [PATCH 29/35] Fixes an armrest related hard del (#89139)
## About The Pull Request
Another spurious CI runtime that keeps coming up all the time and is
annoying me. I believe it's occurring due to the chair not being
initialized before a `mob_buckler` mapping helper tries to buckle mobs
to it.
So I moved their code to lateload to hopefully ensure that doesn't
happen, as well as an additional safety measure in the armchair code
itself.
edit: confirmed that this does indeed fix it, as I have it merged
downstream preemptively due to it being such a blocking nuisance
![image](https://github.com/user-attachments/assets/508e3f58-08ee-4e54-98a2-8a655ce85530)
Caused by
## Why It's Good For The Game
Less CI failures
## Changelog
N/A
---
code/modules/mapping/mapping_helpers.dm | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm
index d04e6e0afd15b..da7d288d161fe 100644
--- a/code/modules/mapping/mapping_helpers.dm
+++ b/code/modules/mapping/mapping_helpers.dm
@@ -1373,6 +1373,13 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_atoms_ontop)
/obj/effect/mapping_helpers/mob_buckler/Initialize(mapload)
. = ..()
+ if(!mapload)
+ log_mapping("[src] spawned outside of mapload!")
+ return INITIALIZE_HINT_QDEL
+
+ return INITIALIZE_HINT_LATELOAD
+
+/obj/effect/mapping_helpers/mob_buckler/LateInitialize()
var/atom/movable/buckle_to
var/list/mobs = list()
for(var/atom/movable/possible_buckle as anything in loc)
@@ -1385,12 +1392,13 @@ INITIALIZE_IMMEDIATE(/obj/effect/mapping_helpers/no_atoms_ontop)
if(isnull(buckle_to))
log_mapping("[type] at [x] [y] [z] did not find anything to buckle to")
- return INITIALIZE_HINT_QDEL
+ qdel(src)
+ return
for(var/mob/living/mob as anything in mobs)
buckle_to.buckle_mob(mob, force = force_buckle)
- return INITIALIZE_HINT_QDEL
+ qdel(src)
///Basic mob flag helpers for things like deleting on death.
/obj/effect/mapping_helpers/basic_mob_flags
From 83e179ee21f52b5072a2210185e82ed0f53ecec4 Mon Sep 17 00:00:00 2001
From: Vekter
Date: Tue, 21 Jan 2025 23:45:45 -0600
Subject: [PATCH 30/35] Drastically simplifies the roundstart report (#89150)
## About The Pull Request
The roundstart report has been changed in the following ways:
- There are now only four alert levels: Yellow Star (0-65 Threat), Red
Star (66-79 Threat), Black Orbit (80-99 Threat), and Midnight Sun (100
Threat).
- The roundstart report is now 100% accurate.
- Extended rounds will still show the "No credible threat" alerts, but
this should only happen if an admin sets the round to Extended.
## Why It's Good For The Game
The current roundstart report system is too granular as it is now, which
leads to situations where players will suicide 5-10 minutes into the
round due to the threat level being too low. Making it potentially
random was meaningless, because players would just act on whatever it
said without actually giving the round a chance to do anything.
I also feel like this brings back a fair bit of paranoia to the round,
as low threat levels would often just result in people expecting nothing
to happen. That can be fun when the report is lying, but it doesn't
happen often enough to really make it worth keeping.
We tested this a few months ago and the results seemed positive. We also
had a lot of discussion about the matter and, while I'm open to changing
implementation in some ways, I'm pretty set on this being a beneficial
change, at least in the short term until we can make Dynamic more
interesting.
I kept the high threat level stuff because it's fun to know some crazy
shit might happen. I might bring back the random threat level thing to
differentiate between those but I don't really care tbh; the targeted
behavior here is people bailing on low threat rounds, not people knowing
it's a high threat round.
## Changelog
:cl: Vekter
balance: The roundstart report will now display a more broad, less
specific message about threat levels when between 0 and 80 threat.
/:cl:
---
code/controllers/subsystem/dynamic/dynamic.dm | 57 +------------------
.../subsystem/dynamic/dynamic_logging.dm | 1 -
2 files changed, 3 insertions(+), 55 deletions(-)
diff --git a/code/controllers/subsystem/dynamic/dynamic.dm b/code/controllers/subsystem/dynamic/dynamic.dm
index b56c13308ebe1..c215feedd39d6 100644
--- a/code/controllers/subsystem/dynamic/dynamic.dm
+++ b/code/controllers/subsystem/dynamic/dynamic.dm
@@ -1,9 +1,3 @@
-#define FAKE_GREENSHIFT_FORM_CHANCE 15
-#define FAKE_REPORT_CHANCE 8
-#define PULSAR_REPORT_CHANCE 8
-#define REPORT_NEG_DIVERGENCE -15
-#define REPORT_POS_DIVERGENCE 15
-
// Are HIGH_IMPACT_RULESETs allowed to stack?
GLOBAL_VAR_INIT(dynamic_no_stacking, TRUE)
// If enabled does not accept or execute any rulesets.
@@ -195,10 +189,6 @@ SUBSYSTEM_DEF(dynamic)
/// Used for choosing different midround injections.
var/list/current_midround_rulesets
- /// The amount of threat shown on the piece of paper.
- /// Can differ from the actual threat amount.
- var/shown_threat
-
VAR_PRIVATE/next_midround_injection
/datum/controller/subsystem/dynamic/proc/admin_panel()
@@ -336,7 +326,7 @@ SUBSYSTEM_DEF(dynamic)
continue
min_threat = min(ruleset.cost, min_threat)
- var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat && shown_threat < min_threat) //if both shown and real threat are below any ruleset, its extended time
+ var/greenshift = GLOB.dynamic_forced_extended || (threat_level < min_threat) //if threat is below any ruleset, its extended time
SSstation.generate_station_goals(greenshift ? INFINITY : CONFIG_GET(number/station_goal_budget))
var/list/datum/station_goal/goals = SSstation.get_station_goals()
@@ -380,39 +370,10 @@ SUBSYSTEM_DEF(dynamic)
/// Generate the advisory level depending on the shown threat level.
/datum/controller/subsystem/dynamic/proc/generate_advisory_level()
var/advisory_string = ""
- if(prob(PULSAR_REPORT_CHANCE))
- for(var/datum/station_trait/our_trait as anything in shuffle(SSstation.station_traits))
- advisory_string += our_trait.get_pulsar_message()
- if(length(advisory_string))
- return advisory_string
-
- advisory_string += "Advisory Level: Pulsar Star
"
- advisory_string += "Your sector's advisory level is Pulsar Star. A large, unknown electromagnetic field has stormed through nearby surveillance equipment, causing major data loss. Partial data was recovered and showed no credible threats to Nanotrasen assets within the Spinward Sector; however, the Department of Intelligence advises maintaining high alert against potential threats due to the lack of complete data."
- return advisory_string
- //a white dwarf shift leads to a green security alert on report and special announcement, this prevents a meta check if the alert report is fake or not.
- if(round(shown_threat) == 0 && round(threat_level) == 0)
- advisory_string += "Advisory Level: White Dwarf
"
- advisory_string += "Your sector's advisory level is White Dwarf. Our surveillance has ruled out any and all potential threats known in our database, eliminating most risks to our assets in the Spinward Sector. We advise a lower level of security, alongside distributing resources on potential profit."
- return advisory_string
-
- switch(round(shown_threat))
- if(0 to 19)
- var/show_core_territory = (GLOB.current_living_antags.len > 0)
- if (prob(FAKE_GREENSHIFT_FORM_CHANCE))
- show_core_territory = !show_core_territory
-
- if (show_core_territory)
- advisory_string += "Advisory Level: Blue Star
"
- advisory_string += "Your sector's advisory level is Blue Star. At this threat advisory, the risk of attacks on Nanotrasen assets within the sector is minor but cannot be ruled out entirely. Remain vigilant."
- else
- advisory_string += "Advisory Level: Green Star
"
- advisory_string += "Your sector's advisory level is Green Star. Surveillance information shows no credible threats to Nanotrasen assets within the Spinward Sector at this time. As always, the Department of Intelligence advises maintaining vigilance against potential threats, regardless of a lack of known threats."
- if(20 to 39)
+ switch(round(threat_level))
+ if(0 to 65)
advisory_string += "Advisory Level: Yellow Star
"
advisory_string += "Your sector's advisory level is Yellow Star. Surveillance shows a credible risk of enemy attack against our assets in the Spinward Sector. We advise a heightened level of security alongside maintaining vigilance against potential threats."
- if(40 to 65)
- advisory_string += "Advisory Level: Orange Star
"
- advisory_string += "Your sector's advisory level is Orange Star. Upon reviewing your sector's intelligence, the Department has determined that the risk of enemy activity is moderate to severe. At this advisory, we recommend maintaining a higher degree of security and reviewing red alert protocols with command and the crew."
if(66 to 79)
advisory_string += "Advisory Level: Red Star
"
advisory_string += "Your sector's advisory level is Red Star. The Department of Intelligence has decrypted Cybersun communications suggesting a high likelihood of attacks on Nanotrasen assets within the Spinward Sector. Stations in the region are advised to remain highly vigilant for signs of enemy activity and to be on high alert."
@@ -497,11 +458,6 @@ SUBSYSTEM_DEF(dynamic)
)
return TRUE
-/datum/controller/subsystem/dynamic/proc/setup_shown_threat()
- if (prob(FAKE_REPORT_CHANCE))
- shown_threat = rand(1, 100)
- else
- shown_threat = clamp(threat_level + rand(REPORT_NEG_DIVERGENCE, REPORT_POS_DIVERGENCE), 0, 100)
/datum/controller/subsystem/dynamic/proc/set_cooldowns()
var/latejoin_injection_cooldown_middle = 0.5*(latejoin_delay_max + latejoin_delay_min)
@@ -523,7 +479,6 @@ SUBSYSTEM_DEF(dynamic)
configure_station_trait_costs()
setup_parameters()
setup_hijacking()
- setup_shown_threat()
setup_rulesets()
//We do this here instead of with the midround rulesets and such because these rules can hang refs
@@ -1056,9 +1011,3 @@ SUBSYSTEM_DEF(dynamic)
#undef MAXIMUM_DYN_DISTANCE
-
-#undef FAKE_REPORT_CHANCE
-#undef FAKE_GREENSHIFT_FORM_CHANCE
-#undef PULSAR_REPORT_CHANCE
-#undef REPORT_NEG_DIVERGENCE
-#undef REPORT_POS_DIVERGENCE
diff --git a/code/controllers/subsystem/dynamic/dynamic_logging.dm b/code/controllers/subsystem/dynamic/dynamic_logging.dm
index 16bd56a730316..3e4987ecf7340 100644
--- a/code/controllers/subsystem/dynamic/dynamic_logging.dm
+++ b/code/controllers/subsystem/dynamic/dynamic_logging.dm
@@ -74,7 +74,6 @@
serialized["threat_level"] = threat_level
serialized["round_start_budget"] = initial_round_start_budget
serialized["mid_round_budget"] = threat_level - initial_round_start_budget
- serialized["shown_threat"] = shown_threat
var/list/serialized_snapshots = list()
for (var/datum/dynamic_snapshot/snapshot as anything in snapshots)
From 163380a7d9ab56eae1754a3e1f253977c95b4d8e Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 05:46:04 +0000
Subject: [PATCH 31/35] Automatic changelog for PR #89150 [ci skip]
---
html/changelogs/AutoChangeLog-pr-89150.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-89150.yml
diff --git a/html/changelogs/AutoChangeLog-pr-89150.yml b/html/changelogs/AutoChangeLog-pr-89150.yml
new file mode 100644
index 0000000000000..685f90e5b0f25
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-89150.yml
@@ -0,0 +1,4 @@
+author: "Vekter"
+delete-after: True
+changes:
+ - balance: "The roundstart report will now display a more broad, less specific message about threat levels when between 0 and 80 threat."
\ No newline at end of file
From 17010c11822c21ff4af94986bfc8dd2e72dd609a Mon Sep 17 00:00:00 2001
From: The Sharkening <95130227+StrangeWeirdKitten@users.noreply.github.com>
Date: Wed, 22 Jan 2025 05:11:45 -0500
Subject: [PATCH 32/35] Makes the mech repair droid unstackable + mech armor
balance (#88789)
## About The Pull Request
alternative to #88776
Makes the repair droid unable to be stacked and reduces armor slots to 1
on station mechs except the phazon.
## Why It's Good For The Game
You can get to some pretty heavy duty values on certain mechs,
especially the durand, with a very intense rate of healing. This makes
those items unstackable.
![image](https://github.com/user-attachments/assets/714c48ca-f9a1-4452-bc25-9d20070f43be)
## Changelog
:cl:
balance: Reduces armor slots to 1 for all station built mechs except the
phazon.
balance: melee mech armor has been increased to 20 from 15.
balance: mech bullet and laser armor has both been increased to 15 from
10.
balance: You can no longer stack the repair droid on mechs.
/:cl:
---
code/modules/vehicles/mecha/combat/durand.dm | 2 +-
code/modules/vehicles/mecha/combat/gygax.dm | 2 +-
code/modules/vehicles/mecha/combat/honker.dm | 2 +-
code/modules/vehicles/mecha/combat/savannah_ivanov.dm | 2 +-
code/modules/vehicles/mecha/equipment/mecha_equipment.dm | 9 +++++++++
.../vehicles/mecha/equipment/tools/other_tools.dm | 7 ++++---
6 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/code/modules/vehicles/mecha/combat/durand.dm b/code/modules/vehicles/mecha/combat/durand.dm
index 9095197b93ea0..b9d2ccdb6533e 100644
--- a/code/modules/vehicles/mecha/combat/durand.dm
+++ b/code/modules/vehicles/mecha/combat/durand.dm
@@ -18,7 +18,7 @@
MECHA_R_ARM = 1,
MECHA_UTILITY = 3,
MECHA_POWER = 1,
- MECHA_ARMOR = 3,
+ MECHA_ARMOR = 1,
)
var/obj/durand_shield/shield
diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm
index 0acb746c52d4a..638f53d9aaecf 100644
--- a/code/modules/vehicles/mecha/combat/gygax.dm
+++ b/code/modules/vehicles/mecha/combat/gygax.dm
@@ -18,7 +18,7 @@
MECHA_R_ARM = 1,
MECHA_UTILITY = 3,
MECHA_POWER = 1,
- MECHA_ARMOR = 2,
+ MECHA_ARMOR = 1,
)
step_energy_drain = 4
can_use_overclock = TRUE
diff --git a/code/modules/vehicles/mecha/combat/honker.dm b/code/modules/vehicles/mecha/combat/honker.dm
index 39c5ef1d0e8c4..2a3da129ccd4d 100644
--- a/code/modules/vehicles/mecha/combat/honker.dm
+++ b/code/modules/vehicles/mecha/combat/honker.dm
@@ -57,7 +57,7 @@
MECHA_R_ARM = 1,
MECHA_UTILITY = 3,
MECHA_POWER = 1,
- MECHA_ARMOR = 3,
+ MECHA_ARMOR = 2,
)
/obj/vehicle/sealed/mecha/honker/dark/loaded
diff --git a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
index ffc4c61e5a87f..60dad9de64ab5 100644
--- a/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
+++ b/code/modules/vehicles/mecha/combat/savannah_ivanov.dm
@@ -35,7 +35,7 @@
MECHA_R_ARM = 1,
MECHA_UTILITY = 3,
MECHA_POWER = 1,
- MECHA_ARMOR = 3,
+ MECHA_ARMOR = 1,
)
//no tax on flying, since the power cost is in the leap itself.
phasing_energy_drain = 0
diff --git a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
index 2ad10ae028d17..092c8c1044889 100644
--- a/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
+++ b/code/modules/vehicles/mecha/equipment/mecha_equipment.dm
@@ -18,6 +18,8 @@
var/can_be_triggered = FALSE
///Whether the module is currently active
var/active = TRUE
+ ///Can we stack multiple types of the same item?
+ var/unstackable = FALSE
///Label used in the ui next to the Activate/Enable/Disable buttons
var/active_label = "Status"
///Chassis power cell quantity used on activation
@@ -157,6 +159,13 @@
to_chat(user, span_warning("\The [mech]'s left arm is full![mech.equip_by_category[MECHA_R_ARM] || !mech.max_equip_by_category[MECHA_R_ARM] ? "" : " Try right arm!"]"))
return FALSE
return TRUE
+ if(unstackable)
+ var/list/obj/item/mecha_parts/mecha_equipment/contents = mech.equip_by_category[equipment_slot]
+ for(var/obj/equipment as anything in contents)
+ if(src.type == equipment.type)
+ to_chat(user, span_warning("You can't stack more of this item ontop itself!"))
+ return FALSE
+
if(length(mech.equip_by_category[equipment_slot]) == mech.max_equip_by_category[equipment_slot])
to_chat(user, span_warning("This equipment slot is already full!"))
return FALSE
diff --git a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
index 613f82fe85981..a0a1e7443acbb 100644
--- a/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
+++ b/code/modules/vehicles/mecha/equipment/tools/other_tools.dm
@@ -173,7 +173,7 @@
armor_mod = /datum/armor/mecha_equipment_ccw_boost
/datum/armor/mecha_equipment_ccw_boost
- melee = 15
+ melee = 20
/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster
name = "Projectile Shielding"
@@ -184,8 +184,8 @@
armor_mod = /datum/armor/mecha_equipment_ranged_boost
/datum/armor/mecha_equipment_ranged_boost
- bullet = 10
- laser = 10
+ bullet = 15
+ laser = 15
////////////////////////////////// REPAIR DROID //////////////////////////////////////////////////
@@ -196,6 +196,7 @@
icon_state = "repair_droid"
energy_drain = 50
range = 0
+ unstackable = TRUE
can_be_toggled = TRUE
active = FALSE
equipment_slot = MECHA_UTILITY
From fdb81afcaa41e7c4dece7dcaf304a02803246db5 Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 10:17:28 +0000
Subject: [PATCH 33/35] Automatic changelog for PR #88789 [ci skip]
---
html/changelogs/AutoChangeLog-pr-88789.yml | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-88789.yml
diff --git a/html/changelogs/AutoChangeLog-pr-88789.yml b/html/changelogs/AutoChangeLog-pr-88789.yml
new file mode 100644
index 0000000000000..10f5e68880cc7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-88789.yml
@@ -0,0 +1,7 @@
+author: "StrangeWeirdKitten"
+delete-after: True
+changes:
+ - balance: "Reduces armor slots to 1 for all station built mechs except the phazon."
+ - balance: "melee mech armor has been increased to 20 from 15."
+ - balance: "mech bullet and laser armor has both been increased to 15 from 10."
+ - balance: "You can no longer stack the repair droid on mechs."
\ No newline at end of file
From 29869bbcc4a077c9498a4f1d7dd753acb24e0436 Mon Sep 17 00:00:00 2001
From: Ghom <42542238+Ghommie@users.noreply.github.com>
Date: Wed, 22 Jan 2025 11:28:49 +0100
Subject: [PATCH 34/35] Makes chasms not spawn things when explosions happen
again. (#89132)
---
code/modules/fishing/sources/source_types.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/fishing/sources/source_types.dm b/code/modules/fishing/sources/source_types.dm
index af975bb4ccdb4..02df0ff9e7c0c 100644
--- a/code/modules/fishing/sources/source_types.dm
+++ b/code/modules/fishing/sources/source_types.dm
@@ -159,7 +159,6 @@
radial_name = "Chasm"
overlay_state = "portal_chasm"
radial_state = "ground_hole"
- fish_source_flags = FISH_SOURCE_FLAG_EXPLOSIVE_NONE
/datum/fish_source/portal/ocean
fish_table = list(
@@ -327,6 +326,7 @@
/datum/chasm_detritus = 30,
)
fishing_difficulty = FISHING_DEFAULT_DIFFICULTY + 15
+ fish_source_flags = FISH_SOURCE_FLAG_EXPLOSIVE_NONE
/datum/fish_source/chasm/on_start_fishing(obj/item/fishing_rod/rod, mob/fisherman, atom/parent)
. = ..()
From f032bb1d4d982d4ee57c214c18238aaddb45d512 Mon Sep 17 00:00:00 2001
From: "tgstation-ci[bot]"
<179393467+tgstation-ci[bot]@users.noreply.github.com>
Date: Wed, 22 Jan 2025 10:47:50 +0000
Subject: [PATCH 35/35] Automatic changelog for PR #89132 [ci skip]
---
html/changelogs/AutoChangeLog-pr-89132.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-89132.yml
diff --git a/html/changelogs/AutoChangeLog-pr-89132.yml b/html/changelogs/AutoChangeLog-pr-89132.yml
new file mode 100644
index 0000000000000..693684c833982
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-89132.yml
@@ -0,0 +1,4 @@
+author: "Ghommie"
+delete-after: True
+changes:
+ - bugfix: "Chasms are once again incompatible with explosive fishing."
\ No newline at end of file