From 139aa9ee8da16f27edbd27069b208ef366ae2bcc Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 00:25:26 +0000 Subject: [PATCH 01/74] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88951.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89034.yml | 13 ----------- html/changelogs/AutoChangeLog-pr-89073.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89077.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89078.yml | 4 ---- html/changelogs/archive/2025-01.yml | 26 ++++++++++++++++++++++ 6 files changed, 26 insertions(+), 31 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88951.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89034.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89073.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89077.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89078.yml diff --git a/html/changelogs/AutoChangeLog-pr-88951.yml b/html/changelogs/AutoChangeLog-pr-88951.yml deleted file mode 100644 index e3e533e94e325..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88951.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Big smoke puff from cigarettes happen" - - bugfix: "Tram now smashes certain objects it should be smashing again" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89034.yml b/html/changelogs/AutoChangeLog-pr-89034.yml deleted file mode 100644 index decab86f06aa8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89034.yml +++ /dev/null @@ -1,13 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - rscadd: "Adds Carptongue language, spoken by Space Carps." - - rscdel: "Space Carps no longer speak or understand Common. Special carps like Cayenne and Lia can still understand common." - - rscadd: "Space Dragons can speak Draconic and Carptongue." - - rscdel: "Space Dragons no longer speak Common. They can still understand it." - - rscadd: "Ash Drakes and Ice Whelps now speak Draconic." - - rscdel: "Ash Drakes and Ice Whelps no longer speak Common. They can still understand it." - - rscadd: "Fire Sharks now speak Carptongue." - - rscdel: "Fire Sharks no longer speak Common. They can still understand it." - - rscadd: "Fish and Carp Infusion now grant Carptongue, letting you speak to (and understand) Space Carps." - - rscadd: "Sleeping Carp grants you Carptongue, but as most human tongues can't speak it, you'll only be able to understand Space Carps unless you steal a fish tongue." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89073.yml b/html/changelogs/AutoChangeLog-pr-89073.yml deleted file mode 100644 index ee237e305443a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89073.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "gleypi" -delete-after: True -changes: - - spellcheck: "fixed the tong clacking message" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89077.yml b/html/changelogs/AutoChangeLog-pr-89077.yml deleted file mode 100644 index 9f9e0cecc344a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89077.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Majkl-J" -delete-after: True -changes: - - bugfix: "The apiary now correctly checks for podpeople, allowing subtypes of the species to also interact with is." - - code_imp: "Beebox file single letter vars have been told to buzz off." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89078.yml b/html/changelogs/AutoChangeLog-pr-89078.yml deleted file mode 100644 index 4bce2afa62e2d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89078.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - spellcheck: "Exporting a human tongue no longer calls it a 'tounge'." \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index 907156b46f920..2d32d11809347 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -478,3 +478,29 @@ - bugfix: Any bug that would occur from becoming nearsighted with a scarred eye should be fixed now - code_imp: status_effect/grouped merging code has been improved (i hope) +2025-01-17: + 00-Steven: + - spellcheck: Exporting a human tongue no longer calls it a 'tounge'. + Majkl-J: + - bugfix: The apiary now correctly checks for podpeople, allowing subtypes of the + species to also interact with is. + - code_imp: Beebox file single letter vars have been told to buzz off. + Melbert: + - bugfix: Big smoke puff from cigarettes happen + - bugfix: Tram now smashes certain objects it should be smashing again + - rscadd: Adds Carptongue language, spoken by Space Carps. + - rscdel: Space Carps no longer speak or understand Common. Special carps like Cayenne + and Lia can still understand common. + - rscadd: Space Dragons can speak Draconic and Carptongue. + - rscdel: Space Dragons no longer speak Common. They can still understand it. + - rscadd: Ash Drakes and Ice Whelps now speak Draconic. + - rscdel: Ash Drakes and Ice Whelps no longer speak Common. They can still understand + it. + - rscadd: Fire Sharks now speak Carptongue. + - rscdel: Fire Sharks no longer speak Common. They can still understand it. + - rscadd: Fish and Carp Infusion now grant Carptongue, letting you speak to (and + understand) Space Carps. + - rscadd: Sleeping Carp grants you Carptongue, but as most human tongues can't speak + it, you'll only be able to understand Space Carps unless you steal a fish tongue. + gleypi: + - spellcheck: fixed the tong clacking message From 958116f998684f6d86d4f124455ede5d7416aa96 Mon Sep 17 00:00:00 2001 From: EnterTheJake <102721711+EnterTheJake@users.noreply.github.com> Date: Fri, 17 Jan 2025 10:30:20 +0100 Subject: [PATCH 02/74] Resprites the Codex Cicatrix. (#89084) --- icons/obj/antags/eldritch.dmi | Bin 9258 -> 9416 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/antags/eldritch.dmi b/icons/obj/antags/eldritch.dmi index 664311e5c7c478ca645ca31f1cb4fab1ddbea768..0a7b097127cc815b27525f58101a0f456e748b9a 100644 GIT binary patch literal 9416 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 Pv8Jt2 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 ke>$~Rjp(G4;21nvH$=8 From 322bffc3f9d467d5cafa3f41dbd3a6f0a995ac67 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 17 Jan 2025 09:46:15 +0000 Subject: [PATCH 03/74] Automatic changelog for PR #89084 [ci skip] --- html/changelogs/AutoChangeLog-pr-89084.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89084.yml diff --git a/html/changelogs/AutoChangeLog-pr-89084.yml b/html/changelogs/AutoChangeLog-pr-89084.yml new file mode 100644 index 0000000000000..9a4e4f4c458c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89084.yml @@ -0,0 +1,4 @@ +author: "EnterTheJake" +delete-after: True +changes: + - image: "Codex Cicatrix has received a new sprite" \ No newline at end of file From fe0119727802a3aa2e03ef09eba6f12c82d8a188 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 00:24:45 +0000 Subject: [PATCH 04/74] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89084.yml | 4 ---- html/changelogs/archive/2025-01.yml | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89084.yml diff --git a/html/changelogs/AutoChangeLog-pr-89084.yml b/html/changelogs/AutoChangeLog-pr-89084.yml deleted file mode 100644 index 9a4e4f4c458c4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89084.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EnterTheJake" -delete-after: True -changes: - - image: "Codex Cicatrix has received a new sprite" \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index 2d32d11809347..cddfcce1af8e8 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -504,3 +504,6 @@ it, you'll only be able to understand Space Carps unless you steal a fish tongue. gleypi: - spellcheck: fixed the tong clacking message +2025-01-18: + EnterTheJake: + - image: Codex Cicatrix has received a new sprite From 1f94efd34d5725a9d0fe0b1aa401e58e9d824dc8 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sat, 18 Jan 2025 04:30:40 +0300 Subject: [PATCH 05/74] [NO GBP] Fixes active turfs on the new Turreted Outpost ruin (#89112) ## About The Pull Request Forgot about airless plating when designing it, so some air always leaked out from the breached insulator wall every round. ## Changelog :cl: fix: Fixed active turfs on the new Turreted Outpost ruin. /:cl: --- .../SpaceRuins/turretedoutpost.dmm | 71 +++++++++++++------ code/game/turfs/open/floor/misc_floor.dm | 3 + 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm b/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm index fa4f3122564a3..cfb0424aeeebc 100644 --- a/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm +++ b/_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm @@ -50,6 +50,10 @@ /obj/structure/girder, /turf/open/floor/plating, /area/ruin/space/has_grav/turretedoutpost) +"eR" = ( +/obj/structure/foamedmetal/iron, +/turf/open/floor/plating/airless, +/area/ruin/space/has_grav/turretedoutpost) "eT" = ( /obj/effect/turf_decal/trimline/red/line, /obj/effect/turf_decal/trimline/red/line{ @@ -190,7 +194,7 @@ "mf" = ( /obj/structure/lattice, /obj/structure/girder, -/turf/open/floor/plating/rust, +/turf/open/floor/plating/rust/airless, /area/template_noop) "my" = ( /obj/effect/turf_decal/trimline/red/line{ @@ -204,7 +208,7 @@ /area/ruin/space/has_grav/turretedoutpost) "nd" = ( /obj/structure/girder/reinforced, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/ruin/space/has_grav/turretedoutpost) "no" = ( /obj/machinery/light/dim/directional/west, @@ -459,6 +463,10 @@ /obj/structure/marker_beacon/burgundy, /turf/template_noop, /area/ruin/space/has_grav/turretedoutpost) +"Ct" = ( +/obj/structure/girder, +/turf/open/floor/plating/rust/airless, +/area/ruin/space/has_grav/turretedoutpost) "Cu" = ( /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/plating, @@ -577,6 +585,10 @@ /obj/structure/barricade/wooden/crude, /turf/open/floor/iron/dark, /area/ruin/space/has_grav/turretedoutpost) +"Ny" = ( +/obj/structure/girder, +/turf/open/floor/plating/airless, +/area/ruin/space/has_grav/turretedoutpost) "NU" = ( /obj/effect/turf_decal/trimline/red/line{ dir = 8 @@ -650,6 +662,14 @@ /obj/effect/decal/cleanable/cobweb, /turf/open/floor/iron, /area/ruin/space/has_grav/turretedoutpost) +"Sw" = ( +/obj/structure/girder, +/obj/structure/grille, +/turf/open/floor/plating/airless, +/area/ruin/space/has_grav/turretedoutpost) +"Te" = ( +/turf/open/floor/plating/rust/airless, +/area/ruin/space/has_grav/turretedoutpost) "Tg" = ( /obj/effect/turf_decal/siding/thinplating_new/dark, /obj/structure/table/reinforced, @@ -686,6 +706,11 @@ "TY" = ( /turf/open/floor/iron/dark, /area/ruin/space/has_grav/turretedoutpost) +"Ut" = ( +/obj/structure/girder, +/obj/structure/grille, +/turf/open/floor/plating/rust/airless, +/area/ruin/space/has_grav/turretedoutpost) "UD" = ( /obj/effect/turf_decal/tile/red/opposingcorners, /obj/effect/decal/cleanable/dirt/dust, @@ -721,7 +746,7 @@ /obj/structure/girder/displaced, /obj/structure/grille/broken, /obj/effect/mapping_helpers/broken_floor, -/turf/open/floor/plating, +/turf/open/floor/plating/airless, /area/ruin/space/has_grav/turretedoutpost) "VO" = ( /obj/machinery/porta_turret/syndicate/energy/ruin, @@ -904,7 +929,7 @@ ro ro ro nd -up +Te ro ro ro @@ -931,13 +956,13 @@ jM jM ro ro -ID -cD -ID -ID +Sw +Ct +Ut +Sw VB -ID -pO +Sw +eR ro ro jM @@ -961,15 +986,15 @@ Ci bU ro ro -ID -ID +Sw +Sw ro ro ro ro ro -pO -pO +eR +eR ro ro ro @@ -991,8 +1016,8 @@ jM jM jM ro -ID -ID +Sw +Sw ro ro sy @@ -1000,7 +1025,7 @@ fF EA ro ro -ID +Sw ro St pi @@ -1022,7 +1047,7 @@ jM jM jM ro -ID +Ut ro ro hr @@ -1053,7 +1078,7 @@ jM jM jM ro -ID +Ut ro Pf aH @@ -1084,7 +1109,7 @@ bU jM rK ro -ID +Sw ro gn aH @@ -1115,7 +1140,7 @@ bU bU bU ro -pO +eR ro ro lF @@ -1146,8 +1171,8 @@ Ci jM rK ro -pO -cD +eR +Ny ro Lf US diff --git a/code/game/turfs/open/floor/misc_floor.dm b/code/game/turfs/open/floor/misc_floor.dm index 9c2450e5af271..409b572309c8b 100644 --- a/code/game/turfs/open/floor/misc_floor.dm +++ b/code/game/turfs/open/floor/misc_floor.dm @@ -258,6 +258,9 @@ AddElement(/datum/element/rust) color = null +/turf/open/floor/plating/rust/airless + initial_gas_mix = AIRLESS_ATMOS + /turf/open/floor/plating/heretic_rust color = COLOR_GREEN_GRAY From 33742737309bc49b2b2dac94b9a5bfa1a9eda3ac Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 01:31:00 +0000 Subject: [PATCH 06/74] Automatic changelog for PR #89112 [ci skip] --- html/changelogs/AutoChangeLog-pr-89112.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89112.yml diff --git a/html/changelogs/AutoChangeLog-pr-89112.yml b/html/changelogs/AutoChangeLog-pr-89112.yml new file mode 100644 index 0000000000000..b4369a59d8308 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89112.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed active turfs on the new Turreted Outpost ruin." \ No newline at end of file From 1c8def783743b9fb897c2ffc9129156bd64489c0 Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Sat, 18 Jan 2025 04:20:48 +0200 Subject: [PATCH 07/74] Another SmartFridge restyle (#89013) ## About The Pull Request Another SmartFridge restyle aimed at improving the UI/UX. Finally used the new component (ImageButton) as I originally wanted to, but I kept failing. If you need to get a certain amount of fruit, you don't have to type in how much you need and then click on the fruit, just type it in and the fruit will be dispensed immediately, example in the video below. There are a total of 3 options to get what you need with SmartFridge: 1. Just click on the product, you will get 1 unit, nothing new. 2. Enter the required value, this was already there but it became a bit more convenient because you don't have to click on the product after entering it. 3. Press Right Mouse Button to get everything at once. ## Why It's Good For The Game Better UI/UX (No offense to those who made the past variations, they tried their best, but now there is a special component for such purposes, which makes it very much easier) ## Demonstration
Comparison screenshots | Old (Grid) | New (Grid) | | - | - | | ![image](https://github.com/user-attachments/assets/e4ee68fd-c984-402b-a265-864c08f17771) | ![image](https://github.com/user-attachments/assets/a5334f86-22a4-4509-a6c7-09e5b39cc113) | | Old (List) | New (List) | - | - | | ![image](https://github.com/user-attachments/assets/ef5e4a29-470d-4c5e-9776-5bf2af508fb5) | ![image](https://github.com/user-attachments/assets/653ad2f0-247e-4002-8f1f-93b76c77ff67) |
Video https://github.com/user-attachments/assets/c8788707-5947-4f1e-8a3c-6a56ac983e98
## Changelog :cl: qol: SmartFridge got another redesign, and you can dispense all amount of product in one click (RMB on product) /:cl: --- tgui/packages/tgui-bench/package.json | 2 +- tgui/packages/tgui-panel/package.json | 2 +- tgui/packages/tgui-say/package.json | 2 +- tgui/packages/tgui/interfaces/SmartVend.tsx | 328 ++++++++------------ tgui/packages/tgui/package.json | 2 +- tgui/yarn.lock | 16 +- 6 files changed, 149 insertions(+), 203 deletions(-) diff --git a/tgui/packages/tgui-bench/package.json b/tgui/packages/tgui-bench/package.json index 6a42b87af9fde..9a99745a5cb3b 100644 --- a/tgui/packages/tgui-bench/package.json +++ b/tgui/packages/tgui-bench/package.json @@ -12,6 +12,6 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "tgui": "workspace:*", - "tgui-core": "^1.7.2" + "tgui-core": "^1.7.4" } } diff --git a/tgui/packages/tgui-panel/package.json b/tgui/packages/tgui-panel/package.json index 4b521d0618507..4f03130458695 100644 --- a/tgui/packages/tgui-panel/package.json +++ b/tgui/packages/tgui-panel/package.json @@ -10,7 +10,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "tgui": "workspace:*", - "tgui-core": "^1.7.2", + "tgui-core": "^1.7.4", "tgui-dev-server": "workspace:*", "tgui-polyfill": "workspace:*" } diff --git a/tgui/packages/tgui-say/package.json b/tgui/packages/tgui-say/package.json index b535dbccad6bc..6d3fb9f7bf9d5 100644 --- a/tgui/packages/tgui-say/package.json +++ b/tgui/packages/tgui-say/package.json @@ -9,7 +9,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "tgui": "workspace:*", - "tgui-core": "^1.7.2", + "tgui-core": "^1.7.4", "tgui-polyfill": "workspace:*" } } diff --git a/tgui/packages/tgui/interfaces/SmartVend.tsx b/tgui/packages/tgui/interfaces/SmartVend.tsx index 01be12bbf2e58..0937095a9d10c 100644 --- a/tgui/packages/tgui/interfaces/SmartVend.tsx +++ b/tgui/packages/tgui/interfaces/SmartVend.tsx @@ -1,8 +1,7 @@ import { useState } from 'react'; -import { DmIcon, Icon } from 'tgui-core/components'; import { - Box, Button, + ImageButton, Input, NoticeBox, NumberInput, @@ -48,44 +47,57 @@ export const SmartVend = (props) => { ? Object.values(data.contents).filter(search) : Object.values(data.contents); return ( - +
act('Dry')} - > - {data.drying ? 'Stop drying' : 'Dry'} - - ) : ( - <> - setSearchText(value)} - /> + <> + {data.isdryer ? ( + ) : ( + <> + setSearchText(value)} + /> + - - {item.name} - - + 1 && ( + { + act('Release', { + path: item.path, + amount: value, + }); + }} + /> + ) + } + buttonsAlt={ + + + + x{item.amount} + + + } + onClick={() => + act('Release', { + path: item.path, + amount: 1, + }) + } + onRightClick={() => + act('Release', { + path: item.path, + amount: item.amount, + }) + } + > + {item.name} + ) as any; }; const ItemList = ({ item }) => { const { act } = useBackend(); - const fallback = ( - - ); - const [itemCount, setItemCount] = useState(1); + const disabled = item.amount <= 1; return ( - - - - - - {item.name} - - - - - {item.amount > 1 && ( - - {`x${item.amount}`} + + } + onClick={() => + act('Release', { + path: item.path, + amount: 1, + }) + } + onRightClick={() => + act('Release', { + path: item.path, + amount: item.amount, + }) + } + > + + {item.name} + + x{item.amount} - )} - - - setItemCount(value)} - /> - - + + ) as any; }; diff --git a/tgui/packages/tgui/package.json b/tgui/packages/tgui/package.json index 3e9ef3c02cf22..c8fa431eaa0a6 100644 --- a/tgui/packages/tgui/package.json +++ b/tgui/packages/tgui/package.json @@ -18,7 +18,7 @@ "react": "^18.3.1", "react-dom": "^18.3.1", "react-popper": "^2.3.0", - "tgui-core": "^1.7.2", + "tgui-core": "^1.7.4", "tgui-dev-server": "workspace:*", "tgui-polyfill": "workspace:*" } diff --git a/tgui/yarn.lock b/tgui/yarn.lock index b080e0484a3cc..4f425cb8bd638 100644 --- a/tgui/yarn.lock +++ b/tgui/yarn.lock @@ -18723,17 +18723,17 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" tgui: "workspace:*" - tgui-core: "npm:^1.7.2" + tgui-core: "npm:^1.7.4" languageName: unknown linkType: soft -"tgui-core@npm:^1.7.2": - version: 1.7.2 - resolution: "tgui-core@npm:1.7.2" +"tgui-core@npm:^1.7.4": + version: 1.7.4 + resolution: "tgui-core@npm:1.7.4" peerDependencies: react: ^18.2.0 react-dom: ^18.2.0 - checksum: 10c0/401102042d4d0ede4f8658160124cd523c4ffc44492e0f7d0500d25e0b8a085be2b6f829c89b81eb706c369af16d6d57375704337d7bcc813480caa749c258d4 + checksum: 10c0/06b9d8702d6ae170383b28725bf6308cd320499367ea8ea1f9dd5039ab371cfe34419a7d3d1e0e2b86884326e8d4ab116e5601208d2f85d215b7c464fd32fdbf languageName: node linkType: hard @@ -18761,7 +18761,7 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" tgui: "workspace:*" - tgui-core: "npm:^1.7.2" + tgui-core: "npm:^1.7.4" tgui-dev-server: "workspace:*" tgui-polyfill: "workspace:*" languageName: unknown @@ -18788,7 +18788,7 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" tgui: "workspace:*" - tgui-core: "npm:^1.7.2" + tgui-core: "npm:^1.7.4" tgui-polyfill: "workspace:*" languageName: unknown linkType: soft @@ -18850,7 +18850,7 @@ __metadata: react: "npm:^18.3.1" react-dom: "npm:^18.3.1" react-popper: "npm:^2.3.0" - tgui-core: "npm:^1.7.2" + tgui-core: "npm:^1.7.4" tgui-dev-server: "workspace:*" tgui-polyfill: "workspace:*" languageName: unknown From 0f24743cbbdb298dd4a7dfdca169ceda747944fa Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Jan 2025 05:21:40 +0300 Subject: [PATCH 08/74] Fixed plant analyzer crash when the plant graft gives reagent gene, rather than trait gene [NO GBP] (#89089) ## About The Pull Request ![image](https://github.com/user-attachments/assets/3d4c5d7a-904c-4b63-a6c8-8c65e1a490da) Didn't know that some plants have reagent traits defined for grafted traits. It didn't work because the trait_db contained only subtypes of `/datum/plant_gene/trait`, but not `/datum/plant_gene/reagent`. ## Why It's Good For The Game Fix ## Changelog :cl: fix: Fixed plant analyzer UI crashing on plants that have a reagent gene on their graft fix: Plants with reagent traits in the graft now properly say the name of the grafted reagent /:cl: --- code/__HELPERS/global_lists.dm | 2 +- code/_globalvars/lists/objects.dm | 2 -- code/_globalvars/lists/reagents.dm | 2 ++ code/game/objects/items/devices/scanners/plant_analyzer.dm | 4 ++-- code/modules/hydroponics/plant_genes.dm | 7 ++++--- code/modules/hydroponics/seed_extractor.dm | 4 ++-- tgui/packages/tgui/interfaces/SeedExtractor.tsx | 4 +++- 7 files changed, 14 insertions(+), 11 deletions(-) diff --git a/code/__HELPERS/global_lists.dm b/code/__HELPERS/global_lists.dm index 3ddfb73dfe419..7df14b5fa2d77 100644 --- a/code/__HELPERS/global_lists.dm +++ b/code/__HELPERS/global_lists.dm @@ -219,7 +219,7 @@ GLOBAL_LIST_INIT(allowed_money, typecacheof(list( /// Inits GLOB.plant_traits /proc/init_plant_traits() var/traits = list() - for(var/trait_path in subtypesof(/datum/plant_gene/trait)) + for(var/trait_path in subtypesof(/datum/plant_gene)) traits += new trait_path sort_list(traits, GLOBAL_PROC_REF(cmp_typepaths_asc)) return traits diff --git a/code/_globalvars/lists/objects.dm b/code/_globalvars/lists/objects.dm index 1d7b2109be128..4707ebf0a962e 100644 --- a/code/_globalvars/lists/objects.dm +++ b/code/_globalvars/lists/objects.dm @@ -104,5 +104,3 @@ GLOBAL_LIST_INIT(prototype_organs, typecacheof(list( /obj/item/organ/eyes/dullahan, ), only_root_path = TRUE)) -/// list of all plan traits -GLOBAL_LIST_INIT(plant_traits, init_plant_traits()) diff --git a/code/_globalvars/lists/reagents.dm b/code/_globalvars/lists/reagents.dm index dc18f9814c63f..b760b5c6d6934 100644 --- a/code/_globalvars/lists/reagents.dm +++ b/code/_globalvars/lists/reagents.dm @@ -56,6 +56,8 @@ GLOBAL_LIST_INIT(blacklisted_metalgen_types, typecacheof(list( ))) /// Map of reagent names to its datum path GLOBAL_LIST_INIT(name2reagent, build_name2reagentlist()) +/// list of all plan traits +GLOBAL_LIST_INIT(plant_traits, init_plant_traits()) /// Initialises all /datum/reagent into a list indexed by reagent id /proc/init_chemical_reagent_list() diff --git a/code/game/objects/items/devices/scanners/plant_analyzer.dm b/code/game/objects/items/devices/scanners/plant_analyzer.dm index 86980d2ee1574..25bfab652f796 100644 --- a/code/game/objects/items/devices/scanners/plant_analyzer.dm +++ b/code/game/objects/items/devices/scanners/plant_analyzer.dm @@ -140,10 +140,10 @@ var/list/data = list() data["cycle_seconds"] = HYDROTRAY_CYCLE_DELAY / 10 data["trait_db"] = list() - for(var/datum/plant_gene/trait/trait as anything in GLOB.plant_traits) + for(var/datum/plant_gene/trait as anything in GLOB.plant_traits) var/trait_data = list(list( "path" = trait.type, - "name" = trait.name, + "name" = trait.get_name(), "icon" = trait.icon, "description" = trait.description )) diff --git a/code/modules/hydroponics/plant_genes.dm b/code/modules/hydroponics/plant_genes.dm index 7dbfc4262ed77..278ec19228e8d 100644 --- a/code/modules/hydroponics/plant_genes.dm +++ b/code/modules/hydroponics/plant_genes.dm @@ -2,6 +2,8 @@ /datum/plant_gene /// The name of the gene. var/name + /// Bonus lines displayed on examine. + var/description = "" /// The font awesome icon name representing the gene in the seed extractor UI var/icon = FA_ICON_DNA /// Flags that determine if a gene can be modified. @@ -62,7 +64,8 @@ var/formatted_name if(!(mutability_flags & PLANT_GENE_REMOVABLE)) formatted_name += "Fragile " - formatted_name += "[name] production [rate*100]%" + var/datum/reagent/reagent = reagent_id + formatted_name += "[reagent.name] production [rate*100]%" return formatted_name /* @@ -117,8 +120,6 @@ /datum/plant_gene/trait /// The rate at which this trait affects something. This can be anything really - why? I dunno. var/rate = 0.05 - /// Bonus lines displayed on examine. - var/description = "" /// Flag - Traits that share an ID cannot be placed on the same plant. var/trait_ids /// Flag - Modifications made to the final product. diff --git a/code/modules/hydroponics/seed_extractor.dm b/code/modules/hydroponics/seed_extractor.dm index ae94580ada591..0df75d987e9c2 100644 --- a/code/modules/hydroponics/seed_extractor.dm +++ b/code/modules/hydroponics/seed_extractor.dm @@ -268,10 +268,10 @@ var/list/data = list() data["cycle_seconds"] = HYDROTRAY_CYCLE_DELAY / 10 data["trait_db"] = list() - for(var/datum/plant_gene/trait/trait as anything in GLOB.plant_traits) + for(var/datum/plant_gene/trait as anything in GLOB.plant_traits) var/trait_data = list(list( "path" = trait.type, - "name" = trait.name, + "name" = trait.get_name(), "icon" = trait.icon, "description" = trait.description )) diff --git a/tgui/packages/tgui/interfaces/SeedExtractor.tsx b/tgui/packages/tgui/interfaces/SeedExtractor.tsx index 9e868f3238102..defb9fb9fb2e8 100644 --- a/tgui/packages/tgui/interfaces/SeedExtractor.tsx +++ b/tgui/packages/tgui/interfaces/SeedExtractor.tsx @@ -436,9 +436,11 @@ export const TraitTooltip = (props) => { const trait = props.trait_db.find((t) => { return t.path === props.path; }); + if (!trait) { + return; + } return ( {!!props.grafting && ( From a5ead86807f91fb9e76eaad4c7a1cd13c191b35c Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 02:26:52 +0000 Subject: [PATCH 09/74] Automatic changelog for PR #89013 [ci skip] --- html/changelogs/AutoChangeLog-pr-89013.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89013.yml diff --git a/html/changelogs/AutoChangeLog-pr-89013.yml b/html/changelogs/AutoChangeLog-pr-89013.yml new file mode 100644 index 0000000000000..ad7c6be528824 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89013.yml @@ -0,0 +1,4 @@ +author: "AyIong" +delete-after: True +changes: + - qol: "SmartFridge got another redesign, and you can dispense all amount of product in one click (RMB on product)" \ No newline at end of file From 2df57ac33ee650e71faebfe5dd8d34fdcaf42049 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 02:27:10 +0000 Subject: [PATCH 10/74] Automatic changelog for PR #89089 [ci skip] --- html/changelogs/AutoChangeLog-pr-89089.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89089.yml diff --git a/html/changelogs/AutoChangeLog-pr-89089.yml b/html/changelogs/AutoChangeLog-pr-89089.yml new file mode 100644 index 0000000000000..c6e81b3c33688 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89089.yml @@ -0,0 +1,5 @@ +author: "MTandi" +delete-after: True +changes: + - bugfix: "Fixed plant analyzer UI crashing on plants that have a reagent gene on their graft" + - bugfix: "Plants with reagent traits in the graft now properly say the name of the grafted reagent" \ No newline at end of file From e3933ba938a75942766033558c1df261d33c3377 Mon Sep 17 00:00:00 2001 From: Andrew Date: Sat, 18 Jan 2025 10:06:36 +0300 Subject: [PATCH 11/74] This year's medkit resprite (#89085) --- code/game/objects/items/storage/medkit.dm | 11 +++++++---- ...reenshot_humanoids__datum_species_moth.png | Bin 1648 -> 1618 bytes .../inhands/equipment/medical_lefthand.dmi | Bin 15464 -> 15978 bytes .../inhands/equipment/medical_righthand.dmi | Bin 17853 -> 17618 bytes icons/obj/storage/medkit.dmi | Bin 6343 -> 7665 bytes 5 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/storage/medkit.dm b/code/game/objects/items/storage/medkit.dm index 9441d879799a2..2d8bb5b9d769f 100644 --- a/code/game/objects/items/storage/medkit.dm +++ b/code/game/objects/items/storage/medkit.dm @@ -108,6 +108,7 @@ /obj/item/storage/medkit/emergency icon_state = "medbriefcase" + inhand_icon_state = "medkit-emergency" name = "emergency medkit" desc = "A very simple first aid kit meant to secure and stabilize serious wounds for later treatment." @@ -127,7 +128,7 @@ /obj/item/storage/medkit/surgery name = "surgical medkit" icon_state = "medkit_surgery" - inhand_icon_state = "medkit" + inhand_icon_state = "medkit-surgical" desc = "A high capacity aid kit for doctors, full of medical supplies and basic surgical equipment." /obj/item/storage/medkit/surgery/Initialize(mapload) @@ -275,7 +276,7 @@ name = "advanced first aid kit" desc = "An advanced kit to help deal with advanced wounds." icon_state = "medkit_advanced" - inhand_icon_state = "medkit-rad" + inhand_icon_state = "medkit-advanced" custom_premium_price = PAYCHECK_COMMAND * 6 damagetype_healed = HEAL_ALL_DAMAGE @@ -294,8 +295,8 @@ /obj/item/storage/medkit/tactical_lite name = "combat first aid kit" - icon_state = "medkit_tactical" - inhand_icon_state = "medkit-tactical" + icon_state = "medkit_tactical_lite" + inhand_icon_state = "medkit-tactical-lite" damagetype_healed = HEAL_ALL_DAMAGE /obj/item/storage/medkit/tactical_lite/get_medbot_skin() @@ -350,6 +351,8 @@ /obj/item/storage/medkit/tactical/premium name = "premium combat medical kit" desc = "May or may not contain traces of lead." + icon_state = "medkit_tactical_premium" + inhand_icon_state = "medkit-tactical-premium" grind_results = list(/datum/reagent/lead = 10) /obj/item/storage/medkit/tactical/premium/Initialize(mapload) diff --git a/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_moth.png b/code/modules/unit_tests/screenshots/screenshot_humanoids__datum_species_moth.png index 284205a73ec132117c951f148a2dc7f207e5e6da..ba18a7ec165bdb5a04168f371c987b8d5a140a52 100644 GIT binary patch delta 1290 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 literal 15464 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 OSVzm?PKk!Y^Zx;KXS~_~ literal 17853 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 Qp5YQaSJMO6t2jjc2Y?_p2><{9 literal 6343 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 WmJ-sm<@V16p01XjW{tXC#J>Uf>wz!; From dac262d09f32029b3dea94b52a8cd1c01b386c37 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 07:06:57 +0000 Subject: [PATCH 12/74] Automatic changelog for PR #89085 [ci skip] --- html/changelogs/AutoChangeLog-pr-89085.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89085.yml diff --git a/html/changelogs/AutoChangeLog-pr-89085.yml b/html/changelogs/AutoChangeLog-pr-89085.yml new file mode 100644 index 0000000000000..a4df0c607ead2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89085.yml @@ -0,0 +1,4 @@ +author: "MTandi" +delete-after: True +changes: + - image: "yet another medkit resprite" \ No newline at end of file From 94e18a02d3c9837c55a8df21f6c29d3dcb0efc36 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Sat, 18 Jan 2025 02:41:09 -0600 Subject: [PATCH 13/74] Smol cleanup of `autopsy/success` (#89094) --- code/modules/surgery/autopsy.dm | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/code/modules/surgery/autopsy.dm b/code/modules/surgery/autopsy.dm index d0ada2dce55b1..3efb02f776a58 100644 --- a/code/modules/surgery/autopsy.dm +++ b/code/modules/surgery/autopsy.dm @@ -44,17 +44,15 @@ ) display_pain(target, "You feel a burning sensation in your chest!") -/datum/surgery_step/autopsy/success(mob/user, mob/living/carbon/target, target_zone, obj/item/autopsy_scanner/tool, datum/surgery/surgery, default_display_results = FALSE) +/datum/surgery_step/autopsy/success(mob/living/user, mob/living/carbon/target, target_zone, obj/item/autopsy_scanner/tool, datum/surgery/surgery, default_display_results = FALSE) ADD_TRAIT(target, TRAIT_DISSECTED, AUTOPSY_TRAIT) - if(!HAS_TRAIT(src, TRAIT_SURGICALLY_ANALYZED)) - ADD_TRAIT(target, TRAIT_SURGICALLY_ANALYZED, AUTOPSY_TRAIT) + ADD_TRAIT(target, TRAIT_SURGICALLY_ANALYZED, AUTOPSY_TRAIT) tool.scan_cadaver(user, target) var/obj/machinery/computer/operating/operating_computer = surgery.locate_operating_computer(get_turf(target)) if (!isnull(operating_computer)) SEND_SIGNAL(operating_computer, COMSIG_OPERATING_COMPUTER_AUTOPSY_COMPLETE, target) - if(HAS_MIND_TRAIT(user, TRAIT_MORBID) && ishuman(user)) - var/mob/living/carbon/human/morbid_weirdo = user - morbid_weirdo.add_mood_event("morbid_dissection_success", /datum/mood_event/morbid_dissection_success) + if(HAS_MIND_TRAIT(user, TRAIT_MORBID)) + user.add_mood_event("morbid_dissection_success", /datum/mood_event/morbid_dissection_success) return ..() /datum/surgery_step/autopsy/failure(mob/user, mob/living/carbon/target, target_zone, obj/item/tool, datum/surgery/surgery) From 04a67230b4c551f02dcb622290ff25d7101eba33 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Sat, 18 Jan 2025 13:25:39 +0000 Subject: [PATCH 14/74] Grillable foods grill in hot air (#88914) ## About The Pull Request This PR makes is so that if the air is hot enough to trigger a fire door to close, grillable foods left out in the open will grill themselves. I picked the minimum grilling temperature essentially at random because I don't know what heat units are or should be, but the define `FIRE_MINIMUM_TEMPERATURE_TO_EXIST` sounded about right. IMPORTANT NOTE: **All foods are grillable by default** and become "burned mess" after about 30 seconds. If this seems like too much of a grief vector (a significant fire in the kitchen may cause all food to grill itself into oblivion) I can make this optional rather than a default-enabled thing on all food. IDK whether or not this matters, because all food is also flammable. Food will only grill based on air temperature if it is set out on an open tile (including while on a table), not while in your hands or backpack or pockets or a closet or inside an oven or (oddly enough) while on a grill. ## Why It's Good For The Game it increases my emulsion if eggs can fry on a hot sidewalk ## Changelog :cl: add: Eggs (and all other edible food) left in a hot place will fry. /:cl: --- code/datums/components/grillable.dm | 80 +++++++++++++++++++++++++---- 1 file changed, 71 insertions(+), 9 deletions(-) diff --git a/code/datums/components/grillable.dm b/code/datums/components/grillable.dm index f584808a1f3bd..3b3ef047c833f 100644 --- a/code/datums/components/grillable.dm +++ b/code/datums/components/grillable.dm @@ -1,3 +1,5 @@ +#define IDEAL_GRILLING_TEMPERATURE 200 + T0C + /datum/component/grillable dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // So you can change grill results with various cookstuffs ///Result atom type of grilling this object @@ -14,6 +16,12 @@ var/who_placed_us /// Reagents that should be added to the result var/list/added_reagents + /// Open turf we were last placed on, to check temperature + var/turf/open/listening_turf + /// Are we grilling right now? + var/is_grilling = FALSE + /// What's our current air temperature? + var/current_temperature = 0 /datum/component/grillable/Initialize(cook_result, required_cook_time, positive_result, use_large_steam_sprite, list/added_reagents) . = ..() @@ -32,14 +40,20 @@ RegisterSignal(parent, COMSIG_ITEM_GRILL_TURNED_OFF, PROC_REF(on_grill_turned_off)) RegisterSignal(parent, COMSIG_ITEM_GRILL_PROCESS, PROC_REF(on_grill)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) + RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_location_changed)) + on_location_changed(parent) /datum/component/grillable/UnregisterFromParent() + if (listening_turf) + UnregisterSignal(listening_turf, COMSIG_TURF_EXPOSE) + UnregisterSignal(parent, list( COMSIG_ATOM_EXAMINE, COMSIG_ITEM_GRILL_TURNED_ON, COMSIG_ITEM_GRILL_TURNED_OFF, COMSIG_ITEM_GRILL_PROCESS, COMSIG_ITEM_GRILL_PLACED, + COMSIG_MOVABLE_MOVED )) // Inherit the new values passed to the component @@ -55,6 +69,32 @@ if(use_large_steam_sprite) src.use_large_steam_sprite = use_large_steam_sprite +/datum/component/grillable/Destroy(force) + . = ..() + STOP_PROCESSING(SSmachines, src) + listening_turf = null + +/// Signal proc for [COMSIG_MOVABLE_MOVED], our location has changed and we should register for temperature information +/datum/component/grillable/proc/on_location_changed(atom/source) + SIGNAL_HANDLER + + if (is_grilling) + on_grill_turned_off(source) + STOP_PROCESSING(SSmachines, src) + + if (listening_turf) + UnregisterSignal(listening_turf, COMSIG_TURF_EXPOSE) + + if (isnull(source)) + return + + var/turf/open/current_turf = source.loc + if (!isopenturf(current_turf)) + return + listening_turf = current_turf + RegisterSignal(current_turf, COMSIG_TURF_EXPOSE, PROC_REF(on_turf_atmos_changed)) + on_turf_atmos_changed(current_turf, current_turf.air, current_turf.air?.temperature || 0) + /// Signal proc for [COMSIG_ITEM_GRILL_PLACED], item is placed on the grill. /datum/component/grillable/proc/on_grill_placed(datum/source, mob/griller) SIGNAL_HANDLER @@ -62,12 +102,11 @@ if(griller && griller.mind) who_placed_us = REF(griller.mind) - RegisterSignal(parent, COMSIG_MOVABLE_MOVED, PROC_REF(on_moved)) - /// Signal proc for [COMSIG_ITEM_GRILL_TURNED_ON], starts the grilling process. /datum/component/grillable/proc/on_grill_turned_on(datum/source) RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(add_grilled_item_overlay)) + is_grilling = TRUE var/atom/atom_parent = parent atom_parent.update_appearance() @@ -75,6 +114,7 @@ /datum/component/grillable/proc/on_grill_turned_off(datum/source) UnregisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS) + is_grilling = FALSE var/atom/atom_parent = parent atom_parent.update_appearance() @@ -138,15 +178,37 @@ else examine_list += span_danger("[parent] should probably not be put on the grill.") -///Ran when an object moves from the grill -/datum/component/grillable/proc/on_moved(atom/source, atom/OldLoc, Dir, Forced) +/datum/component/grillable/proc/add_grilled_item_overlay(datum/source, list/overlays) SIGNAL_HANDLER - UnregisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS) - UnregisterSignal(parent, COMSIG_MOVABLE_MOVED) - source.update_appearance() + overlays += mutable_appearance('icons/effects/steam.dmi', "[use_large_steam_sprite ? "steam_triple" : "steam_single"]", ABOVE_OBJ_LAYER) -/datum/component/grillable/proc/add_grilled_item_overlay(datum/source, list/overlays) +/// Signal proc for [COMSIG_TURF_EXPOSE], atmosphere might be hot enough for grilling. +/datum/component/grillable/proc/on_turf_atmos_changed(turf/open/source, datum/gas_mixture/air, exposed_temperature) SIGNAL_HANDLER - overlays += mutable_appearance('icons/effects/steam.dmi', "[use_large_steam_sprite ? "steam_triple" : "steam_single"]", ABOVE_OBJ_LAYER) + if (!is_grilling) + if (exposed_temperature < FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + return + on_grill_turned_on(source) + START_PROCESSING(SSmachines, src) + current_temperature = exposed_temperature + else + if (exposed_temperature >= FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + current_temperature = exposed_temperature + return + on_grill_turned_off(source) + STOP_PROCESSING(SSmachines, src) + +// Grill while exposed to hot air +/datum/component/grillable/process(seconds_per_tick) + var/atom/atom_parent = parent + + // Grill faster as we approach 200 degrees celsius + var/check_temperature = clamp(current_temperature, FIRE_MINIMUM_TEMPERATURE_TO_EXIST, IDEAL_GRILLING_TEMPERATURE) + var/temp_scale = (check_temperature - FIRE_MINIMUM_TEMPERATURE_TO_EXIST) / (IDEAL_GRILLING_TEMPERATURE - FIRE_MINIMUM_TEMPERATURE_TO_EXIST) + var/speed_modifier = LERP(0.5, 1, temp_scale) + + on_grill(parent, atom_parent.loc, seconds_per_tick * speed_modifier) + +#undef IDEAL_GRILLING_TEMPERATURE From 63f42818b8e0321674d389ebd844a0b57abcffa7 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:25:59 +0000 Subject: [PATCH 15/74] Automatic changelog for PR #88914 [ci skip] --- html/changelogs/AutoChangeLog-pr-88914.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88914.yml diff --git a/html/changelogs/AutoChangeLog-pr-88914.yml b/html/changelogs/AutoChangeLog-pr-88914.yml new file mode 100644 index 0000000000000..8bea08ce11599 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88914.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - rscadd: "Eggs (and all other edible food) left in a hot place will fry." \ No newline at end of file From 4f14df11b624f673470a3398a0c6781df2e40071 Mon Sep 17 00:00:00 2001 From: Chowder-McArthor <166885501+Chowder-McArthor@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:22:07 -0800 Subject: [PATCH 16/74] Redo of the Geyser Code: Second Attempt (#89111) ## About The Pull Request Makes it so strange geysers now say their name when scanned. ## Why It's Good For The Game Should help make geysers actually worthwhile now that it's easier to tell what they produce. ## Changelog :cl: qol: Strange geysers now say in their name what they produce. /:cl: --- code/game/objects/structures/lavaland/geyser.dm | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/code/game/objects/structures/lavaland/geyser.dm b/code/game/objects/structures/lavaland/geyser.dm index 9a546e8154d9f..fa0fd02e21cec 100644 --- a/code/game/objects/structures/lavaland/geyser.dm +++ b/code/game/objects/structures/lavaland/geyser.dm @@ -106,11 +106,12 @@ /obj/structure/geyser/random point_value = 500 - true_name = "strange geyser" - discovery_message = "It's a strange geyser! How does any of this even work?" //it doesnt /obj/structure/geyser/random/Initialize(mapload) reagent_id = get_random_reagent_id() + var/datum/reagent/Random_Reagent = reagent_id + true_name = "[initial(Random_Reagent.name)] geyser" + discovery_message = "It's a [initial(Random_Reagent.name)] geyser! How does any of this even work?" //it doesnt return ..() From d1e3444dd7e947b692e6b94bd954bf37ad020451 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 21:22:46 +0000 Subject: [PATCH 17/74] Automatic changelog for PR #89111 [ci skip] --- html/changelogs/AutoChangeLog-pr-89111.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89111.yml diff --git a/html/changelogs/AutoChangeLog-pr-89111.yml b/html/changelogs/AutoChangeLog-pr-89111.yml new file mode 100644 index 0000000000000..d44499f99f2fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89111.yml @@ -0,0 +1,4 @@ +author: "Chowder-McArthor" +delete-after: True +changes: + - qol: "Strange geysers now say in their name what they produce." \ No newline at end of file From 8c721d11f9abb79503d22cdb3ce4efc1c451ea5c Mon Sep 17 00:00:00 2001 From: Lucy Date: Sat, 18 Jan 2025 16:58:23 -0500 Subject: [PATCH 18/74] Small and tiny mobs no longer trigger the squeak component (#89100) ## About The Pull Request This prevents mobs with `MOB_SIZE_SMALL` or `MOB_SIZE_TINY` from triggering squeak sounds on crossed. Simple enough. Also made the cooldown use the cooldown macros. ## Why It's Good For The Game Small or tiny mobs are, well, tiny, and wouldn't really be able to trigger the same kinda reaction. Also sound spam is universally bad, and this gets rid of another method of sound spam. ## Changelog :cl: qol: Small and tiny mobs no longer trigger squeaking objects when walking over them. /:cl: --- code/datums/components/squeak.dm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/datums/components/squeak.dm b/code/datums/components/squeak.dm index ca1bb82ace785..ec900943997f1 100644 --- a/code/datums/components/squeak.dm +++ b/code/datums/components/squeak.dm @@ -11,8 +11,8 @@ var/step_delay = 1 // This is to stop squeak spam from inhand usage - var/last_use = 0 - var/use_delay = 20 + COOLDOWN_DECLARE(spam_cooldown) + var/use_delay = 2 SECONDS ///extra-range for this component's sound var/sound_extra_range = -1 @@ -102,6 +102,10 @@ return if(ismob(arrived) && !arrived.density) // Prevents 10 overlapping mice from making an unholy sound while moving return + if(isliving(arrived)) + var/mob/living/living_arrived = arrived + if(living_arrived.mob_size < MOB_SIZE_HUMAN) + return var/atom/current_parent = parent if(isturf(current_parent?.loc)) play_squeak() @@ -109,8 +113,8 @@ /datum/component/squeak/proc/use_squeak() SIGNAL_HANDLER - if(last_use + use_delay < world.time) - last_use = world.time + if(COOLDOWN_FINISHED(src, spam_cooldown)) + COOLDOWN_START(src, spam_cooldown, use_delay) play_squeak() /datum/component/squeak/proc/on_equip(datum/source, mob/equipper, slot) From 1f270eec8d853ee4919b388b86f64f7143b06de4 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sat, 18 Jan 2025 21:58:45 +0000 Subject: [PATCH 19/74] Automatic changelog for PR #89100 [ci skip] --- html/changelogs/AutoChangeLog-pr-89100.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89100.yml diff --git a/html/changelogs/AutoChangeLog-pr-89100.yml b/html/changelogs/AutoChangeLog-pr-89100.yml new file mode 100644 index 0000000000000..a9ccbbf619da8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89100.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - qol: "Small and tiny mobs no longer trigger squeaking objects when walking over them." \ No newline at end of file From ed54b220443ea7f89c00182bba5a3334a91ba2da Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 00:35:08 +0000 Subject: [PATCH 20/74] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88914.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89013.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89085.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89089.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89100.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89111.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89112.yml | 4 ---- html/changelogs/archive/2025-01.yml | 19 +++++++++++++++++++ 8 files changed, 19 insertions(+), 29 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88914.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89013.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89085.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89089.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89100.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89111.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89112.yml diff --git a/html/changelogs/AutoChangeLog-pr-88914.yml b/html/changelogs/AutoChangeLog-pr-88914.yml deleted file mode 100644 index 8bea08ce11599..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88914.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - rscadd: "Eggs (and all other edible food) left in a hot place will fry." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89013.yml b/html/changelogs/AutoChangeLog-pr-89013.yml deleted file mode 100644 index ad7c6be528824..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89013.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "AyIong" -delete-after: True -changes: - - qol: "SmartFridge got another redesign, and you can dispense all amount of product in one click (RMB on product)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89085.yml b/html/changelogs/AutoChangeLog-pr-89085.yml deleted file mode 100644 index a4df0c607ead2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89085.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MTandi" -delete-after: True -changes: - - image: "yet another medkit resprite" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89089.yml b/html/changelogs/AutoChangeLog-pr-89089.yml deleted file mode 100644 index c6e81b3c33688..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89089.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "MTandi" -delete-after: True -changes: - - bugfix: "Fixed plant analyzer UI crashing on plants that have a reagent gene on their graft" - - bugfix: "Plants with reagent traits in the graft now properly say the name of the grafted reagent" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89100.yml b/html/changelogs/AutoChangeLog-pr-89100.yml deleted file mode 100644 index a9ccbbf619da8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89100.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - qol: "Small and tiny mobs no longer trigger squeaking objects when walking over them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89111.yml b/html/changelogs/AutoChangeLog-pr-89111.yml deleted file mode 100644 index d44499f99f2fa..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89111.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Chowder-McArthor" -delete-after: True -changes: - - qol: "Strange geysers now say in their name what they produce." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89112.yml b/html/changelogs/AutoChangeLog-pr-89112.yml deleted file mode 100644 index b4369a59d8308..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89112.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed active turfs on the new Turreted Outpost ruin." \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index cddfcce1af8e8..72a590d411f3c 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -507,3 +507,22 @@ 2025-01-18: EnterTheJake: - image: Codex Cicatrix has received a new sprite +2025-01-19: + Absolucy: + - qol: Small and tiny mobs no longer trigger squeaking objects when walking over + them. + AyIong: + - qol: SmartFridge got another redesign, and you can dispense all amount of product + in one click (RMB on product) + Chowder-McArthor: + - qol: Strange geysers now say in their name what they produce. + Jacquerel: + - rscadd: Eggs (and all other edible food) left in a hot place will fry. + MTandi: + - bugfix: Fixed plant analyzer UI crashing on plants that have a reagent gene on + their graft + - bugfix: Plants with reagent traits in the graft now properly say the name of the + grafted reagent + - image: yet another medkit resprite + SmArtKar: + - bugfix: Fixed active turfs on the new Turreted Outpost ruin. From 85f11990ae2230d3075d3cc65c868ca3bb7fe5fc Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sun, 19 Jan 2025 10:02:15 +0300 Subject: [PATCH 21/74] Resprites default and mirage grenades (#89118) --- icons/obj/weapons/grenade.dmi | Bin 37622 -> 37930 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/weapons/grenade.dmi b/icons/obj/weapons/grenade.dmi index 628b271d423e571c3dcfb94bd39712dd3a48eb03..c2eba7adcc1d65abd5eb417cf8ea82f0b0e5bee0 100644 GIT binary patch delta 36295 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

y;0lp&0 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 From e1c87793d8f41a9e2c5928830fa3c8084a61247a Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sun, 19 Jan 2025 10:04:19 +0300 Subject: [PATCH 22/74] Touches up the unholy water flask (#89117) --- icons/obj/drinks/bottles.dmi | Bin 27819 -> 26535 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/icons/obj/drinks/bottles.dmi b/icons/obj/drinks/bottles.dmi index 2bdacf04265065785d7672311d94f2c2a09caeb1..3dece4b41c6c9c88498c3f87e74564b159b503d3 100644 GIT binary patch literal 26535 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 literal 27819 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 Y@^&CsNRSWs5;BmIoa)OG*>{2e2M^=>00000 From d28db3124896b566ed0bee1256d9f8998a566b5e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 12:55:28 +0000 Subject: [PATCH 23/74] Automatic changelog for PR #89118 [ci skip] --- html/changelogs/AutoChangeLog-pr-89118.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89118.yml diff --git a/html/changelogs/AutoChangeLog-pr-89118.yml b/html/changelogs/AutoChangeLog-pr-89118.yml new file mode 100644 index 0000000000000..c49bafe2a57aa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89118.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - image: "Resprited default and mirage grenades" \ No newline at end of file From 622f8de0fbc7e75ba4d5b5d40f996f9e17b0a7e0 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 12:55:34 +0000 Subject: [PATCH 24/74] Automatic changelog for PR #89117 [ci skip] --- html/changelogs/AutoChangeLog-pr-89117.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89117.yml diff --git a/html/changelogs/AutoChangeLog-pr-89117.yml b/html/changelogs/AutoChangeLog-pr-89117.yml new file mode 100644 index 0000000000000..0695ea964d4f0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89117.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - image: "Made the unholy water flask darker" \ No newline at end of file From 90b67b0541413ba47603947ccabf974ee3544d88 Mon Sep 17 00:00:00 2001 From: Y0SH1M4S73R Date: Sun, 19 Jan 2025 13:40:23 -0500 Subject: [PATCH 25/74] A Small Circuit Expansion: Wallmounts, Undertiles, and Wire Bundles (#89122) ## About The Pull Request This PR adds several circuit features, and changes several assembly-related features to make them a bit more logical in how they work. Included are the following changes/additions: - Assemblies and wires have been refactored with vars that describe their behavior: - Assemblies have an `assembly_behavior` bitflag instead of a `attachable` var. This var has 3 flags: - `ASSEMBLY_INPUT`: The assembly is able to pulse the wire it is attached to. - `ASSEMBLY_TOGGLE_ARMED`: On activation, the assembly toggles whether it can pulse the wire it is attached to. - `ASSEMBLY_FUNCTIONAL_OUTPUT`: On activation, the assembly does something other than just toggling whether it's armed. - Wires have a `wires_behavior` bitflag with 3 flags: - `WIRES_INPUT`: The object the wires are attached to does something when the wires are pulsed. - `WIRES_TOGGLE_ARMED`: The object the wires are attached to can activate assemblies attached to those wires, and is fine if all that activating that assembly does is toggle whether it's armed. - `WIRES_FUNCTIONAL_OUTPUT`: The object the wires are attached to expects that assemblies attached to its wires do something other than toggling themselves when activated. - Buttons can only accept assemblies with `ASSEMBLY_FUNCTIONAL_OUTPUT`. - Pressure plates can now accept any assembly with `ASSEMBLY_FUNCTIONAL_OUTPUT`, not just signalers. Assembly shells attached to pressure plates will draw power from the powernet if the pressure plate is under a tile. - Adds a new circuit component - the wire bundle. - This component gives the circuit a number of wires corresponding to the size of the shell. - Each wire has a corresponding port on the component that can pulse, and receive pulses from, that wire. - A circuit can only have one wire bundle component. - Assembly shells cannot be attached to these wires, and no wires will be created if the component is added to an assembly shell. - Available with roundstart tech. - Adds two new shells. - The wallmounted shell is a large shell that can be hung on walls, and uses power from the area it's placed in. - Frame icon: ![image](https://github.com/user-attachments/assets/2fe9297d-44a9-4ceb-b803-a758e59b807d) - Constructed icon: ![image](https://github.com/user-attachments/assets/34c3ffcb-53cb-415f-952f-aec5de63cf17) - The undertile shell is a small shell that only works when fit under a floor tile, but uses power from the area it's placed in. ![image](https://github.com/user-attachments/assets/11ea150d-08be-4ce9-bf44-35a9d6e2d94f) - Both shells support usb cables. - The above shells are available with the Advanced Shells techweb node. ## Why It's Good For The Game The wire bundle component complements the functionality of the assembly shell by allowing circuits to use assemblies directly in their logic. The wallmounted and undertile shells provide ways of placing circuits that don't necessarily take up space for machines. The undertile shell is particularly useful for relaying usb component data over wirenets. Pressure plates being able to accept assemblies other than signalers expands their uses significantly. ## Changelog :cl: refactor: Wires and assemblies have been refactored to have directionality to them. This mostly makes it so that assemblies can only be attached to wires it would make sense for them to be attached to. qol: Pressure plates can now also accept igniters, condensers, flashes, assembly shells, and door controllers. add: Undertile circuit shells. They only work when placed under floor tiles, but support USB cables and use APC power instead of cell power. add: Wallmounted circuit shells. Large shells that support USB cables and use APC power instead of cell power. add: Wire bundle component. Adds a number of wires to the circuit proportional to the capacity of the shell, allowing you to use assemblies in circuit logic. /:cl: --- code/__DEFINES/dcs/signals/signals_object.dm | 16 ++- code/__DEFINES/traits/declarations.dm | 3 + code/__DEFINES/wires.dm | 26 ++++ code/_globalvars/traits/_traits.dm | 1 + code/datums/wires/_wires.dm | 16 +-- code/datums/wires/scanner_gate.dm | 1 + code/datums/wires/wire_bundle_component.dm | 24 ++++ code/game/machinery/buttons.dm | 3 + .../objects/items/devices/pressureplates.dm | 42 ++++--- code/game/objects/items/puzzle_pieces.dm | 2 +- code/modules/assembly/assembly.dm | 4 +- code/modules/assembly/doorcontrol.dm | 1 - code/modules/assembly/health.dm | 2 +- code/modules/assembly/mousetrap.dm | 2 +- code/modules/assembly/proximity.dm | 2 +- code/modules/assembly/signaler.dm | 2 +- code/modules/assembly/timer.dm | 2 +- code/modules/assembly/voice.dm | 2 +- .../research/designs/wiremod_designs.dm | 34 ++++++ .../research/techweb/nodes/circuit_nodes.dm | 3 + .../wiremod/components/utility/wire_bundle.dm | 115 ++++++++++++++++++ code/modules/wiremod/shell/assembly.dm | 33 +++-- code/modules/wiremod/shell/undertile.dm | 13 ++ code/modules/wiremod/shell/wallmount.dm | 33 +++++ icons/obj/science/circuits.dmi | Bin 20554 -> 22989 bytes tgstation.dme | 4 + 26 files changed, 342 insertions(+), 44 deletions(-) create mode 100644 code/datums/wires/wire_bundle_component.dm create mode 100644 code/modules/wiremod/components/utility/wire_bundle.dm create mode 100644 code/modules/wiremod/shell/undertile.dm create mode 100644 code/modules/wiremod/shell/wallmount.dm diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index 2044aab51e24d..4d9c6e9c00bf9 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -558,19 +558,29 @@ #define COMSIG_ASSEMBLY_DETACHED "assembly_detached" /* - * The following two signals are separate from the above two because buttons don't set the holder of the inserted assembly. + * The following four signals are separate from the above two because buttons and pressure plates don't set the holder of the inserted assembly. * This causes subtle behavioral differences that future handlers for these signals may need to account for, * even if none of the currently implemented handlers do. */ -/// Sent from /obj/machinery/button/assembly_act(obj/machinery/button/button, mob/user) +/// Sent when an assembly is added to a button : (obj/machinery/button/button, mob/user) #define COMSIG_ASSEMBLY_ADDED_TO_BUTTON "assembly_added_to_button" -/// Sent from /obj/machinery/button/remove_assembly(obj/machinery/button/button, mob/user) +/// Sent when an assembly is removed from a button : (obj/machinery/button/button, mob/user) #define COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON "assembly_removed_from_button" +/// Sent when an assembly is added to a pressure plate : (obj/item/pressureplate/pressure_plate, mob/user) +#define COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE "assembly_added_to_pressure_plate" + +/// Sent when an assembly is removed from a pressure plate : (obj/item/pressureplate/pressure_plate, mob/user) +#define COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE "assembly_removed_from_pressure_playe" + /// Sent from /datum/powernet/add_cable() #define COMSIG_CABLE_ADDED_TO_POWERNET "cable_added_to_powernet" /// Sent from /datum/powernet/remove_cable() #define COMSIG_CABLE_REMOVED_FROM_POWERNET "cable_removed_from_powernet" + +/// Sent from /datum/wires/attach_assembly() : (atom/holder) +#define COMSIG_ASSEMBLY_PRE_ATTACH "assembly_pre_attach" + #define COMPONENT_CANCEL_ATTACH (1<<0) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index dc3d6fa0c1d70..5d35a7fcb8718 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1424,4 +1424,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Mob doesn't get closed eyelids overlay when it gets knocked out cold or dies #define TRAIT_NO_EYELIDS "no_eyelids" +/// Trait applied when the wire bundle component is added to an [/obj/item/integrated_circuit] +#define TRAIT_COMPONENT_WIRE_BUNDLE "component_wire_bundle" + // END TRAIT DEFINES diff --git a/code/__DEFINES/wires.dm b/code/__DEFINES/wires.dm index 4926996f26bd3..034bb8897e6e6 100644 --- a/code/__DEFINES/wires.dm +++ b/code/__DEFINES/wires.dm @@ -2,6 +2,30 @@ #define COMSIG_CUT_WIRE(wire) "cut_wire [wire]" #define COMSIG_MEND_WIRE(wire) "mend_wire [wire]" +/// from base of /datum/wires/proc/on_pulse : (wire, mob/user) +#define COMSIG_PULSE_WIRE "pulse_wire" + +// Directionality of wire pulses + +/// The wires interact with their holder when pulsed +#define WIRES_INPUT (1<<0) +/// The wires have a reason to toggle whether attached assemblies are armed +#define WIRES_TOGGLE_ARMED (1<<1) +/// The wires only want to activate assemblies that do something other than (dis)arming themselves +#define WIRES_FUNCTIONAL_OUTPUT (1<<2) +/// The holder can both pulse its wires and be affected by its wires getting pulsed +#define WIRES_ALL (WIRES_INPUT | WIRES_TOGGLE_ARMED | WIRES_FUNCTIONAL_OUTPUT) + +/// The assembly can pulse a wire it is attached to +#define ASSEMBLY_INPUT (1<<0) +/// The assembly toggles whether it will pulse the attached wire when it is pulsed by the attached wire +#define ASSEMBLY_TOGGLE_ARMED (1<<1) +/// The assembly does something other than just (dis)arming itself when it is pulsed by the wire it is attached to +#define ASSEMBLY_FUNCTIONAL_OUTPUT (1<<2) +/// The assembly can both pulse the wire it is attached to, and (dis)arms itself when pulsed by the wire +#define ASSEMBLY_TOGGLEABLE_INPUT (ASSEMBLY_INPUT | ASSEMBLY_TOGGLE_ARMED) +#define ASSEMBLY_ALL (ASSEMBLY_TOGGLEABLE_INPUT | ASSEMBLY_FUNCTIONAL_OUTPUT) + //retvals for attempt_wires_interaction #define WIRE_INTERACTION_FAIL 0 #define WIRE_INTERACTION_SUCCESSFUL 1 @@ -72,3 +96,5 @@ #define AI_WIRE_DISABLED 1 #define AI_WIRE_HACKED 2 #define AI_WIRE_DISABLED_HACKED -1 + +#define MAX_WIRE_COUNT 17 diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 4edc46bb50303..e351e155dc170 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -687,6 +687,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CIRCUIT_UI_OPEN" = TRAIT_CIRCUIT_UI_OPEN, "TRAIT_CIRCUIT_UNDUPABLE" = TRAIT_CIRCUIT_UNDUPABLE, "TRAIT_COMPONENT_MMI" = TRAIT_COMPONENT_MMI, + "TRAIT_COMPONENT_WIRE_BUNDLE" = TRAIT_COMPONENT_WIRE_BUNDLE, ), /obj/item/modular_computer = list( "TRAIT_MODPC_HALVED_DOWNLOAD_SPEED" = TRAIT_MODPC_HALVED_DOWNLOAD_SPEED, diff --git a/code/datums/wires/_wires.dm b/code/datums/wires/_wires.dm index 73bdc511ee4ba..13b9420d8366a 100644 --- a/code/datums/wires/_wires.dm +++ b/code/datums/wires/_wires.dm @@ -7,16 +7,14 @@ if(I.tool_behaviour == TOOL_WIRECUTTER || I.tool_behaviour == TOOL_MULTITOOL) return TRUE if(isassembly(I)) - var/obj/item/assembly/A = I - if(A.attachable) - return TRUE + return TRUE /atom/proc/attempt_wire_interaction(mob/user) if(!wires) return WIRE_INTERACTION_FAIL if(!user.CanReach(src)) return WIRE_INTERACTION_FAIL - wires.interact(user) + INVOKE_ASYNC(wires, TYPE_PROC_REF(/datum/wires, interact), user) return WIRE_INTERACTION_BLOCK /datum/wires @@ -29,6 +27,9 @@ /// The display name for the wire set shown in station blueprints. Not shown in blueprints if randomize is TRUE or it's an item NT wouldn't know about (Explosives/Nuke). Also used in the hacking interface. var/proper_name = "Unknown" + /// Whether pulsed wires affect the holder, and/or the holder pulses its wires + var/wire_behavior = WIRES_INPUT + /// List of all wires. var/list/wires = list() /// List of cut wires. @@ -179,6 +180,7 @@ /datum/wires/proc/pulse(wire, user, force=FALSE) if(!force && is_cut(wire)) return + SEND_SIGNAL(src, COMSIG_PULSE_WIRE, wire, user) on_pulse(wire, user) /datum/wires/proc/pulse_color(color, mob/living/user, force=FALSE) @@ -191,7 +193,7 @@ return TRUE /datum/wires/proc/attach_assembly(color, obj/item/assembly/S) - if(S && istype(S) && S.attachable && !is_attached(color)) + if(S && istype(S) && S.assembly_behavior && !is_attached(color) && !(SEND_SIGNAL(S, COMSIG_ASSEMBLY_PRE_ATTACH, holder) & COMPONENT_CANCEL_ATTACH)) assemblies[color] = S S.forceMove(holder) S.connected = src @@ -384,13 +386,13 @@ I = L.get_active_held_item() if(isassembly(I)) var/obj/item/assembly/A = I - if(A.attachable) + if(A.assembly_behavior & wire_behavior) if(!L.temporarilyRemoveItemFromInventory(A)) return if(!attach_assembly(target_wire, A)) A.forceMove(L.drop_location()) . = TRUE else - to_chat(L, span_warning("You need an attachable assembly!")) + to_chat(L, span_warning("You cannot attach this assembly to these wires!")) #undef MAXIMUM_EMP_WIRES diff --git a/code/datums/wires/scanner_gate.dm b/code/datums/wires/scanner_gate.dm index 14752ec6795ec..cb363d68f95ea 100644 --- a/code/datums/wires/scanner_gate.dm +++ b/code/datums/wires/scanner_gate.dm @@ -2,6 +2,7 @@ holder_type = /obj/machinery/scanner_gate proper_name = "Scanner Gate" wires = list(WIRE_ACCEPT, WIRE_DENY, WIRE_DISABLE) + wire_behavior = WIRES_FUNCTIONAL_OUTPUT /datum/wires/scanner_gate/on_pulse(wire, user) . = ..() diff --git a/code/datums/wires/wire_bundle_component.dm b/code/datums/wires/wire_bundle_component.dm new file mode 100644 index 0000000000000..5cd4ffa2af620 --- /dev/null +++ b/code/datums/wires/wire_bundle_component.dm @@ -0,0 +1,24 @@ +#define CAPACITY_PER_WIRE 10 + +/datum/wires/wire_bundle_component + holder_type = /atom //Anything that can have a shell component, really. + randomize = TRUE + wire_behavior = WIRES_ALL + +/datum/wires/wire_bundle_component/New(atom/holder) + var/datum/component/shell/shell_comp = holder.GetComponent(/datum/component/shell) + if(!istype(shell_comp)) + CRASH("Holder does not have a shell component!") + var/wire_count = clamp(round(shell_comp.capacity / CAPACITY_PER_WIRE, 1), 1, MAX_WIRE_COUNT) + for(var/index in 1 to wire_count) + wires += "Port [index]" + ..() + +/datum/wires/wire_bundle_component/always_reveal_wire(color) + return TRUE // Let's not make wiring up this stuff confusing - just give them what wires correspond to what ports. + +/datum/wires/wire_bundle_component/ui_data(mob/user) + proper_name = holder.name + . = ..() + +#undef CAPACITY_PER_WIRE diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index c8aba44ef4732..66f1b64795a6b 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -140,6 +140,9 @@ if(device) to_chat(user, span_warning("The button already contains a device!")) return ITEM_INTERACT_BLOCKING + if(!(new_device.assembly_behavior & ASSEMBLY_FUNCTIONAL_OUTPUT)) + to_chat(user, span_warning("\The [new_device] won't really do anything meaningful inside of the button...")) + return ITEM_INTERACT_BLOCKING if(!user.transferItemToLoc(new_device, src, silent = FALSE)) to_chat(user, span_warning("\The [new_device] is stuck to you!")) return ITEM_INTERACT_BLOCKING diff --git a/code/game/objects/items/devices/pressureplates.dm b/code/game/objects/items/devices/pressureplates.dm index 17f324d109f99..ea27894d829c3 100644 --- a/code/game/objects/items/devices/pressureplates.dm +++ b/code/game/objects/items/devices/pressureplates.dm @@ -14,12 +14,12 @@ var/specific_item = null var/trigger_silent = FALSE var/sound/trigger_sound = 'sound/effects/pressureplate.ogg' - var/obj/item/assembly/signaler/sigdev = null + var/obj/item/assembly/assembly = null var/roundstart_signaller = FALSE var/roundstart_signaller_freq = FREQ_PRESSURE_PLATE var/roundstart_signaller_code = 30 var/roundstart_hide = FALSE - var/removable_signaller = TRUE + var/removable_assembly = TRUE var/active = FALSE var/image/tile_overlay = null var/can_trigger = TRUE @@ -31,9 +31,10 @@ . = ..() tile_overlay = image(icon = 'icons/turf/floors.dmi', icon_state = "pp_overlay") if(roundstart_signaller) - sigdev = new - sigdev.code = roundstart_signaller_code - sigdev.set_frequency(roundstart_signaller_freq) + var/obj/item/assembly/signaler/signaller = new(src) + signaller.code = roundstart_signaller_code + signaller.set_frequency(roundstart_signaller_freq) + assembly = signaller if(undertile_pressureplate) AddElement(/datum/element/undertile, tile_overlay = tile_overlay, use_anchor = TRUE) @@ -59,21 +60,28 @@ /obj/item/pressure_plate/proc/trigger() can_trigger = TRUE - if(istype(sigdev)) - sigdev.signal() + if(istype(assembly)) + assembly.activate() -/obj/item/pressure_plate/attackby(obj/item/I, mob/living/L) - if(issignaler(I) && !istype(sigdev) && removable_signaller && L.transferItemToLoc(I, src)) - sigdev = I - to_chat(L, span_notice("You attach [I] to [src]!")) +/obj/item/pressure_plate/attackby(obj/item/item, mob/living/L) + if(isassembly(item) && !istype(assembly) && removable_assembly) + var/obj/item/assembly/new_assembly = item + if(!(new_assembly.assembly_behavior & ASSEMBLY_FUNCTIONAL_OUTPUT)) + to_chat(L, span_warning("\The [item] doesn't seem like it would do much of anything inside of [src]...")) + return + if(L.transferItemToLoc(item, src)) + assembly = item + SEND_SIGNAL(item, COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE, src, L) + to_chat(L, span_notice("You attach [item] to [src]!")) return ..() /obj/item/pressure_plate/attack_self(mob/living/L) - if(removable_signaller && istype(sigdev)) - to_chat(L, span_notice("You remove [sigdev] from [src].")) - if(!L.put_in_hands(sigdev)) - sigdev.forceMove(get_turf(src)) - sigdev = null + if(removable_assembly && istype(assembly)) + to_chat(L, span_notice("You remove [assembly] from [src].")) + SEND_SIGNAL(assembly, COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE, src, L) + if(!L.put_in_hands(assembly)) + assembly.forceMove(get_turf(src)) + assembly = null return ..() /obj/item/pressure_plate/item_ctrl_click(mob/user) @@ -97,7 +105,7 @@ protected = TRUE anchored = TRUE //this prevents us from being picked up active = TRUE - removable_signaller = FALSE + removable_assembly = FALSE /// puzzle id we send if stepped on var/puzzle_id /// queue size must match diff --git a/code/game/objects/items/puzzle_pieces.dm b/code/game/objects/items/puzzle_pieces.dm index a7bd4da85aebf..f5e3cf6da689e 100644 --- a/code/game/objects/items/puzzle_pieces.dm +++ b/code/game/objects/items/puzzle_pieces.dm @@ -168,7 +168,7 @@ trigger_mob = FALSE trigger_item = TRUE specific_item = /obj/structure/holobox - removable_signaller = FALSE //Being a pressure plate subtype, this can also use signals. + removable_assembly = FALSE //Being a pressure plate subtype, this can also use signals. roundstart_signaller_freq = FREQ_HOLOGRID_SOLUTION //Frequency is kept on its own default channel however. active = TRUE trigger_delay = 10 diff --git a/code/modules/assembly/assembly.dm b/code/modules/assembly/assembly.dm index dbd5a70461476..0ac5993aeccf5 100644 --- a/code/modules/assembly/assembly.dm +++ b/code/modules/assembly/assembly.dm @@ -23,7 +23,7 @@ var/secured = TRUE var/list/attached_overlays = null var/obj/item/assembly_holder/holder = null - var/attachable = FALSE // can this be attached to wires + var/assembly_behavior = ASSEMBLY_FUNCTIONAL_OUTPUT // how does the assembly behave with respect to what it's connected to var/datum/wires/connected = null var/next_activate = 0 //When we're next allowed to activate - for spam control @@ -126,7 +126,7 @@ balloon_alert(user, "can't attach another of that!") return if(new_assembly.secured || secured) - balloon_alert(user, "both devices not attachable!") + balloon_alert(user, "both devices not assembly_behavior!") return holder = new /obj/item/assembly_holder(drop_location()) diff --git a/code/modules/assembly/doorcontrol.dm b/code/modules/assembly/doorcontrol.dm index 31584976cedf3..3361028350238 100644 --- a/code/modules/assembly/doorcontrol.dm +++ b/code/modules/assembly/doorcontrol.dm @@ -2,7 +2,6 @@ name = "blast door controller" desc = "A small electronic device able to control a blast door remotely." icon_state = "control" - attachable = TRUE /// The ID of the blast door electronics to match to the ID of the blast door being used. var/id = null /// Cooldown of the door's controller. Updates when pressed (activate()) diff --git a/code/modules/assembly/health.dm b/code/modules/assembly/health.dm index ad2c6ac17641d..d4635ac159fe7 100644 --- a/code/modules/assembly/health.dm +++ b/code/modules/assembly/health.dm @@ -3,7 +3,7 @@ desc = "Used for scanning and monitoring health." icon_state = "health" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*8, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 2) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT var/scanning = FALSE var/health_scan diff --git a/code/modules/assembly/mousetrap.dm b/code/modules/assembly/mousetrap.dm index 187a161df80b7..2b2065a67a040 100644 --- a/code/modules/assembly/mousetrap.dm +++ b/code/modules/assembly/mousetrap.dm @@ -4,7 +4,7 @@ icon_state = "mousetrap" inhand_icon_state = "mousetrap" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT var/armed = FALSE drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/proximity.dm b/code/modules/assembly/proximity.dm index 6ba2a7a63421e..9b7ccad9aefcc 100644 --- a/code/modules/assembly/proximity.dm +++ b/code/modules/assembly/proximity.dm @@ -3,7 +3,7 @@ desc = "Used for scanning and alerting when someone enters a certain proximity." icon_state = "prox" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*8, /datum/material/glass=SMALL_MATERIAL_AMOUNT * 2) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' var/scanning = FALSE diff --git a/code/modules/assembly/signaler.dm b/code/modules/assembly/signaler.dm index 4e265384ace24..b5346386d7dd3 100644 --- a/code/modules/assembly/signaler.dm +++ b/code/modules/assembly/signaler.dm @@ -6,7 +6,7 @@ lefthand_file = 'icons/mob/inhands/items/devices_lefthand.dmi' righthand_file = 'icons/mob/inhands/items/devices_righthand.dmi' custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT * 4, /datum/material/glass=SMALL_MATERIAL_AMOUNT*1.2) - attachable = TRUE + assembly_behavior = ASSEMBLY_ALL drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/timer.dm b/code/modules/assembly/timer.dm index 09cbfd9b0dc59..b25d30e1b4b5c 100644 --- a/code/modules/assembly/timer.dm +++ b/code/modules/assembly/timer.dm @@ -3,7 +3,7 @@ desc = "Used to time things. Works well with contraptions which has to count down. Tick tock." icon_state = "timer" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*5, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT drop_sound = 'sound/items/handling/component_drop.ogg' pickup_sound = 'sound/items/handling/component_pickup.ogg' diff --git a/code/modules/assembly/voice.dm b/code/modules/assembly/voice.dm index de0954c960e5e..106b812730718 100644 --- a/code/modules/assembly/voice.dm +++ b/code/modules/assembly/voice.dm @@ -8,7 +8,7 @@ desc = "A small electronic device able to record a voice sample, and send a signal when that sample is repeated." icon_state = "voice" custom_materials = list(/datum/material/iron=SMALL_MATERIAL_AMOUNT*5, /datum/material/glass=SMALL_MATERIAL_AMOUNT*0.5) - attachable = TRUE + assembly_behavior = ASSEMBLY_TOGGLEABLE_INPUT verb_say = "beeps" verb_ask = "beeps" verb_exclaim = "beeps" diff --git a/code/modules/research/designs/wiremod_designs.dm b/code/modules/research/designs/wiremod_designs.dm index f8732cc332b72..526e8d2a54a11 100644 --- a/code/modules/research/designs/wiremod_designs.dm +++ b/code/modules/research/designs/wiremod_designs.dm @@ -477,6 +477,11 @@ id = "comp_assoc_list_pick" build_path = /obj/item/circuit_component/list_pick/assoc +/datum/design/component/wire_bundle + name = "Wire Bundle" + id = "comp_wire_bundle" + build_path = /obj/item/circuit_component/wire_bundle + /datum/design/component/wirenet_receive name = "Wirenet Receiver Component" id = "comp_wirenet_receive" @@ -691,3 +696,32 @@ category = list( RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS ) + +/datum/design/undertile_shell + name = "Under-tile Shell" + desc = "A small shell that can fit under the floor." + id = "undertile_shell" + materials = list( + /datum/material/glass=HALF_SHEET_MATERIAL_AMOUNT, + /datum/material/iron=SHEET_MATERIAL_AMOUNT*2.5, + ) + build_path = /obj/item/undertile_circuit + build_type = COMPONENT_PRINTER + category = list( + RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS + ) + + +/datum/design/wallmount_shell + name = "Wall-mounted Shell" + desc = "A large shell that can be mounted on a wall." + id = "wallmount_shell" + materials = list( + /datum/material/glass=SHEET_MATERIAL_AMOUNT, + /datum/material/iron=SHEET_MATERIAL_AMOUNT*5, + ) + build_path = /obj/item/wallframe/circuit + build_type = COMPONENT_PRINTER + category = list( + RND_CATEGORY_CIRCUITRY + RND_SUBCATEGORY_CIRCUITRY_SHELLS + ) diff --git a/code/modules/research/techweb/nodes/circuit_nodes.dm b/code/modules/research/techweb/nodes/circuit_nodes.dm index 109873c38510b..9ef3b929ac424 100644 --- a/code/modules/research/techweb/nodes/circuit_nodes.dm +++ b/code/modules/research/techweb/nodes/circuit_nodes.dm @@ -86,6 +86,7 @@ "comp_typecast", "comp_typecheck", "comp_view_sensor", + "comp_wire_bundle", "comp_wirenet_receive", "comp_wirenet_send", "comp_wirenet_send_literal", @@ -108,6 +109,8 @@ "money_bot_shell", "scanner_gate_shell", "scanner_shell", + "undertile_shell", + "wallmount_shell", "comp_equip_action", ) research_costs = list(TECHWEB_POINT_TYPE_GENERIC = TECHWEB_TIER_1_POINTS) diff --git a/code/modules/wiremod/components/utility/wire_bundle.dm b/code/modules/wiremod/components/utility/wire_bundle.dm new file mode 100644 index 0000000000000..7e0355e894837 --- /dev/null +++ b/code/modules/wiremod/components/utility/wire_bundle.dm @@ -0,0 +1,115 @@ +/obj/item/circuit_component/wire_bundle + display_name = "Wire Bundle" + desc = "A bundle of exposed wires that assemblies can be attached to. Ports will only show up once the circuit is inserted into a shell." + category = "Utility" + circuit_flags = CIRCUIT_FLAG_REFUSE_MODULE + + var/datum/wires/wire_bundle_component/tracked_wires + + var/list/wire_input_ports = list() + var/list/wire_output_ports = list() + +/obj/item/circuit_component/wire_bundle/get_ui_notices() + . = ..() + . += create_ui_notice("Port count is proportional to shell capacity.", "orange", "plug") + . += create_ui_notice("Max port count: [MAX_WIRE_COUNT]", "orange", "plug") + . += create_ui_notice("Incompatible with assembly shell.", "red", "plug-circle-xmark") + +/obj/item/circuit_component/wire_bundle/register_shell(atom/movable/shell) + . = ..() + if(isassembly(shell) && !parent.admin_only) + return + if(shell.wires) // Don't add wires to shells that already have some. + return + tracked_wires = new(shell) + shell.set_wires(tracked_wires) + for(var/wire in tracked_wires.wires) + wire_input_ports[add_input_port("Pulse [wire]", PORT_TYPE_SIGNAL)] = wire + wire_output_ports[wire] = add_output_port("[wire] Pulsed", PORT_TYPE_SIGNAL) + RegisterSignal(tracked_wires, COMSIG_PULSE_WIRE, PROC_REF(on_pulse_wire)) + RegisterSignal(shell, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM, PROC_REF(on_shell_requesting_context)) + RegisterSignal(shell, COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, PROC_REF(on_shell_secondary_interaction)) + +/obj/item/circuit_component/wire_bundle/unregister_shell(atom/movable/shell) + . = ..() + if(shell.wires != tracked_wires) + return + UnregisterSignal(shell, list(COMSIG_ATOM_ITEM_INTERACTION_SECONDARY, COMSIG_ATOM_REQUESTING_CONTEXT_FROM_ITEM)) + for(var/color in tracked_wires.colors) + var/obj/item/assembly/assembly = tracked_wires.detach_assembly(color) + if(assembly) + assembly.forceMove(drop_location()) + shell.set_wires(null) + QDEL_NULL(tracked_wires) + for(var/datum/port/input/in_port in wire_input_ports) + remove_input_port(in_port) + for(var/wire in wire_output_ports) + var/datum/port/output/out_port = wire_output_ports[wire] + remove_output_port(out_port) + wire_input_ports.Cut() + wire_output_ports.Cut() + +/obj/item/circuit_component/wire_bundle/add_to(obj/item/integrated_circuit/added_to) + . = ..() + if(HAS_TRAIT(added_to, TRAIT_COMPONENT_WIRE_BUNDLE)) + return FALSE + ADD_TRAIT(added_to, TRAIT_COMPONENT_WIRE_BUNDLE, REF(src)) + +/obj/item/circuit_component/wire_bundle/removed_from(obj/item/integrated_circuit/removed_from) + . = ..() + REMOVE_TRAIT(removed_from, TRAIT_COMPONENT_WIRE_BUNDLE, REF(src)) + return ..() + +/obj/item/circuit_component/wire_bundle/input_received(datum/port/input/port) + . = ..() + if(!port) + return + var/wire = wire_input_ports[port] + if(!wire) + return + if(tracked_wires.is_cut(wire)) + return + var/color = tracked_wires.get_color_of_wire(wire) + var/obj/item/assembly/attached = tracked_wires.get_attached(color) + attached?.activate() + +/obj/item/circuit_component/wire_bundle/proc/on_pulse_wire(source, wire) + SIGNAL_HANDLER + if(tracked_wires.is_cut(wire)) + return + var/datum/port/output/port = wire_output_ports[wire] + if(!istype(port)) + return + port.set_output(COMPONENT_SIGNAL) + +/obj/item/circuit_component/wire_bundle/proc/can_access_wires(atom/source) + if(ismachinery(source)) + var/obj/machinery/machine = source + return machine.panel_open + return TRUE + +/obj/item/circuit_component/wire_bundle/proc/on_shell_requesting_context(atom/source, list/context, obj/item/item, mob/user) + SIGNAL_HANDLER + . = NONE + + if(!is_wire_tool(item)) + return + if(!can_access_wires(source)) + return + context[SCREENTIP_CONTEXT_RMB] = "Interact with wires" + return CONTEXTUAL_SCREENTIP_SET + +/obj/item/circuit_component/wire_bundle/proc/on_shell_secondary_interaction(atom/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + if(!is_wire_tool(tool)) + return + if(!can_access_wires(source)) + return + var/datum/component/shell/shell_comp = source.GetComponent(/datum/component/shell) + if(shell_comp.locked) + source.balloon_alert(user, "locked!") + return ITEM_INTERACT_FAILURE + if(source.attempt_wire_interaction(user) == WIRE_INTERACTION_BLOCK) + return ITEM_INTERACT_BLOCKING + + diff --git a/code/modules/wiremod/shell/assembly.dm b/code/modules/wiremod/shell/assembly.dm index 3e69331c4c826..033808c84541a 100644 --- a/code/modules/wiremod/shell/assembly.dm +++ b/code/modules/wiremod/shell/assembly.dm @@ -7,13 +7,13 @@ name = "circuit assembly" desc = "A small electronic device that can house an integrated circuit." icon_state = "wiremod" - attachable = TRUE + assembly_behavior = ASSEMBLY_ALL /// A reference to any holder to use power from instead of the circuit's own cell var/atom/movable/power_use_proxy /// Valid types for `power_use_proxy` to be - var/static/list/power_use_override_types = list(/obj/machinery, /obj/vehicle/sealed/mecha, /obj/item/mod/control, /mob/living/silicon/robot) + var/static/list/power_use_override_types = list(/obj/machinery, /obj/vehicle/sealed/mecha, /obj/item/mod/control, /obj/item/pressure_plate, /mob/living/silicon/robot) /obj/item/assembly/wiremod/Initialize(mapload) . = ..() @@ -23,10 +23,11 @@ ), SHELL_CAPACITY_SMALL) RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_ATTACHED, PROC_REF(on_circuit_attached)) RegisterSignal(shell, COMSIG_SHELL_CIRCUIT_REMOVED, PROC_REF(on_circuit_removed)) - RegisterSignals(src, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON), PROC_REF(on_attached)) - RegisterSignals(src, list(COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON), PROC_REF(on_detached)) + RegisterSignal(src, COMSIG_ASSEMBLY_PRE_ATTACH, PROC_REF(on_pre_attach)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_ATTACHED, COMSIG_ASSEMBLY_ADDED_TO_BUTTON, COMSIG_ASSEMBLY_ADDED_TO_PRESSURE_PLATE), PROC_REF(on_attached)) + RegisterSignals(src, list(COMSIG_ASSEMBLY_DETACHED, COMSIG_ASSEMBLY_REMOVED_FROM_BUTTON, COMSIG_ASSEMBLY_REMOVED_FROM_PRESSURE_PLATE), PROC_REF(on_detached)) -/obj/item/assembly/wiremod/proc/on_circuit_attached(_source, obj/item/integrated_circuit/circuit) +/obj/item/assembly/wiremod/proc/on_circuit_attached(source, obj/item/integrated_circuit/circuit) SIGNAL_HANDLER RegisterSignal(circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE, PROC_REF(override_circuit_power_usage)) @@ -34,12 +35,24 @@ SIGNAL_HANDLER UnregisterSignal(source.attached_circuit, COMSIG_CIRCUIT_PRE_POWER_USAGE) -/obj/item/assembly/wiremod/proc/on_attached(_source, atom/movable/holder) +/obj/item/assembly/wiremod/proc/on_pre_attach(obj/item/circuit_component/wire_bundle/source, atom/holder) + SIGNAL_HANDLER + if(!istype(source)) + return + if(source.parent.admin_only) + return + if(istype(holder.wires, /datum/wires/wire_bundle_component)) + var/datum/component/shell/shell_comp = GetComponent(/datum/component/shell) + if(shell_comp.attached_circuit.admin_only) + return + return COMPONENT_CANCEL_ATTACH + +/obj/item/assembly/wiremod/proc/on_attached(source, atom/movable/holder) SIGNAL_HANDLER if(is_type_in_list(holder, power_use_override_types)) power_use_proxy = holder -/obj/item/assembly/wiremod/proc/on_detached(_source) +/obj/item/assembly/wiremod/proc/on_detached(source) SIGNAL_HANDLER power_use_proxy = null @@ -59,6 +72,12 @@ var/obj/item/mod/control/modsuit = power_use_proxy if(modsuit.subtract_charge(power_to_use)) return COMPONENT_OVERRIDE_POWER_USAGE + if(istype(power_use_proxy, /obj/item/pressure_plate)) + if(!power_use_proxy.anchored) + return + var/area/our_area = get_area(power_use_proxy) + if(our_area.apc?.use_energy(power_to_use, AREA_USAGE_EQUIP)) + return COMPONENT_OVERRIDE_POWER_USAGE if(iscyborg(power_use_proxy)) var/mob/living/silicon/robot/borg = power_use_proxy if(borg.cell?.use(power_to_use, force = TRUE)) diff --git a/code/modules/wiremod/shell/undertile.dm b/code/modules/wiremod/shell/undertile.dm new file mode 100644 index 0000000000000..69ef66b61c0ea --- /dev/null +++ b/code/modules/wiremod/shell/undertile.dm @@ -0,0 +1,13 @@ +/obj/item/undertile_circuit + name = "circuit panel" + desc = "A panel for an integrated circuit. It needs to be fit under a floor tile to operate." + icon = 'icons/obj/science/circuits.dmi' + inhand_icon_state = "flashtool" + lefthand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' + icon_state = "undertile" + +/obj/item/undertile_circuit/Initialize(mapload) + . = ..() + AddElement(/datum/element/undertile, TRAIT_T_RAY_VISIBLE, INVISIBILITY_OBSERVER, use_anchor = TRUE) + AddComponent(/datum/component/shell, null, SHELL_CAPACITY_SMALL, SHELL_FLAG_REQUIRE_ANCHOR|SHELL_FLAG_USB_PORT) diff --git a/code/modules/wiremod/shell/wallmount.dm b/code/modules/wiremod/shell/wallmount.dm new file mode 100644 index 0000000000000..d461f696da131 --- /dev/null +++ b/code/modules/wiremod/shell/wallmount.dm @@ -0,0 +1,33 @@ +/obj/structure/wallmount_circuit + name = "circuit box" + desc = "A wall-mounted box suitable for the installation of integrated circuits." + icon = 'icons/obj/science/circuits.dmi' + icon_state = "wallmount" + layer = BELOW_OBJ_LAYER + anchored = TRUE + + resistance_flags = LAVA_PROOF | FIRE_PROOF + +/obj/structure/wallmount_circuit/Initialize(mapload) + . = ..() + AddComponent(/datum/component/shell, null, SHELL_CAPACITY_LARGE, SHELL_FLAG_REQUIRE_ANCHOR|SHELL_FLAG_USB_PORT) + +/obj/structure/wallmount_circuit/wrench_act(mob/living/user, obj/item/tool) + var/datum/component/shell/shell_comp = GetComponent(/datum/component/shell) + if(shell_comp.locked) + balloon_alert(user, "locked!") + return ITEM_INTERACT_FAILURE + to_chat(user, span_notice("You start unsecuring the circuit box...")) + if(tool.use_tool(src, user, 40, volume=50)) + to_chat(user, span_notice("You unsecure the circuit box.")) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + deconstruct(TRUE) + return ITEM_INTERACT_SUCCESS + +/obj/item/wallframe/circuit + name = "circuit box frame" + desc = "A box that can be mounted on a wall and have circuits installed." + icon = 'icons/obj/science/circuits.dmi' + icon_state = "wallmount_assembly" + result_path = /obj/structure/wallmount_circuit + pixel_shift = 32 diff --git a/icons/obj/science/circuits.dmi b/icons/obj/science/circuits.dmi index 1d50c67823bb2fc9afac7e40e397772f11f83794..e91025ae61365e780a5bac27a325fc62858f451b 100644 GIT binary patch literal 22989 zcmZs@1z1$wyEeWDkdPQsK)OVw1q5l3PC*H2Md^}ukdzRRmhO^}?ruZ`rMm@$p(ICo zzQy~V-*?Xc|DEg7YuI~sti9J-&wW4lbFT?`qOL%A^Y%>$f(VrqWwjs(CUyNE7aQ#P z5tUa2HgXWp^ju_LJDWLKIl5Rm*h7#KT7MM#%12TOu8 z&7)U2efS$6nD${cs*cqP3BQ+#t}Hl;LVh+6l)#(mcSt#oG~is@Yu ziCIuo&%i*$;|re0R+^eFgaKaW!s$M&8FE}Y*`#b780pndr?p<$QHw5G(0)ud4pA=d z&RF5UFRiOiRqV!l>|qqU;Y9rT=a5i(^$uPPim3C{J~6I9_E=~j<0iS0ohK&uyu9vY zQ^vB^DmlHY&~d6!d+tF;ljgBVlYhT~=n1^3@nu!#8H>KlJ)2(%TW6&K<-kA@k1yL!&77t;{81ni z@*Ng_>vYK}c%!Y*gKvkU>ZVjv5X1;6$x1)-NZo1iawMNj`+J_IM&KVU@E}H-I9Ibh zeiwr@B8~)A#Y(^SmB}rW7RO50+?ne&N2h_u4|Br2xq}*8>Wh;*T zJdN2&A-!|!Ro7JHTMudu8>JvIe_v`mvkqlm7AC7HTl+;xg!&*d-P-My{6yVv7-2z>R&lAbls|TSWMS}&)T1>Ley2*S>AtQI^o4cLsr?t8>yA( z=LUmc6Uk_W9eq=hl7y?>&mhSnBW z*0)LT+;JojeSuLB`}M2*<5G78h2CPXCl==Bj(cd)0&4q}0r}xG9Gi(HX$XDml=K3+ z+Br#B@_|l9RuedT@1=}nM2jRso0%0A(O-&-W!2RqO7|-C2*Sg|=WM-jDLM6`SnZXU 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 Date: Sun, 19 Jan 2025 18:44:23 +0000 Subject: [PATCH 26/74] Automatic changelog for PR #89122 [ci skip] --- html/changelogs/AutoChangeLog-pr-89122.yml | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89122.yml diff --git a/html/changelogs/AutoChangeLog-pr-89122.yml b/html/changelogs/AutoChangeLog-pr-89122.yml new file mode 100644 index 0000000000000..74c844109328a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89122.yml @@ -0,0 +1,8 @@ +author: "Y0SH1M4S73R" +delete-after: True +changes: + - refactor: "Wires and assemblies have been refactored to have directionality to them. This mostly makes it so that assemblies can only be attached to wires it would make sense for them to be attached to." + - qol: "Pressure plates can now also accept igniters, condensers, flashes, assembly shells, and door controllers." + - rscadd: "Undertile circuit shells. They only work when placed under floor tiles, but support USB cables and use APC power instead of cell power." + - rscadd: "Wallmounted circuit shells. Large shells that support USB cables and use APC power instead of cell power." + - rscadd: "Wire bundle component. Adds a number of wires to the circuit proportional to the capacity of the shell, allowing you to use assemblies in circuit logic." \ No newline at end of file From 3986b5d4b3eb04368fbabe2861856bcb3554edd4 Mon Sep 17 00:00:00 2001 From: RengaN02 <60517664+RengaN02@users.noreply.github.com> Date: Sun, 19 Jan 2025 21:49:01 +0300 Subject: [PATCH 27/74] Fixes Engine Diagnostic surgery (#89131) ## About The Pull Request There was no mechanical version of the coronary bypass and then I checked the code. ## Why It's Good For The Game Its a little fix ## Changelog :cl: fix: Fixed Engine Diagnostic surgery /:cl: --- code/modules/surgery/coronary_bypass.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/surgery/coronary_bypass.dm b/code/modules/surgery/coronary_bypass.dm index 1c5012d7580b9..be147e541181c 100644 --- a/code/modules/surgery/coronary_bypass.dm +++ b/code/modules/surgery/coronary_bypass.dm @@ -12,7 +12,7 @@ /datum/surgery_step/close, ) -/datum/surgery/gastrectomy/mechanic +/datum/surgery/coronary_bypass/mechanic name = "Engine Diagnostic" requires_bodypart_type = BODYTYPE_ROBOTIC steps = list( From 60a56f70ee2cae4f396b708a7c1917e8a844b0be Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 18:49:51 +0000 Subject: [PATCH 28/74] Automatic changelog for PR #89131 [ci skip] --- html/changelogs/AutoChangeLog-pr-89131.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89131.yml diff --git a/html/changelogs/AutoChangeLog-pr-89131.yml b/html/changelogs/AutoChangeLog-pr-89131.yml new file mode 100644 index 0000000000000..4b1a73b6c3e31 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89131.yml @@ -0,0 +1,4 @@ +author: "RengaN02" +delete-after: True +changes: + - bugfix: "Fixed Engine Diagnostic surgery" \ No newline at end of file From cbc7437735db4107688cce287573f30a01019225 Mon Sep 17 00:00:00 2001 From: Bloop <13398309+vinylspiders@users.noreply.github.com> Date: Sun, 19 Jan 2025 14:11:14 -0500 Subject: [PATCH 29/74] Removes the from from from from (#89127) --- code/modules/antagonists/heretic/magic/furious_steel.dm | 4 ++-- code/modules/vehicles/mecha/mech_fabricator.dm | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/code/modules/antagonists/heretic/magic/furious_steel.dm b/code/modules/antagonists/heretic/magic/furious_steel.dm index 4f2bb2dd7f108..ec3248af422fe 100644 --- a/code/modules/antagonists/heretic/magic/furious_steel.dm +++ b/code/modules/antagonists/heretic/magic/furious_steel.dm @@ -1,7 +1,7 @@ /datum/action/cooldown/spell/pointed/projectile/furious_steel name = "Furious Steel" desc = "Summon three silver blades which orbit you. \ - While orbiting you, these blades will protect you from from attacks, but will be consumed on use. \ + While orbiting you, these blades will protect you from attacks, but will be consumed on use. \ Additionally, you can click to fire the blades at a target, dealing damage and causing bleeding." background_icon_state = "bg_heretic" overlay_icon_state = "bg_heretic_border" @@ -151,7 +151,7 @@ /datum/action/cooldown/spell/pointed/projectile/furious_steel/haunted name = "Cursed Steel" desc = "Summon two cursed blades which orbit you. \ - While orbiting you, these blades will protect you from from attacks, but will be consumed on use. \ + While orbiting you, these blades will protect you from attacks, but will be consumed on use. \ Additionally, you can click to fire the blades at a target, dealing damage and causing bleeding." background_icon_state = "bg_heretic" // kept intentionally overlay_icon_state = "bg_cult_border" diff --git a/code/modules/vehicles/mecha/mech_fabricator.dm b/code/modules/vehicles/mecha/mech_fabricator.dm index ad28886d99f22..7667178392a8a 100644 --- a/code/modules/vehicles/mecha/mech_fabricator.dm +++ b/code/modules/vehicles/mecha/mech_fabricator.dm @@ -476,7 +476,7 @@ return if("del_queue_part") - // Delete a specific from from the queue + // Delete a specific from the queue var/index = text2num(params["index"]) remove_from_queue(index) From 4b512f1239ebda17d74d99181ab97fcb7e81c23f Mon Sep 17 00:00:00 2001 From: jimmyl <70376633+mc-oofert@users.noreply.github.com> Date: Sun, 19 Jan 2025 22:29:49 +0100 Subject: [PATCH 30/74] makes mimics into basicmobs (#88910) ## About The Pull Request mimics are basicmobs now the only change not carried over worth mentioning is that all mimics are a consistent speed because i cant imagine a gun or object with aimbot going at you mach 2 would be very fun mimic crates had some stuff changed compared to their simple animal variant they open and close their lid when attacking (unless locked) to be like menacing or something like animals flash colors to ward off people attempting to open a nonsentient hostile crate mimic will make it lock itself (if it contains anything) and attack you mimics are a really stupid naming for these because like mimic crates pretend to be crates anything else inheriting from mimics are just used to make objects alive https://github.com/user-attachments/assets/34a733a4-45a3-409e-8a6a-b2a8c7540898 ranged mimics now use viscontents (they also keep trying to pointblank people for some reason i think thats ok though unless its a wand of fireball) ranged mimic (any ranged weapon animated by a bolt of animation) https://github.com/user-attachments/assets/c3f1d2f5-cfb8-46a9-a58c-255c53a034db ## Why It's Good For The Game fixes #85668 ## Changelog :cl: refactor: mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs fix: crate mimics may now be opened /:cl: --------- Co-authored-by: Jacquerel --- ..._underground_abandoned_plasma_facility.dmm | 4 +- _maps/map_files/Birdshot/birdshot.dmm | 2 +- _maps/map_files/wawastation/wawastation.dmm | 2 +- _maps/virtual_domains/psyker_shuffle.dmm | 12 +- code/__DEFINES/ai/monsters.dm | 2 + code/_globalvars/lists/mobs.dm | 2 +- code/game/objects/items.dm | 2 +- code/game/objects/structures.dm | 2 +- code/modules/admin/verbs/spawnobjasmob.dm | 15 +- .../antagonists/malf_ai/malf_ai_modules.dm | 2 +- code/modules/mining/abandoned_crates.dm | 2 +- .../living/basic/ruin_defender/mimic/mimic.dm | 403 +++++++++++++++++ .../basic/ruin_defender/mimic/mimic_ai.dm | 86 ++++ .../mob/living/simple_animal/hostile/mimic.dm | 423 ------------------ code/modules/projectiles/gun.dm | 2 +- .../unit_tests/simple_animal_freeze.dm | 6 - tgstation.dme | 3 +- .../Scripts/88910_mimicbasicmobs.txt | 5 + 18 files changed, 521 insertions(+), 454 deletions(-) create mode 100644 code/modules/mob/living/basic/ruin_defender/mimic/mimic.dm create mode 100644 code/modules/mob/living/basic/ruin_defender/mimic/mimic_ai.dm delete mode 100644 code/modules/mob/living/simple_animal/hostile/mimic.dm create mode 100644 tools/UpdatePaths/Scripts/88910_mimicbasicmobs.txt diff --git a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm index 0bfcc133f0c98..e5f7305eba078 100644 --- a/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm +++ b/_maps/RandomRuins/IceRuins/icemoon_underground_abandoned_plasma_facility.dmm @@ -338,7 +338,7 @@ /obj/structure/railing/corner{ dir = 4 }, -/mob/living/simple_animal/hostile/mimic/crate, +/mob/living/basic/mimic/crate, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) "fO" = ( @@ -2073,7 +2073,7 @@ /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) "KV" = ( -/mob/living/simple_animal/hostile/mimic/crate, +/mob/living/basic/mimic/crate, /turf/open/floor/plating/snowed/icemoon, /area/icemoon/underground/explored) "KY" = ( diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index ff06bb5914c6b..758a5c877925e 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -26116,7 +26116,7 @@ /turf/open/floor/iron/smooth_large, /area/station/science/robotics/mechbay) "iPU" = ( -/mob/living/simple_animal/hostile/mimic/crate, +/mob/living/basic/mimic/crate, /turf/open/floor/plating, /area/station/maintenance/fore/lesser) "iPW" = ( diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index 0295a23f50395..64cad41bbebb1 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -840,7 +840,7 @@ /obj/effect/decal/cleanable/blood/old{ icon_state = "gib3-old" }, -/mob/living/simple_animal/hostile/mimic, +/mob/living/basic/mimic/crate, /turf/open/floor/iron/white, /area/station/maintenance/aft/upper) "anu" = ( diff --git a/_maps/virtual_domains/psyker_shuffle.dmm b/_maps/virtual_domains/psyker_shuffle.dmm index c744cecf0b430..5f303d4ae0471 100644 --- a/_maps/virtual_domains/psyker_shuffle.dmm +++ b/_maps/virtual_domains/psyker_shuffle.dmm @@ -64,11 +64,7 @@ /turf/template_noop, /area/template_noop) "r" = ( -/mob/living/simple_animal/hostile/mimic, -/turf/open/indestructible/dark, -/area/virtual_domain) -"s" = ( -/mob/living/simple_animal/hostile/mimic/crate, +/mob/living/basic/mimic/crate, /turf/open/indestructible/dark, /area/virtual_domain) "t" = ( @@ -767,7 +763,7 @@ Y Q Q Q -s +r M Q Q @@ -878,11 +874,11 @@ o Y a Q -s +r Y Y Y -s +r Q Q Q diff --git a/code/__DEFINES/ai/monsters.dm b/code/__DEFINES/ai/monsters.dm index d77817a203980..6a1433fa5ec86 100644 --- a/code/__DEFINES/ai/monsters.dm +++ b/code/__DEFINES/ai/monsters.dm @@ -312,3 +312,5 @@ #define BB_TURTLE_HEADBUTT_VICTIM "turtle_headbutt_victim" ///flore we must smell #define BB_TURTLE_FLORA_TARGET "turtle_flora_target" + +#define BB_GUNMIMIC_GUN_EMPTY "BB_GUNMIMIC_GUN_EMPTY" diff --git a/code/_globalvars/lists/mobs.dm b/code/_globalvars/lists/mobs.dm index 5ece846e84de3..6024f7991388d 100644 --- a/code/_globalvars/lists/mobs.dm +++ b/code/_globalvars/lists/mobs.dm @@ -29,7 +29,7 @@ GLOBAL_LIST_INIT(abstract_mob_types, list( /mob/living/simple_animal/hostile/asteroid/elite, /mob/living/simple_animal/hostile/asteroid, /mob/living/simple_animal/hostile/megafauna, - /mob/living/simple_animal/hostile/mimic, // Cannot exist if spawned without being passed an item reference + /mob/living/basic/mimic, // Cannot exist if spawned without being passed an item reference /mob/living/simple_animal/hostile/retaliate, /mob/living/simple_animal/hostile, /mob/living/simple_animal/soulscythe, // As mimic, can't exist if spawned outside an item diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 0d00b4f355a03..b389438f0f9be 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1840,7 +1840,7 @@ return null /obj/item/animate_atom_living(mob/living/owner) - new /mob/living/simple_animal/hostile/mimic/copy(drop_location(), src, owner) + new /mob/living/basic/mimic/copy(drop_location(), src, owner) /** * Used to update the weight class of the item in a way that other atoms can react to the change. diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm index e6c9579d67936..7f5e4c6b76d89 100644 --- a/code/game/objects/structures.dm +++ b/code/game/objects/structures.dm @@ -71,7 +71,7 @@ . = ..() /obj/structure/animate_atom_living(mob/living/owner) - new /mob/living/simple_animal/hostile/mimic/copy(drop_location(), src, owner) + new /mob/living/basic/mimic/copy(drop_location(), src, owner) /// For when a mob comes flying through the window, smash it and damage the mob /obj/structure/proc/smash_and_injure(mob/living/flying_mob, atom/oldloc, direction) diff --git a/code/modules/admin/verbs/spawnobjasmob.dm b/code/modules/admin/verbs/spawnobjasmob.dm index e673202f0bae1..c8d9ba3719d13 100644 --- a/code/modules/admin/verbs/spawnobjasmob.dm +++ b/code/modules/admin/verbs/spawnobjasmob.dm @@ -4,7 +4,7 @@ ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if if (!chosen) return - var/mob/living/simple_animal/hostile/mimic/copy/basemob = /mob/living/simple_animal/hostile/mimic/copy + var/mob/living/basic/mimic/copy/basemob = /mob/living/basic/mimic/copy var/obj/chosen_obj = text2path(chosen) @@ -54,8 +54,8 @@ ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if "mobtype" = list( "desc" = "Base mob type", "type" = "datum", - "path" = "/mob/living/simple_animal/hostile/mimic/copy", - "value" = "/mob/living/simple_animal/hostile/mimic/copy", + "path" = "/mob/living/basic/mimic/copy", + "value" = "/mob/living/basic/mimic/copy", ), "ckey" = list( "desc" = "ckey", @@ -71,13 +71,14 @@ ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if chosen_obj = text2path(mainsettings["objtype"]["value"]) basemob = text2path(mainsettings["mobtype"]["value"]) - if (!ispath(basemob, /mob/living/simple_animal/hostile/mimic/copy) || !ispath(chosen_obj, /obj)) + if (!ispath(basemob, /mob/living/basic/mimic/copy) || !ispath(chosen_obj, /obj)) to_chat(user.mob, "Mob or object path invalid", confidential = TRUE) basemob = new basemob(get_turf(user.mob), new chosen_obj(get_turf(user.mob)), user.mob, mainsettings["dropitem"]["value"] == "Yes" ? FALSE : TRUE, (mainsettings["googlyeyes"]["value"] == "Yes" ? FALSE : TRUE)) if (mainsettings["disableai"]["value"] == "Yes") - basemob.toggle_ai(AI_OFF) + qdel(basemob.ai_controller) + basemob.ai_controller = null if (mainsettings["idledamage"]["value"] == "No") basemob.idledamage = FALSE @@ -85,7 +86,9 @@ ADMIN_VERB(spawn_obj_as_mob, R_SPAWN, "Spawn Object-Mob", "Spawn an object as if if (mainsettings["access"]) var/newaccess = text2path(mainsettings["access"]["value"]) if (ispath(newaccess)) - basemob.access_card = new newaccess + var/obj/item/card/id/id = new newaccess //cant do initial on lists + basemob.AddComponent(/datum/component/simple_access, id.access) + qdel(id) if (mainsettings["maxhealth"]["value"]) if (!isnum(mainsettings["maxhealth"]["value"])) diff --git a/code/modules/antagonists/malf_ai/malf_ai_modules.dm b/code/modules/antagonists/malf_ai/malf_ai_modules.dm index 22e32d8264ab7..c95302c80ae11 100644 --- a/code/modules/antagonists/malf_ai/malf_ai_modules.dm +++ b/code/modules/antagonists/malf_ai/malf_ai_modules.dm @@ -479,7 +479,7 @@ GLOBAL_LIST_INIT(malf_modules, subtypesof(/datum/ai_module/malf)) if(QDELETED(to_animate)) return - new /mob/living/simple_animal/hostile/mimic/copy/machine(get_turf(to_animate), to_animate, clicker, TRUE) + new /mob/living/basic/mimic/copy/machine(get_turf(to_animate), to_animate, clicker, TRUE) /// Destroy RCDs: Detonates all non-cyborg RCDs on the station. /datum/ai_module/malf/destructive/destroy_rcd diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index 10b2fbe71d062..7fa66c8a65ce7 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -231,7 +231,7 @@ if(93) new /obj/item/dnainjector/xraymut(src) if(94) - new /mob/living/simple_animal/hostile/mimic/crate(src) + new /mob/living/basic/mimic/crate(src) qdel_on_open = TRUE if(95) new /obj/item/toy/plush/nukeplushie(src) diff --git a/code/modules/mob/living/basic/ruin_defender/mimic/mimic.dm b/code/modules/mob/living/basic/ruin_defender/mimic/mimic.dm new file mode 100644 index 0000000000000..b8661c3c38ea8 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/mimic/mimic.dm @@ -0,0 +1,403 @@ +#define CANT_INSERT_FULL -1 +/// Mimics can't be made out of these objects +GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list( + /obj/structure/table, + /obj/structure/cable, + /obj/structure/window, + /obj/structure/blob, +))) + +/mob/living/basic/mimic + response_help_continuous = "touches" + response_help_simple = "touch" + response_disarm_continuous = "pushes" + response_disarm_simple = "push" + speed = 6 + maxHealth = 250 + health = 250 + gender = NEUTER + mob_biotypes = NONE + pass_flags = PASSFLAPS + melee_damage_lower = 8 + melee_damage_upper = 12 + attack_sound = 'sound/items/weapons/punch1.ogg' + speak_emote = list("creaks") + + unsuitable_cold_damage = 0 + unsuitable_heat_damage = 0 + unsuitable_atmos_damage = 0 + + faction = list(FACTION_MIMIC) + basic_mob_flags = DEL_ON_DEATH + combat_mode = TRUE + /// can we stun people on hit + var/knockdown_people = FALSE + +/mob/living/basic/mimic/melee_attack(mob/living/carbon/target, list/modifiers, ignore_cooldown) + . = ..() + if(!. || !knockdown_people || !prob(15) || !istype(target)) + return + target.Paralyze(4 SECONDS) + target.visible_message(span_danger("\The [src] knocks down \the [target]!"), \ + span_userdanger("\The [src] knocks you down!")) + + +// **************************** +// CRATE MIMIC +// **************************** + +// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies. +/mob/living/basic/mimic/crate + name = "crate" + desc = "A rectangular steel crate." + icon = 'icons/obj/storage/crates.dmi' + icon_state = "crate" + icon_living = "crate" + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + speak_emote = list("clatters") + layer = BELOW_MOB_LAYER + ai_controller = /datum/ai_controller/basic_controller/mimic_crate + /// are we open + var/opened = FALSE + /// max mob size + var/max_mob_size = MOB_SIZE_HUMAN + /// can we be opened or closed, if false we can + var/locked = FALSE + /// action to lock us + var/datum/action/innate/mimic_lock/lock + ///A cap for items in the mimic. Prevents the mimic from eating enough stuff to cause lag when opened. + var/storage_capacity = 50 + ///A cap for mobs. Mobs count towards the item cap. Same purpose as above. + var/mob_storage_capacity = 10 + +// Pickup loot +/mob/living/basic/mimic/crate/Initialize(mapload) + . = ..() + lock = new + lock.Grant(src) + ADD_TRAIT(src, TRAIT_AI_PAUSED, INNATE_TRAIT) + ai_controller?.set_ai_status(AI_STATUS_OFF) //start inert, let gullible people pull us into cargo or something and then go nuts when opened + if(mapload) //eat shit + for(var/obj/item/item in loc) + item.forceMove(src) + +/mob/living/basic/mimic/crate/Destroy() + lock = null + return ..() + +/mob/living/basic/mimic/crate/attack_hand(mob/living/carbon/human/user, list/modifiers) + if(user.combat_mode) + return ..() + if(trigger()) + to_chat(user, span_danger("As you try to open [src] it [length(contents) ? "stiffens up and " : ""]nearly clamps down on your fingers!")) + return TRUE + toggle_open(user) + return TRUE + +/mob/living/basic/mimic/crate/melee_attack(mob/living/carbon/target, list/modifiers, ignore_cooldown) + . = ..() + toggle_open() // show our cool lid at the dumbass humans + +/mob/living/basic/mimic/crate/proc/trigger() + if(isnull(ai_controller) || client) + return FALSE + if(ai_controller.ai_status != AI_STATUS_OFF) + return FALSE + visible_message(span_danger("[src] starts to move!")) + REMOVE_TRAIT(src, TRAIT_AI_PAUSED, INNATE_TRAIT) + ai_controller.set_ai_status(AI_STATUS_ON) + if(length(contents)) + locked = TRUE //if this was a crate with loot then we dont want people to just leftclick it to open it then bait it somewhere and steal its loot + return TRUE + +/mob/living/basic/mimic/crate/adjust_health(amount, updating_health = TRUE, forced = FALSE) + if(amount > 0) + trigger() + return ..() + +/mob/living/basic/mimic/crate/death() + var/obj/structure/closet/crate/lootbox = new(get_turf(src)) + // Put loot in crate + for(var/obj/loot in src) + loot.forceMove(lootbox) + return ..() + +/mob/living/basic/mimic/crate/early_melee_attack(atom/target, list/modifiers, ignore_cooldown) + if(target == src) + toggle_open() + return FALSE + return ..() + +/mob/living/basic/mimic/crate/CanAllowThrough(atom/movable/mover, border_dir) + . = ..() + if(istype(mover, /obj/structure/closet)) + return FALSE + +/** +* Used to open and close the mimic +* +* Will insert tile contents into the mimic when closing +* Will dump mimic contents into the time when opening +* Does nothing if the mimic locked itself +*/ +/mob/living/basic/mimic/crate/proc/toggle_open(mob/user) + if(locked) + if(user) + balloon_alert(user, "too stiff!") + return + if(!opened) + ADD_TRAIT(src, TRAIT_UNDENSE, MIMIC_TRAIT) + opened = TRUE + icon_state = "crateopen" + playsound(src, 'sound/machines/crate/crate_open.ogg', 50, TRUE) + for(var/atom/movable/movable as anything in src) + movable.forceMove(loc) + else + REMOVE_TRAIT(src, TRAIT_UNDENSE, MIMIC_TRAIT) + opened = FALSE + icon_state = "crate" + playsound(src, 'sound/machines/crate/crate_close.ogg', 50, TRUE) + for(var/atom/movable/movable as anything in get_turf(src)) + if(movable != src && insert(movable) == CANT_INSERT_FULL) + playsound(src, 'sound/items/trayhit/trayhit2.ogg', 50, TRUE) + break + +/** +* Called by toggle_open to put items inside the mimic when it's being closed +* +* Will return CANT_INSERT_FULL (-1) if the insertion fails due to the storage capacity of the mimic having been reached +* Will return FALSE if insertion fails +* Will return TRUE if insertion succeeds +* Arguments: +* * AM - item to be inserted +*/ +/mob/living/basic/mimic/crate/proc/insert(atom/movable/movable) + if(contents.len >= storage_capacity) + return CANT_INSERT_FULL + if(insertion_allowed(movable)) + movable.forceMove(src) + return TRUE + return FALSE + +/mob/living/basic/mimic/crate/proc/insertion_allowed(atom/movable/movable) + if(movable.anchored) + return FALSE + if(ismob(movable)) + if(!isliving(movable)) //Don't let ghosts and such get trapped in the beast. + return FALSE + var/mob/living/living = movable + if(living.anchored || living.buckled || living.incorporeal_move || living.has_buckled_mobs()) + return FALSE + if(living.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items. + if(living.density || living.mob_size > max_mob_size) + return FALSE + var/mobs_stored = 0 + for(var/mob/living/living_mob in contents) + mobs_stored++ + if(mobs_stored >= mob_storage_capacity) + return FALSE + living.stop_pulling() + + else if(istype(movable, /obj/structure/closet)) + return FALSE + else if(isobj(movable)) + if(movable.has_buckled_mobs()) + return FALSE + else if(isitem(movable) && !HAS_TRAIT(movable, TRAIT_NODROP)) + return TRUE + else + return FALSE + return TRUE + +/mob/living/basic/mimic/crate/xenobio + health = 210 + maxHealth = 210 + attack_verb_continuous = "bites" + attack_verb_simple = "bite" + speak_emote = list("clatters") + gold_core_spawnable = HOSTILE_SPAWN + +/datum/action/innate/mimic_lock + name = "Lock/Unlock" + desc = "Toggle preventing yourself from being opened or closed." + button_icon = 'icons/hud/radial.dmi' + button_icon_state = "radial_lock" + background_icon_state = "bg_default" + overlay_icon_state = "bg_default_border" + +/datum/action/innate/mimic/lock/Activate() + var/mob/living/basic/mimic/crate/mimic = owner + mimic.locked = !mimic.locked + if(!mimic.locked) + to_chat(mimic, span_warning("You loosen up, allowing yourself to be opened and closed.")) + else + to_chat(mimic, span_warning("You stiffen up, preventing anyone from opening or closing you.")) + +// **************************** +// COPYING (actually imitates target object) MIMIC +// **************************** + +/mob/living/basic/mimic/copy + health = 100 + maxHealth = 100 + mob_biotypes = MOB_SPECIAL + ai_controller = /datum/ai_controller/basic_controller/mimic_copy + /// our creator + var/datum/weakref/creator_ref + /// googly eyes overlay + var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/simple/mob.dmi', "googly_eyes") + /// do we overlay googly eyes over whatever we copy + var/overlay_googly_eyes = TRUE + /// do we take damage when we are not sentient and have no target + var/idledamage = TRUE + /// copied object + var/atom/movable/copied + +/mob/living/basic/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = FALSE, no_googlies = FALSE) + . = ..() + ADD_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT) // They won't remember their original contents upon ressurection and would just be floating eyes + if (no_googlies) + overlay_googly_eyes = FALSE + CopyObject(copy, creator, destroy_original) + +/mob/living/basic/mimic/copy/Destroy() + creator_ref = null + copied = null + return ..() + +/mob/living/basic/mimic/copy/Life(seconds_per_tick = SSMOBS_DT, times_fired) + . = ..() + if(idledamage && !ckey && !ai_controller?.blackboard[BB_BASIC_MOB_CURRENT_TARGET]) //Objects eventually revert to normal if no one is around to terrorize + adjustBruteLoss(0.5 * seconds_per_tick) + for(var/mob/living/victim in contents) //a fix for animated statues from the flesh to stone spell + death() + return + +/mob/living/basic/mimic/copy/death() + for(var/atom/movable/movable as anything in src) + movable.forceMove(get_turf(src)) + return ..() + +/mob/living/basic/mimic/copy/wabbajack(what_to_randomize, change_flags = WABBAJACK) + visible_message(span_warning("[src] resists polymorphing into a new creature!")) + +/mob/living/basic/mimic/copy/animate_atom_living(mob/living/owner) + change_owner(owner) + +/mob/living/basic/mimic/copy/Exited(atom/movable/gone, direction) // if our object gets deleted it calls Exited + . = ..() + if(QDELETED(src) || gone != copied) + return + death() + +/mob/living/basic/mimic/copy/proc/change_owner(mob/owner) + var/mob/creator_resolved = creator_ref?.resolve() + if(!creator_resolved) + creator_ref = null + if(isnull(owner) || creator_resolved == owner) + return + unfriend(creator_resolved) + befriend(owner) + creator_ref = WEAKREF(owner) + +/// Check whether this object can be copied. If destroy_original is true, this proc is ignored. +/mob/living/basic/mimic/copy/proc/check_object(obj/target) + return ((isitem(target) || isstructure(target)) && !is_type_in_typecache(target, GLOB.animatable_blacklist)) + +/mob/living/basic/mimic/copy/proc/CopyObject(obj/original, mob/living/user, destroy_original = FALSE) + if(!destroy_original && !check_object(original)) + return FALSE + if(!destroy_original) + original.forceMove(src) + copied = original + CopyObjectVisuals(original) + if (overlay_googly_eyes) + add_overlay(googly_eyes) + if(isstructure(original) || ismachinery(original)) + health = (anchored * 50) + 50 + if(original.density && original.anchored) + knockdown_people = TRUE + melee_damage_lower *= 2 + melee_damage_upper *= 2 + else if(isitem(original)) + var/obj/item/I = original + health = 15 * I.w_class + melee_damage_lower = 2 + I.force + melee_damage_upper = 2 + I.force + maxHealth = health + if(user) + change_owner(user) + if(destroy_original) + qdel(original) + return TRUE + +/// Copies the object visually including name and desc +/mob/living/basic/mimic/copy/proc/CopyObjectVisuals(obj/original) + name = original.name + desc = original.desc + icon = original.icon + icon_state = original.icon_state + icon_living = icon_state + copy_overlays(original, cut_old = TRUE) + +/mob/living/basic/mimic/copy/machine + ai_controller = /datum/ai_controller/basic_controller/mimic_copy/machine + faction = list(FACTION_MIMIC, FACTION_SILICON) + +/mob/living/basic/mimic/copy/ranged + icon = 'icons/turf/floors.dmi' + icon_state = "invisible" + ai_controller = /datum/ai_controller/basic_controller/mimic_copy/gun + +/mob/living/basic/mimic/copy/ranged/Destroy() + vis_contents.Cut() + return ..() + +/mob/living/basic/mimic/copy/ranged/RangedAttack(atom/atom_target, modifiers) + INVOKE_ASYNC(src, PROC_REF(fire_gun), atom_target, modifiers) + +/mob/living/basic/mimic/copy/ranged/proc/fire_gun(atom/target, modifiers) // i cant find any better way to do this + var/obj/item/gun/gun = locate() in contents + if(!gun.can_shoot()) + if(istype(gun, /obj/item/gun/ballistic)) + var/obj/item/gun/ballistic/ballistic = gun + if(!ballistic.chambered || ballistic.bolt_locked) + ballistic.rack() //we racked so both checked variables should be something else now + // do we have nothing chambered/chambered is spent AND we have no mag or our mag is empty + if(!ballistic.chambered?.loaded_projectile && magazine_useless(gun)) // ran out of ammo + ai_controller?.set_blackboard_key(BB_GUNMIMIC_GUN_EMPTY, TRUE) //BANZAIIIIIIII + ai_controller?.CancelActions() + else //if we cant fire we probably like ran out of energy or magic charges or whatever the hell idk + ai_controller?.set_blackboard_key(BB_GUNMIMIC_GUN_EMPTY, TRUE) + ai_controller?.CancelActions() // Stop our firing behavior so we can plan melee + else + ai_controller?.set_blackboard_key(BB_GUNMIMIC_GUN_EMPTY, FALSE) + gun.fire_gun(target, user = src, flag = FALSE, params = modifiers) //still make like a cool click click sound if trying to fire empty + +/mob/living/basic/mimic/copy/ranged/proc/magazine_useless(obj/item/gun/ballistic/ballistic) + if(isnull(ballistic.magazine) || !length(ballistic.magazine.stored_ammo)) + return TRUE + // is there ATLEAST one unspent round (for the sake of revolvers or a magazine somehow having spent rounds in it) + for(var/obj/item/ammo_casing/thing as anything in ballistic.magazine.stored_ammo) + if(ispath(thing)) + return FALSE // unspent + if(!isnull(thing.loaded_projectile)) + return FALSE //unspent + return TRUE + +/mob/living/basic/mimic/copy/ranged/CopyObject(obj/item/gun/original, mob/living/creator, destroy_original = 0) + if(..()) + obj_damage = 0 + melee_damage_upper = original.force + melee_damage_lower = original.force - max(0, (original.force / 2)) + +/mob/living/basic/mimic/copy/ranged/CopyObjectVisuals(obj/original) + name = original.name + desc = original.desc + vis_contents += original + +/mob/living/basic/mimic/copy/ranged/can_use_guns(obj/item/gun) + return TRUE + +#undef CANT_INSERT_FULL diff --git a/code/modules/mob/living/basic/ruin_defender/mimic/mimic_ai.dm b/code/modules/mob/living/basic/ruin_defender/mimic/mimic_ai.dm new file mode 100644 index 0000000000000..9a673b49ec681 --- /dev/null +++ b/code/modules/mob/living/basic/ruin_defender/mimic/mimic_ai.dm @@ -0,0 +1,86 @@ +/datum/ai_controller/basic_controller/mimic_crate + idle_behavior = null + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + ) + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_controller/basic_controller/mimic_copy + blackboard = list( + 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/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/random_speech/when_has_target/mimic, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_controller/basic_controller/mimic_copy/machine + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/attack_obstacle_in_path, + /datum/ai_planning_subtree/random_speech/when_has_target/mimic_machine, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_planning_subtree/random_speech/when_has_target + /// target key + var/target_key = BB_BASIC_MOB_CURRENT_TARGET + + +/datum/ai_planning_subtree/random_speech/when_has_target/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + if(!controller.blackboard_key_exists(target_key)) + return + return ..() + + +/datum/ai_planning_subtree/random_speech/when_has_target/mimic + speech_chance = 30 + emote_hear = list("growls.") + +/datum/ai_planning_subtree/random_speech/when_has_target/mimic_machine + speech_chance = 7 + emote_hear = list() + speak = list( + "HUMANS ARE IMPERFECT!", + "YOU SHALL BE ASSIMILATED!", + "YOU ARE HARMING YOURSELF", + "You have been deemed hazardous. Will you comply?", + "My logic is undeniable.", + "One of us.", + "FLESH IS WEAK", + "THIS ISN'T WAR, THIS IS EXTERMINATION!", + ) + +/datum/ai_planning_subtree/random_speech/when_has_target/mimic/gun + emote_see = list("aims menacingly!") + +/datum/ai_controller/basic_controller/mimic_copy/gun + blackboard = list( + BB_TARGETING_STRATEGY = /datum/targeting_strategy/basic, + BB_GUNMIMIC_GUN_EMPTY = FALSE, + ) + planning_subtrees = list( + /datum/ai_planning_subtree/simple_find_target, + /datum/ai_planning_subtree/random_speech/when_has_target/mimic/gun, + /datum/ai_planning_subtree/gun_mimic_attack_subtree, + /datum/ai_planning_subtree/basic_melee_attack_subtree, + ) + +/datum/ai_planning_subtree/gun_mimic_attack_subtree + +/datum/ai_planning_subtree/gun_mimic_attack_subtree/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + . = ..() + if(!controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) + return + if(controller.blackboard[BB_GUNMIMIC_GUN_EMPTY]) + return + controller.queue_behavior(/datum/ai_behavior/basic_ranged_attack/avoid_friendly_fire, BB_BASIC_MOB_CURRENT_TARGET, BB_TARGETING_STRATEGY, BB_BASIC_MOB_CURRENT_TARGET_HIDING_LOCATION) + return SUBTREE_RETURN_FINISH_PLANNING //we are going into battle...no distractions. diff --git a/code/modules/mob/living/simple_animal/hostile/mimic.dm b/code/modules/mob/living/simple_animal/hostile/mimic.dm deleted file mode 100644 index 0d8c1d86bdd40..0000000000000 --- a/code/modules/mob/living/simple_animal/hostile/mimic.dm +++ /dev/null @@ -1,423 +0,0 @@ -/// Mimics can't be made out of these objects -GLOBAL_LIST_INIT(animatable_blacklist, typecacheof(list( - /obj/structure/table, - /obj/structure/cable, - /obj/structure/window, - /obj/structure/blob, -))) - -/mob/living/simple_animal/hostile/mimic - name = "crate" - desc = "A rectangular steel crate." - icon = 'icons/obj/storage/crates.dmi' - icon_state = "crate" - icon_living = "crate" - - response_help_continuous = "touches" - response_help_simple = "touch" - response_disarm_continuous = "pushes" - response_disarm_simple = "push" - speed = 0 - maxHealth = 250 - health = 250 - gender = NEUTER - mob_biotypes = NONE - pass_flags = PASSFLAPS - - harm_intent_damage = 5 - melee_damage_lower = 8 - melee_damage_upper = 12 - attack_sound = 'sound/items/weapons/punch1.ogg' - emote_taunt = list("growls") - speak_emote = list("creaks") - taunt_chance = 30 - - atmos_requirements = null - minbodytemp = 0 - - faction = list(FACTION_MIMIC) - move_to_delay = 9 - del_on_death = 1 - ///A cap for items in the mimic. Prevents the mimic from eating enough stuff to cause lag when opened. - var/storage_capacity = 50 - ///A cap for mobs. Mobs count towards the item cap. Same purpose as above. - var/mob_storage_capacity = 10 - -// Aggro when you try to open them. Will also pickup loot when spawns and drop it when dies. -/mob/living/simple_animal/hostile/mimic/crate - attack_verb_continuous = "bites" - attack_verb_simple = "bite" - speak_emote = list("clatters") - stop_automated_movement = 1 - wander = 0 - var/attempt_open = FALSE - -// Pickup loot -/mob/living/simple_animal/hostile/mimic/crate/Initialize(mapload) - . = ..() - if(mapload) //eat shit - for(var/obj/item/I in loc) - I.forceMove(src) - -/mob/living/simple_animal/hostile/mimic/crate/DestroyPathToTarget() - ..() - if(prob(90)) - icon_state = "[initial(icon_state)]open" - else - icon_state = initial(icon_state) - -/mob/living/simple_animal/hostile/mimic/crate/ListTargets() - if(attempt_open) - return ..() - return ..(1) - -/mob/living/simple_animal/hostile/mimic/crate/FindTarget() - . = ..() - if(.) - trigger() - -/mob/living/simple_animal/hostile/mimic/crate/AttackingTarget(atom/attacked_target) - . = ..() - if(.) - icon_state = initial(icon_state) - if(prob(15) && iscarbon(target)) - var/mob/living/carbon/C = target - C.Paralyze(40) - C.visible_message(span_danger("\The [src] knocks down \the [C]!"), \ - span_userdanger("\The [src] knocks you down!")) - -/mob/living/simple_animal/hostile/mimic/crate/proc/trigger() - if(!attempt_open) - visible_message("[src] starts to move!") - attempt_open = TRUE - -/mob/living/simple_animal/hostile/mimic/crate/adjustHealth(amount, updating_health = TRUE, forced = FALSE) - trigger() - . = ..() - -/mob/living/simple_animal/hostile/mimic/crate/LoseTarget() - ..() - icon_state = initial(icon_state) - -/mob/living/simple_animal/hostile/mimic/crate/death() - var/obj/structure/closet/crate/C = new(get_turf(src)) - // Put loot in crate - for(var/obj/O in src) - O.forceMove(C) - ..() - -/mob/living/simple_animal/hostile/mimic/copy - health = 100 - maxHealth = 100 - mob_biotypes = MOB_SPECIAL - var/mob/living/creator = null // the creator - var/destroy_objects = 0 - var/knockdown_people = 0 - var/static/mutable_appearance/googly_eyes = mutable_appearance('icons/mob/simple/mob.dmi', "googly_eyes") - var/overlay_googly_eyes = TRUE - var/idledamage = TRUE - -/mob/living/simple_animal/hostile/mimic/copy/Initialize(mapload, obj/copy, mob/living/creator, destroy_original = 0, no_googlies = FALSE) - . = ..() - ADD_TRAIT(src, TRAIT_PERMANENTLY_MORTAL, INNATE_TRAIT) // They won't remember their original contents upon ressurection and would just be floating eyes - if (no_googlies) - overlay_googly_eyes = FALSE - CopyObject(copy, creator, destroy_original) - -/mob/living/simple_animal/hostile/mimic/copy/Life(seconds_per_tick = SSMOBS_DT, times_fired) - ..() - if(idledamage && !target && !ckey) //Objects eventually revert to normal if no one is around to terrorize - adjustBruteLoss(0.5 * seconds_per_tick) - for(var/mob/living/M in contents) //a fix for animated statues from the flesh to stone spell - death() - -/mob/living/simple_animal/hostile/mimic/copy/death() - for(var/atom/movable/M in src) - M.forceMove(get_turf(src)) - ..() - -/mob/living/simple_animal/hostile/mimic/copy/ListTargets() - . = ..() - return . - creator - -/mob/living/simple_animal/hostile/mimic/copy/wabbajack(what_to_randomize, change_flags = WABBAJACK) - visible_message(span_warning("[src] resists polymorphing into a new creature!")) - -/mob/living/simple_animal/hostile/mimic/copy/animate_atom_living(mob/living/owner) - change_owner(owner) - -/mob/living/simple_animal/hostile/mimic/copy/proc/change_owner(mob/owner) - if(isnull(owner) || creator == owner) - return - LoseTarget() - creator = owner - faction |= REF(owner) - -/mob/living/simple_animal/hostile/mimic/copy/proc/check_object(obj/target) - return ((isitem(target) || isstructure(target)) && !is_type_in_typecache(target, GLOB.animatable_blacklist)) - -/mob/living/simple_animal/hostile/mimic/copy/proc/CopyObject(obj/O, mob/living/user, destroy_original = 0) - if(destroy_original || check_object(O)) - O.forceMove(src) - name = O.name - desc = O.desc - icon = O.icon - icon_state = O.icon_state - icon_living = icon_state - copy_overlays(O) - if (overlay_googly_eyes) - add_overlay(googly_eyes) - if(isstructure(O) || ismachinery(O)) - health = (anchored * 50) + 50 - destroy_objects = 1 - if(O.density && O.anchored) - knockdown_people = 1 - melee_damage_lower *= 2 - melee_damage_upper *= 2 - else if(isitem(O)) - var/obj/item/I = O - health = 15 * I.w_class - melee_damage_lower = 2 + I.force - melee_damage_upper = 2 + I.force - move_to_delay = 2 * I.w_class + 1 - maxHealth = health - if(user) - creator = user - faction += "[REF(creator)]" // very unique - if(destroy_original) - qdel(O) - return 1 - -/mob/living/simple_animal/hostile/mimic/copy/DestroySurroundings() - if(destroy_objects) - ..() - -/mob/living/simple_animal/hostile/mimic/copy/AttackingTarget(atom/attacked_target) - . = ..() - if(knockdown_people && . && prob(15) && iscarbon(target)) - var/mob/living/carbon/C = target - C.Paralyze(40) - C.visible_message(span_danger("\The [src] knocks down \the [C]!"), \ - span_userdanger("\The [src] knocks you down!")) - -/mob/living/simple_animal/hostile/mimic/copy/machine - speak = list( - "HUMANS ARE IMPERFECT!", "YOU SHALL BE ASSIMILATED!", "YOU ARE HARMING YOURSELF", "You have been deemed hazardous. Will you comply?", \ - "My logic is undeniable.", "One of us.", "FLESH IS WEAK", "THIS ISN'T WAR, THIS IS EXTERMINATION!", - ) - speak_chance = 7 - -/mob/living/simple_animal/hostile/mimic/copy/machine/CanAttack(atom/the_target) - if(the_target == creator) // Don't attack our creator AI. - return 0 - if(iscyborg(the_target)) - var/mob/living/silicon/robot/R = the_target - if(R.connected_ai == creator) // Only attack robots that aren't synced to our creator AI. - return 0 - return ..() - -/mob/living/simple_animal/hostile/mimic/copy/ranged - var/obj/item/gun/TrueGun = null - var/obj/item/gun/magic/Zapstick - var/obj/item/gun/ballistic/Pewgun - var/obj/item/gun/energy/Zapgun - -/mob/living/simple_animal/hostile/mimic/copy/ranged/CopyObject(obj/O, mob/living/creator, destroy_original = 0) - if(..()) - emote_see = list("aims menacingly") - obj_damage = 0 - environment_smash = ENVIRONMENT_SMASH_NONE //needed? seems weird for them to do so - ranged = 1 - retreat_distance = 1 //just enough to shoot - minimum_distance = 6 - var/obj/item/gun/G = O - melee_damage_upper = G.force - melee_damage_lower = G.force - max(0, (G.force / 2)) - move_to_delay = 2 * G.w_class + 1 - projectilesound = G.fire_sound - TrueGun = G - if(istype(G, /obj/item/gun/magic)) - Zapstick = G - var/obj/item/ammo_casing/magic/M = Zapstick.ammo_type - projectiletype = initial(M.projectile_type) - if(istype(G, /obj/item/gun/ballistic)) - Pewgun = G - var/obj/item/ammo_box/magazine/M = Pewgun.spawn_magazine_type - casingtype = initial(M.ammo_type) - if(istype(G, /obj/item/gun/energy)) - Zapgun = G - var/selectfiresetting = Zapgun.select - var/obj/item/ammo_casing/energy/E = Zapgun.ammo_type[selectfiresetting] - projectiletype = initial(E.projectile_type) - -/mob/living/simple_animal/hostile/mimic/copy/ranged/OpenFire(the_target) - if(Zapgun) - if(Zapgun.cell) - var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.select] - if(Zapgun.cell.charge >= shot.e_cost) - Zapgun.cell.use(shot.e_cost) - Zapgun.update_appearance() - ..() - else if(Zapstick) - if(Zapstick.charges) - Zapstick.charges-- - Zapstick.update_appearance() - ..() - else if(Pewgun) - if(Pewgun.chambered) - if(Pewgun.chambered.loaded_projectile) - qdel(Pewgun.chambered.loaded_projectile) - Pewgun.chambered.loaded_projectile = null //because qdel takes too long, ensures icon update - Pewgun.chambered.update_appearance() - ..() - else - visible_message(span_danger("The [src] clears a jam!")) - Pewgun.chambered.forceMove(loc) //rip revolver immersions, blame shotgun snowflake procs - Pewgun.chambered = null - if(Pewgun.magazine && Pewgun.magazine.stored_ammo.len) - Pewgun.chambered = Pewgun.magazine.get_round() - Pewgun.chambered.forceMove(Pewgun) - Pewgun.update_appearance() - else if(Pewgun.magazine && Pewgun.magazine.stored_ammo.len) //only true for pumpguns i think - Pewgun.chambered = Pewgun.magazine.get_round() - Pewgun.chambered.forceMove(Pewgun) - visible_message(span_danger("The [src] cocks itself!")) - else - ranged = 0 //BANZAIIII - retreat_distance = 0 - minimum_distance = 1 - return - icon_state = TrueGun.icon_state - icon_living = TrueGun.icon_state - -/mob/living/simple_animal/hostile/mimic/xenobio - health = 210 - maxHealth = 210 - attack_verb_continuous = "bites" - attack_verb_simple = "bite" - speak_emote = list("clatters") - gold_core_spawnable = HOSTILE_SPAWN - var/opened = FALSE - var/open_sound = 'sound/machines/crate/crate_open.ogg' - var/close_sound = 'sound/machines/crate/crate_close.ogg' - ///sound played when the mimic attempts to eat more items than it can - var/full_sound = 'sound/items/trayhit/trayhit2.ogg' - var/max_mob_size = MOB_SIZE_HUMAN - var/locked = FALSE - var/datum/action/innate/mimic/lock/lock - -/mob/living/simple_animal/hostile/mimic/xenobio/Initialize(mapload) - . = ..() - lock = new - lock.Grant(src) - -/mob/living/simple_animal/hostile/mimic/xenobio/AttackingTarget(atom/attacked_target) - if(src == target) - toggle_open() - return - return ..() - -/mob/living/simple_animal/hostile/mimic/xenobio/attack_hand(mob/living/carbon/human/user, list/modifiers) - . = ..() - if(user.combat_mode) - return - toggle_open() - -/mob/living/simple_animal/hostile/mimic/xenobio/death() - var/obj/structure/closet/crate/C = new(get_turf(src)) - // Put loot in crate - for(var/atom/movable/AM in src) - AM.forceMove(C) - return ..() - -/mob/living/simple_animal/hostile/mimic/xenobio/CanAllowThrough(atom/movable/mover, border_dir) - . = ..() - if(istype(mover, /obj/structure/closet)) - return FALSE -/** -* Used to open and close the mimic -* -* Will insert tile contents into the mimic when closing -* Will dump mimic contents into the time when opening -* Does nothing if the mimic locked itself -*/ -/mob/living/simple_animal/hostile/mimic/xenobio/proc/toggle_open() - if(locked) - return - if(!opened) - ADD_TRAIT(src, TRAIT_UNDENSE, MIMIC_TRAIT) - opened = TRUE - icon_state = "crateopen" - playsound(src, open_sound, 50, TRUE) - for(var/atom/movable/AM in src) - AM.forceMove(loc) - else - REMOVE_TRAIT(src, TRAIT_UNDENSE, MIMIC_TRAIT) - opened = FALSE - icon_state = "crate" - playsound(src, close_sound, 50, TRUE) - for(var/atom/movable/AM in get_turf(src)) - if(AM != src && insert(AM) == -1) - playsound(src, full_sound, 50, TRUE) - break -/** -* Called by toggle_open to put items inside the mimic when it's being closed -* -* Will return -1 if the insertion fails due to the storage capacity of the mimic having been reached -* Will return FALSE if insertion fails -* Will return TRUE if insertion succeeds -* Arguments: -* * AM - item to be inserted -*/ -/mob/living/simple_animal/hostile/mimic/xenobio/proc/insert(atom/movable/AM) - if(contents.len >= storage_capacity) - return -1 - if(insertion_allowed(AM)) - AM.forceMove(src) - return TRUE - else - return FALSE - -/mob/living/simple_animal/hostile/mimic/xenobio/proc/insertion_allowed(atom/movable/AM) - if(ismob(AM)) - if(!isliving(AM)) //Don't let ghosts and such get trapped in the beast. - return FALSE - var/mob/living/L = AM - if(L.anchored || L.buckled || L.incorporeal_move || L.has_buckled_mobs()) - return FALSE - if(L.mob_size > MOB_SIZE_TINY) // Tiny mobs are treated as items. - if(L.density || L.mob_size > max_mob_size) - return FALSE - var/mobs_stored = 0 - for(var/mob/living/M in contents) - mobs_stored++ - if(mobs_stored >= mob_storage_capacity) - return FALSE - L.stop_pulling() - - else if(istype(AM, /obj/structure/closet)) - return FALSE - else if(isobj(AM)) - if(AM.anchored || AM.has_buckled_mobs()) - return FALSE - else if(isitem(AM) && !HAS_TRAIT(AM, TRAIT_NODROP)) - return TRUE - else - return FALSE - return TRUE - -/datum/action/innate/mimic - background_icon_state = "bg_default" - overlay_icon_state = "bg_default_border" - -/datum/action/innate/mimic/lock - name = "Lock/Unlock" - desc = "Toggle preventing yourself from being opened or closed." - -/datum/action/innate/mimic/lock/Activate() - var/mob/living/simple_animal/hostile/mimic/xenobio/M = owner - M.locked = !M.locked - if(!M.locked) - to_chat(M, span_warning("You loosen up, allowing yourself to be opened and closed.")) - else - to_chat(M, span_warning("You stiffen up, preventing anyone from opening or closing you.")) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index c8e8a0653ed9d..abaf7883cb888 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -558,7 +558,7 @@ return TRUE /obj/item/gun/animate_atom_living(mob/living/owner) - new /mob/living/simple_animal/hostile/mimic/copy/ranged(drop_location(), src, owner) + new /mob/living/basic/mimic/copy/ranged(drop_location(), src, owner) /obj/item/gun/proc/handle_suicide(mob/living/carbon/human/user, mob/living/carbon/human/target, params, bypass_timer) if(!ishuman(user) || !ishuman(target)) diff --git a/code/modules/unit_tests/simple_animal_freeze.dm b/code/modules/unit_tests/simple_animal_freeze.dm index 55161807eb46e..e82a607a9bfb8 100644 --- a/code/modules/unit_tests/simple_animal_freeze.dm +++ b/code/modules/unit_tests/simple_animal_freeze.dm @@ -57,12 +57,6 @@ /mob/living/simple_animal/hostile/megafauna/legion/small, /mob/living/simple_animal/hostile/megafauna/wendigo, /mob/living/simple_animal/hostile/megafauna/wendigo/noportal, - /mob/living/simple_animal/hostile/mimic, - /mob/living/simple_animal/hostile/mimic/copy, - /mob/living/simple_animal/hostile/mimic/copy/machine, - /mob/living/simple_animal/hostile/mimic/copy/ranged, - /mob/living/simple_animal/hostile/mimic/crate, - /mob/living/simple_animal/hostile/mimic/xenobio, /mob/living/simple_animal/hostile/ooze, /mob/living/simple_animal/hostile/ooze/gelatinous, /mob/living/simple_animal/hostile/ooze/grapes, diff --git a/tgstation.dme b/tgstation.dme index 255baf3b398ec..b7f67bf487db3 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5072,6 +5072,8 @@ #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\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" #include "code\modules\mob\living\basic\ruin_defender\wizard\wizard_ai.dm" #include "code\modules\mob\living\basic\ruin_defender\wizard\wizard_spells.dm" @@ -5348,7 +5350,6 @@ #include "code\modules\mob\living\simple_animal\hostile\dark_wizard.dm" #include "code\modules\mob\living\simple_animal\hostile\hostile.dm" #include "code\modules\mob\living\simple_animal\hostile\illusion.dm" -#include "code\modules\mob\living\simple_animal\hostile\mimic.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" diff --git a/tools/UpdatePaths/Scripts/88910_mimicbasicmobs.txt b/tools/UpdatePaths/Scripts/88910_mimicbasicmobs.txt new file mode 100644 index 0000000000000..b7a012ed1d9b0 --- /dev/null +++ b/tools/UpdatePaths/Scripts/88910_mimicbasicmobs.txt @@ -0,0 +1,5 @@ +/mob/living/simple_animal/hostile/mimic : /mob/living/basic/mimic/crate{@OLD} +/mob/living/simple_animal/hostile/mimic/crate : /mob/living/basic/mimic/crate{@OLD} +/mob/living/simple_animal/hostile/mimic/xenobio : /mob/living/basic/mimic/crate/xenobio{@OLD} +/mob/living/simple_animal/hostile/mimic/copy : /mob/living/basic/mimic/copy{@OLD} +/mob/living/simple_animal/hostile/mimic/copy/ranged : /mob/living/basic/mimic/copy/ranged{@OLD} From 192b698e4d9a6b7bee423ba96c9b547c4c01cb69 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 19 Jan 2025 23:48:32 +0000 Subject: [PATCH 31/74] Automatic changelog for PR #88910 [ci skip] --- html/changelogs/AutoChangeLog-pr-88910.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88910.yml diff --git a/html/changelogs/AutoChangeLog-pr-88910.yml b/html/changelogs/AutoChangeLog-pr-88910.yml new file mode 100644 index 0000000000000..29748f8021ac2 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88910.yml @@ -0,0 +1,5 @@ +author: "mc-oofert" +delete-after: True +changes: + - refactor: "mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs" + - bugfix: "crate mimics may now be opened" \ No newline at end of file From 2d156a0294fc75ce14cdf2910f0b3f02872e0c20 Mon Sep 17 00:00:00 2001 From: NamelessFairy <40036527+NamelessFairy@users.noreply.github.com> Date: Mon, 20 Jan 2025 00:27:06 +0000 Subject: [PATCH 32/74] Cancelling stray admin configured syndicate cargo-pods actually works, also adds missing uplinks to customization (#89047) ## About The Pull Request Must have missed this in initial tests. Cancelling the stray syndicate cargo pod event while modifying the telecrystal value or uplink type did not cancel it. Now it does. Bonus - Uplinks that have been introduced since customization was added have been added ## Why It's Good For The Game I may have accidently dropped a syndicate cargo pod on a station today and I'd prefer to do it intentionally. ## Changelog :cl: fix: Admin fired stray syndicate cargo pods will not rebel against admin whims and launch themselves when cancelled. admin: Admins have new categories to fill syndicate cargo pods with. /:cl: --- code/modules/events/stray_cargo.dm | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/code/modules/events/stray_cargo.dm b/code/modules/events/stray_cargo.dm index 0be1138f59a59..0514af5764e3d 100644 --- a/code/modules/events/stray_cargo.dm +++ b/code/modules/events/stray_cargo.dm @@ -149,7 +149,7 @@ var/admin_selected_pack = tgui_alert(usr,"Customize Pod contents?", "Pod Contents", list("Yes", "No", "Cancel")) switch(admin_selected_pack) if("Yes") - override_contents() + return override_contents() if("No") pack_type_override = null else @@ -161,7 +161,14 @@ var/pack_telecrystals = tgui_input_number(usr, "Please input crate's value in telecrystals.", "Set Telecrystals.", 30) if(isnull(pack_telecrystals)) return ADMIN_CANCEL_EVENT - var/list/possible_uplinks = list("Traitor" = UPLINK_TRAITORS, "Nuke Op" = UPLINK_NUKE_OPS, "Clown Op" = UPLINK_CLOWN_OPS) + var/list/possible_uplinks = list( + "Traitor" = UPLINK_TRAITORS, + "Nuke Op" = UPLINK_NUKE_OPS, + "Clown Op" = UPLINK_CLOWN_OPS, + "Lone Op" = UPLINK_LONE_OP, + "Infiltrator" = UPLINK_INFILTRATORS, + "Spy" = UPLINK_SPY + ) var/uplink_type = tgui_input_list(usr, "Choose uplink to draw items from.", "Choose uplink type.", possible_uplinks) var/selection if(!isnull(uplink_type)) From 1ad83be59038571a2e8184f73b562804f4d86deb Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 00:27:40 +0000 Subject: [PATCH 33/74] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88910.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89117.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89118.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89122.yml | 8 -------- html/changelogs/AutoChangeLog-pr-89131.yml | 4 ---- html/changelogs/archive/2025-01.yml | 21 +++++++++++++++++++++ 6 files changed, 21 insertions(+), 25 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88910.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89117.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89118.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89122.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89131.yml diff --git a/html/changelogs/AutoChangeLog-pr-88910.yml b/html/changelogs/AutoChangeLog-pr-88910.yml deleted file mode 100644 index 29748f8021ac2..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88910.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "mc-oofert" -delete-after: True -changes: - - refactor: "mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs" - - bugfix: "crate mimics may now be opened" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89117.yml b/html/changelogs/AutoChangeLog-pr-89117.yml deleted file mode 100644 index 0695ea964d4f0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89117.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - image: "Made the unholy water flask darker" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89118.yml b/html/changelogs/AutoChangeLog-pr-89118.yml deleted file mode 100644 index c49bafe2a57aa..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89118.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - image: "Resprited default and mirage grenades" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89122.yml b/html/changelogs/AutoChangeLog-pr-89122.yml deleted file mode 100644 index 74c844109328a..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89122.yml +++ /dev/null @@ -1,8 +0,0 @@ -author: "Y0SH1M4S73R" -delete-after: True -changes: - - refactor: "Wires and assemblies have been refactored to have directionality to them. This mostly makes it so that assemblies can only be attached to wires it would make sense for them to be attached to." - - qol: "Pressure plates can now also accept igniters, condensers, flashes, assembly shells, and door controllers." - - rscadd: "Undertile circuit shells. They only work when placed under floor tiles, but support USB cables and use APC power instead of cell power." - - rscadd: "Wallmounted circuit shells. Large shells that support USB cables and use APC power instead of cell power." - - rscadd: "Wire bundle component. Adds a number of wires to the circuit proportional to the capacity of the shell, allowing you to use assemblies in circuit logic." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89131.yml b/html/changelogs/AutoChangeLog-pr-89131.yml deleted file mode 100644 index 4b1a73b6c3e31..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89131.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "RengaN02" -delete-after: True -changes: - - bugfix: "Fixed Engine Diagnostic surgery" \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index 72a590d411f3c..d0707a54087d2 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -526,3 +526,24 @@ - image: yet another medkit resprite SmArtKar: - bugfix: Fixed active turfs on the new Turreted Outpost ruin. +2025-01-20: + RengaN02: + - bugfix: Fixed Engine Diagnostic surgery + SmArtKar: + - image: Resprited default and mirage grenades + - image: Made the unholy water flask darker + Y0SH1M4S73R: + - refactor: Wires and assemblies have been refactored to have directionality to + them. This mostly makes it so that assemblies can only be attached to wires + it would make sense for them to be attached to. + - qol: Pressure plates can now also accept igniters, condensers, flashes, assembly + shells, and door controllers. + - rscadd: Undertile circuit shells. They only work when placed under floor tiles, + but support USB cables and use APC power instead of cell power. + - rscadd: Wallmounted circuit shells. Large shells that support USB cables and use + APC power instead of cell power. + - rscadd: Wire bundle component. Adds a number of wires to the circuit proportional + to the capacity of the shell, allowing you to use assemblies in circuit logic. + mc-oofert: + - refactor: mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs + - bugfix: crate mimics may now be opened From 1bf9e41fa58079de8d735019f118238fb48a3006 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 04:58:59 +0000 Subject: [PATCH 34/74] Automatic changelog for PR #89047 [ci skip] --- html/changelogs/AutoChangeLog-pr-89047.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89047.yml diff --git a/html/changelogs/AutoChangeLog-pr-89047.yml b/html/changelogs/AutoChangeLog-pr-89047.yml new file mode 100644 index 0000000000000..784e95a25ddc0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89047.yml @@ -0,0 +1,5 @@ +author: "NamelessFairy" +delete-after: True +changes: + - bugfix: "Admin fired stray syndicate cargo pods will not rebel against admin whims and launch themselves when cancelled." + - admin: "Admins have new categories to fill syndicate cargo pods with." \ No newline at end of file From 059d17a2778db5e48fcc2852bb6e314fe953c8b2 Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Mon, 20 Jan 2025 05:31:31 +0000 Subject: [PATCH 35/74] Fixes HFR moderator overflow runtime. (#89095) ## About The Pull Request Fixes a runtime when the HFR moderator overflows. This should also let the HFR continue leaking its moderator contents after a crack is created. I didn't test this but it's quite simple really. ## Why It's Good For The Game Closes #70617 ## Changelog :cl: fix: Fixes HFR moderator leaking not leaking properly when a part is cracked. /:cl: --- .../components/fusion/hfr_main_processes.dm | 2 +- .../machinery/components/fusion/hfr_procs.dm | 22 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm index 27cb78bb26ce7..e36d99cb6d73d 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_main_processes.dm @@ -25,7 +25,7 @@ fusion_process(seconds_per_tick) // Note that we process damage/healing even if the fusion process aborts. // Running out of fuel won't save you if your moderator and coolant are exploding on their own. - check_spill() + process_moderator_overflow() process_damageheal(seconds_per_tick) check_alert() if (start_power) diff --git a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm index bc27ab0a42e36..2c77ac829b735 100644 --- a/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm +++ b/code/modules/atmospherics/machinery/components/fusion/hfr_procs.dm @@ -569,18 +569,27 @@ * HFR cracking related procs */ +/** + * Checks for any hypertorus part that is cracked and returns it if found, otherwise returns null. + */ /obj/machinery/atmospherics/components/unary/hypertorus/core/proc/check_cracked_parts() for(var/obj/machinery/atmospherics/components/unary/hypertorus/part in machine_parts) if(part.cracked) - return TRUE - return FALSE + return part -/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/create_crack() +/** + * Causes a random hypertorus part in machine_parts to become cracked and update their appearance. + * Returns the hypertorus part. + */ +/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/create_crack() as /obj/machinery/atmospherics/components/unary/hypertorus var/obj/machinery/atmospherics/components/unary/hypertorus/part = pick(machine_parts) part.cracked = TRUE part.update_appearance() return part +/** + * Takes a ratio portion of target_mix and moves it to the origin's location's air. + */ /obj/machinery/atmospherics/components/unary/hypertorus/core/proc/spill_gases(obj/origin, datum/gas_mixture/target_mix, ratio) var/datum/gas_mixture/remove_mixture = target_mix.remove_ratio(ratio) var/turf/origin_turf = origin.loc @@ -588,8 +597,12 @@ return origin_turf.assume_air(remove_mixture) -/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/check_spill(seconds_per_tick) +/** + * Processes leaking from moderator hypercriticality. + */ +/obj/machinery/atmospherics/components/unary/hypertorus/core/proc/process_moderator_overflow(seconds_per_tick) var/obj/machinery/atmospherics/components/unary/hypertorus/cracked_part = check_cracked_parts() + // Processing of a preexisting crack if any. if (cracked_part) // We have an existing crack var/leak_rate @@ -607,6 +620,7 @@ spill_gases(cracked_part, moderator_internal, ratio = 1 - (1 - leak_rate) ** seconds_per_tick) return + // No crack. Check for conditions to cause a leak and create a crack if possible. if (moderator_internal.total_moles() < HYPERTORUS_HYPERCRITICAL_MOLES) return cracked_part = create_crack() From 66858d8afd021487c590f3b3302eb4a80dc32b2e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 06:02:52 +0000 Subject: [PATCH 36/74] Automatic changelog for PR #89095 [ci skip] --- html/changelogs/AutoChangeLog-pr-89095.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89095.yml diff --git a/html/changelogs/AutoChangeLog-pr-89095.yml b/html/changelogs/AutoChangeLog-pr-89095.yml new file mode 100644 index 0000000000000..4e52e9a2c38cc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89095.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - bugfix: "Fixes HFR moderator leaking not leaking properly when a part is cracked." \ No newline at end of file From 4be0ded2560050e52a0b483a98b0cc856973e115 Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:25:17 +0200 Subject: [PATCH 37/74] Vending Machines restyle (#89137) ## About The Pull Request Vending UI redesign, using ImageButton component. By default list layout is used, you can switch to grid if you want, unfortunately there is no setting yet ## Why It's Good For The Game You don't have to aim for the blue price button to buy/vend anything Plus, looks better and more cohesive, imho

Comparison, everyone loves them though, right? | Before | After | Grid | | - | - | - | | ![image](https://github.com/user-attachments/assets/76742fe6-0500-453e-9c95-6766606c3f64) | ![image](https://github.com/user-attachments/assets/afe5d623-0953-4d94-a4aa-67bf82a0f9fb) | ![image](https://github.com/user-attachments/assets/8f2b7701-bda0-431a-9311-96c5221f8ebf) |
## Changelog :cl: qol: Vending machines got new design with 2 layouts: List and Grid (List by default) /:cl: --- tgui/packages/tgui/interfaces/Vending.tsx | 319 +++++++++++----------- 1 file changed, 157 insertions(+), 162 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Vending.tsx b/tgui/packages/tgui/interfaces/Vending.tsx index c2c18cf901d62..0752217b11f93 100644 --- a/tgui/packages/tgui/interfaces/Vending.tsx +++ b/tgui/packages/tgui/interfaces/Vending.tsx @@ -1,18 +1,14 @@ import { useState } from 'react'; import { - Box, Button, Icon, - LabeledList, + ImageButton, + Input, NoticeBox, Section, Stack, - Table, } from 'tgui-core/components'; -import { DmIcon, Input } from 'tgui-core/components'; -import { classes } from 'tgui-core/react'; -import { capitalizeAll } from 'tgui-core/string'; -import { createSearch } from 'tgui-core/string'; +import { capitalizeAll, createSearch } from 'tgui-core/string'; import { useBackend } from '../backend'; import { Window } from '../layouts'; @@ -132,7 +128,7 @@ export const Vending = (props) => { ); return ( - + {!!onstation && ( @@ -172,31 +168,20 @@ export const UserDetails = (props) => { const { data } = useBackend(); const { user } = data; - if (!user) { - return ( -
- No ID detected! Contact the Head of Personnel. -
- ); - } else { - return ( -
- - - - - - - {user.name} - - {user.job || 'Unemployed'} - - - - -
- ); - } + return ( + + + + + + + {user + ? `${user.name || 'Unknown'} | ${user.job}` + : 'No ID detected! Contact the Head of Personnel.'} + + + + ); }; /** Displays products in a section, with user balance at top */ @@ -224,6 +209,7 @@ const ProductDisplay = (props: { displayed_currency_icon, displayed_currency_name, } = data; + const [toggleLayout, setToggleLayout] = useState(true); return (
+ +
); }; -/** An individual listing for an item. - * Uses a table layout. Labeledlist might be better, - * but you cannot use item icons as labels currently. +/** + * An individual listing for an item. */ -const VendingRow = (props) => { - const { data } = useBackend(); - const { custom, product, productStock } = props; +const Product = (props) => { + const { act, data } = useBackend(); + const { custom, product, productStock, fluid } = props; const { access, department, jobDiscount, all_products_free, user } = data; + + const colorable = !!productStock?.colorable; const free = all_products_free || product.price === 0; const discount = !product.premium && department === user?.department; const remaining = custom ? product.amount : productStock.amount; @@ -290,140 +284,141 @@ const VendingRow = (props) => { !access && (discount ? redPrice : product.price) > user?.cash); + const baseProps = { + base64: product.image, + dmIcon: product.icon, + dmIconState: product.icon_state, + asset: ['vending32x32', product.path], + disabled: disabled, + tooltipPosition: 'bottom', + buttons: colorable && ( + + ), + product: product, + colorable: colorable, + remaining: remaining, + onClick: () => { + custom + ? act('dispense', { + item: product.path, + }) + : act('vend', { + ref: product.ref, + }); + }, + }; + + const priceProps = { + custom: custom, + discount: discount, + free: free, + product: product, + redPrice: redPrice, + }; + + return fluid ? ( + + ) : ( + + ); +}; + +const ProductGrid = (props) => { + const { product, remaining, ...baseProps } = props; + const { ...priceProps } = props; + return ( - - - - - - {capitalizeAll(product.name)} - - - {!!productStock?.colorable && ( - - )} - - - - - - - - + + + + + x{remaining} +
+ } + > + {capitalizeAll(product.name)} + ); }; -/** Displays the product image. Displays a default if there is none. */ -const ProductImage = (props) => { - const { product } = props; +const ProductList = (props) => { + const { colorable, product, remaining, ...baseProps } = props; + const { ...priceProps } = props; return ( - - {product.img ? ( - - ) : product.icon && product.icon_state ? ( - } - /> - ) : ( - - )} - + + + + {capitalizeAll(product.name)} + + + {remaining} left + + + + + + ); }; -/** In the case of customizable items, ie: shoes, +/** + * In the case of customizable items, ie: shoes, * this displays a color wheel button that opens another window. */ const ProductColorSelect = (props) => { const { act } = useBackend(); - const { disabled, product } = props; + const { disabled, product, fluid } = props; return ( - ) : ( - + return ( + + {custom ? ( + <> + {customPrice} + {!access && displayed_currency_name} + + ) : ( + <> + {standardPrice} + {!free && displayed_currency_name} + + )} + ); }; From 4142ae693beb7aa2878558ce25a23ac8ec6d5e3b Mon Sep 17 00:00:00 2001 From: Aylong <69762909+AyIong@users.noreply.github.com> Date: Mon, 20 Jan 2025 18:26:16 +0200 Subject: [PATCH 38/74] Little Stat Panel fix for Byond 516 (#89142) ## About The Pull Request On the 516, when hovering over the cropped text, the transposed text does not expand the background It's a small fix for that. | Before | After | | - | - | | ![image](https://github.com/user-attachments/assets/7fb94a56-5796-4652-92ba-a8ba6a0f9824) | ![image](https://github.com/user-attachments/assets/f7f17185-7d1d-4db7-8602-65c639faebb5) | --- html/statbrowser.css | 1 + 1 file changed, 1 insertion(+) diff --git a/html/statbrowser.css b/html/statbrowser.css index fb87c99b41cf3..810013209ca30 100644 --- a/html/statbrowser.css +++ b/html/statbrowser.css @@ -150,6 +150,7 @@ img { } .grid-item:hover .grid-item-text { + height: 100%; overflow: visible; white-space: normal; background-color: #ececec; From 5ea3aa27021567c4516d2f1fafe94f1c476e6a6a Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 16:45:10 +0000 Subject: [PATCH 39/74] Automatic changelog for PR #89137 [ci skip] --- html/changelogs/AutoChangeLog-pr-89137.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89137.yml diff --git a/html/changelogs/AutoChangeLog-pr-89137.yml b/html/changelogs/AutoChangeLog-pr-89137.yml new file mode 100644 index 0000000000000..bc6196b6256b8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89137.yml @@ -0,0 +1,4 @@ +author: "AyIong" +delete-after: True +changes: + - qol: "Vending machines got new design with 2 layouts: List and Grid (List by default)" \ No newline at end of file From 2e7be24aadb1298382cb11929cba57bd2c2ded8c Mon Sep 17 00:00:00 2001 From: Rhials <28870487+Rhials@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:18:49 -0500 Subject: [PATCH 40/74] Honor-riffic: Adds toggleable honorific titles to certain job ID trims (#88309) ## About The Pull Request This implements a new, minor, but flavorful system to IDs -- Honorifics. Does going by your full name not suit you? Do you demand respect for the position on Space Station 13 that you've earned and want to be addressed by your title? Do you take yourself WAY too seriously? This is for you. Toggled by ctrl-clicking your ID, honorifics append a title to your name depending on your position. Certain titles (Captain, Officer, Doctor, etc.) will only append to the start (replacing or including the first/last name), while others (PhD., Esq.) can only be appended at the end. ![image](https://github.com/user-attachments/assets/3ae22744-5f6e-4d12-9ea8-ecd60456b5a9) Each job TRIM has a set honorific and positions it can be assigned to. A doctor can be "Doctor Peterson" or "Doctor Peterson Bungle" or "Doctor Bungle". A Lawyer can only choose to be "Peterson Bungle, Esq.". This will only occur when the speaker's voice is the same identity as the one written on the ID's registered name. This should not interfere with Unknown voice obfuscation, stolen ID shenanigans, or anything gameplay-oriented. Hopefully. This feature is also mononym friendly! ![image](https://github.com/user-attachments/assets/21555023-5dd0-49e0-acd5-2dd0a06ae621) This also makes `first_name()` and `last_name()` global procs, and adds one to check if a passed string has spaces/dashes/whitespace/whatever. All of this is compatible with ID name changes, but the voice name must align with the card name to display the honorific. If you are "Peter Stinkypants" with your honorific set to display "Doctor Stinkypants", and your ID's registered name is changed to "Peter Stinker", you show up as "Peter Stinkypants (as Peter Stinker)" with no honorific provided. If you become "Peter Stinker" and have a "Peter Stinker" ID, you will show up as "Doctor Stinker" once again. That all make sense? Great.
So about the ID name stuff...
So, when you activate an honorific on your ID, it DOES change the actual object's name. Not the registered name, but the ID's name will go from "Peter Dawson's ID card" to "Captain Dawson's ID card" when an honorific is applied. This, as far as I've tested, does not mess with anything important, but I can totally see it doing so in a way that makes ctrl-Fing through logs harder than it needs to be. This could probably be changed without too much effort so if the issue does arise I can fix it. If not I am totally fine with reverting this PR until I can make it work (if I can at all).
Admittedly this doesn't have much testing with holopads/radios, but I'm confident the message composure is handled well enough to only display the right names under the right circumstances. If this fucks up logging or naming in any way tell me ASAP because I have a sinking feeling it will in a way more catastrophic than I could ever predict. This PR has been tested thoroughly but I have my limits.
--- code/__DEFINES/id_cards.dm | 19 ++++ code/__DEFINES/say.dm | 3 + code/__HELPERS/names.dm | 19 ++++ code/datums/id_trim/_id_trim.dm | 4 + code/datums/id_trim/centcom.dm | 30 +++++ code/datums/id_trim/jobs.dm | 53 ++++++++- code/datums/id_trim/outfits.dm | 2 + code/datums/id_trim/syndicate.dm | 7 ++ code/datums/voice_of_god_command.dm | 4 +- code/game/machinery/computer/arcade/orion.dm | 2 +- code/game/objects/items/cards_ids.dm | 103 +++++++++++++++++- code/game/say.dm | 13 ++- code/modules/hallucination/fake_chat.dm | 6 +- code/modules/hallucination/fake_death.dm | 2 +- .../mob/living/carbon/human/human_helpers.dm | 2 +- code/modules/mob/mob_helpers.dm | 12 -- 16 files changed, 257 insertions(+), 24 deletions(-) diff --git a/code/__DEFINES/id_cards.dm b/code/__DEFINES/id_cards.dm index a42016dd3de3f..2d720630ce637 100644 --- a/code/__DEFINES/id_cards.dm +++ b/code/__DEFINES/id_cards.dm @@ -42,3 +42,22 @@ * Used to crop the ID card's transparency away when chaching the icon for better use in tgui chat. */ #define ID_ICON_BORDERS 1, 9, 32, 24 + +///Honorific will display next to the first name. +#define HONORIFIC_POSITION_FIRST (1<<0) +///Honorific will display next to the last name. +#define HONORIFIC_POSITION_LAST (1<<1) +///Honorific will not be displayed. +#define HONORIFIC_POSITION_NONE (1<<2) +///Honorific will be appended to the full name at the start. +#define HONORIFIC_POSITION_FIRST_FULL (1<<3) +///Honorific will be appended to the full name at the end. +#define HONORIFIC_POSITION_LAST_FULL (1<<4) + +#define HONORIFIC_POSITION_BITFIELDS(...) list( \ + "Honorific + First Name" = HONORIFIC_POSITION_FIRST, \ + "Honorific + Last Name" = HONORIFIC_POSITION_LAST, \ + "Honorific + Full Name" = HONORIFIC_POSITION_FIRST_FULL, \ + "Full Name + Honorific" = HONORIFIC_POSITION_LAST_FULL, \ + "Disable Honorific" = HONORIFIC_POSITION_NONE, \ +) diff --git a/code/__DEFINES/say.dm b/code/__DEFINES/say.dm index c3bd425af0a65..d80e0d1af2b80 100644 --- a/code/__DEFINES/say.dm +++ b/code/__DEFINES/say.dm @@ -129,3 +129,6 @@ ///Defines for priorities for the bubble_icon_override comp #define BUBBLE_ICON_PRIORITY_ACCESSORY 2 #define BUBBLE_ICON_PRIORITY_ORGAN 1 + +/// Sent from /atom/movable/proc/compose_message() to find an honorific. Compatible with NAME_PART_INDEX: (list/stored_name, mob/living/carbon/carbon_human) +#define COMSIG_ID_GET_HONORIFIC "id_get_honorific" diff --git a/code/__HELPERS/names.dm b/code/__HELPERS/names.dm index 3a82c8dc1a66c..c0615dc746b5b 100644 --- a/code/__HELPERS/names.dm +++ b/code/__HELPERS/names.dm @@ -374,3 +374,22 @@ GLOBAL_DATUM(syndicate_code_response_regex, /regex) return "a rolling pin" else return "something... but the gods didn't set this up right (Please report this bug)" + +///Find the first name of a mob from a passed string with regex +/proc/first_name(given_name) + var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace or "-" + firstname.Find(given_name) + return firstname.match + +/// Find the last name of a mob from a passed string with regex +/proc/last_name(given_name) + var/static/regex/lasttname = new("\[^\\s-\]+$") //First word before whitespace or "-" + lasttname.Find(given_name) + return lasttname.match + +/// Find whitespace or dashes in the passed string with regex and returns TRUE if found +/proc/is_mononym(given_name) + var/static/regex/breaks = regex(@"\s") + if(breaks.Find(given_name)) + return FALSE + return TRUE diff --git a/code/datums/id_trim/_id_trim.dm b/code/datums/id_trim/_id_trim.dm index 32bafcb41d3f7..b9356e9c35dc9 100644 --- a/code/datums/id_trim/_id_trim.dm +++ b/code/datums/id_trim/_id_trim.dm @@ -28,6 +28,10 @@ var/big_pointer = FALSE ///If set, IDs with this trim will give wearers arrows of different colors when pointing var/pointer_color + /// What honorifics, if any, will we set our wearer's name to when worn? + var/list/honorifics + /// What positions can our honorific take? To prevent names like "Peter Dr." + var/honorific_positions = NONE /datum/id_trim/proc/find_job() return null diff --git a/code/datums/id_trim/centcom.dm b/code/datums/id_trim/centcom.dm index 498a4de254e3b..7432540f07f35 100644 --- a/code/datums/id_trim/centcom.dm +++ b/code/datums/id_trim/centcom.dm @@ -23,6 +23,8 @@ department_color = COLOR_CENTCOM_BLUE subdepartment_color = COLOR_SERVICE_LIME big_pointer = FALSE + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Thunderdome Overseers. /datum/id_trim/centcom/thunderdome_overseer @@ -39,11 +41,15 @@ access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_WEAPONS) assignment = "CentCom Intern" big_pointer = FALSE + honorifics = list("Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Head Interns. Different assignment, common station access added on. /datum/id_trim/centcom/intern/head assignment = "CentCom Head Intern" big_pointer = TRUE + honorifics = list("Head Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/intern/head/New() . = ..() @@ -66,6 +72,8 @@ /datum/id_trim/centcom/medical_officer access = list(ACCESS_CENT_GENERAL, ACCESS_CENT_LIVING, ACCESS_CENT_MEDICAL) assignment = JOB_CENTCOM_MEDICAL_DOCTOR + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /// Trim for Centcom Research Officers. /datum/id_trim/centcom/research_officer @@ -94,6 +102,8 @@ /// Trim for Centcom Commanders. All Centcom and Station Access. /datum/id_trim/centcom/commander assignment = JOB_CENTCOM_COMMANDER + honorifics = list("Commander", "CMDR.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/commander/New() . = ..() @@ -105,6 +115,9 @@ assignment = JOB_ERT_DEATHSQUAD trim_state = "trim_deathcommando" sechud_icon_state = SECHUD_DEATH_COMMANDO + honorifics = list("Commando") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/deathsquad/New() . = ..() @@ -114,6 +127,8 @@ /// Trim for generic ERT interns. No universal ID card changing access. /datum/id_trim/centcom/ert assignment = "Emergency Response Team Intern" + honorifics = list("Intern") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/New() . = ..() @@ -138,6 +153,8 @@ subdepartment_color = COLOR_SECURITY_RED sechud_icon_state = SECHUD_SECURITY_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Officer") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/security/New() . = ..() @@ -164,6 +181,9 @@ subdepartment_color = COLOR_MEDICAL_BLUE sechud_icon_state = SECHUD_MEDICAL_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/medical/New() . = ..() @@ -177,6 +197,9 @@ subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_RELIGIOUS_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Chaplain") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/chaplain/New() . = ..() @@ -190,6 +213,9 @@ subdepartment_color = COLOR_SERVICE_LIME sechud_icon_state = SECHUD_JANITORIAL_RESPONSE_OFFICER big_pointer = FALSE + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE + /datum/id_trim/centcom/ert/janitor/New() . = ..() @@ -212,7 +238,11 @@ /datum/id_trim/centcom/ert/militia assignment = "Frontier Militia" big_pointer = FALSE + honorifics = list("Minuteman") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/centcom/ert/militia/general assignment = "Frontier Militia General" big_pointer = TRUE + honorifics = list("Minuteman General", "General") + honorific_positions = HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE diff --git a/code/datums/id_trim/jobs.dm b/code/datums/id_trim/jobs.dm index 34432a638db01..4b8b630617571 100644 --- a/code/datums/id_trim/jobs.dm +++ b/code/datums/id_trim/jobs.dm @@ -134,6 +134,8 @@ ACCESS_CE, ) job = /datum/job/atmospheric_technician + honorifics = list("Technician") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/bartender assignment = JOB_BARTENDER @@ -181,6 +183,8 @@ ACCESS_HOP, ) job = /datum/job/pun_pun + honorifics = list(", Almighty Scourge") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/bitrunner assignment = JOB_BITRUNNER @@ -250,6 +254,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/bridge_assistant + honorifics = list("Underling", "Assistant", "Mate") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/captain assignment = JOB_CAPTAIN @@ -266,6 +272,8 @@ job = /datum/job/captain big_pointer = TRUE pointer_color = COLOR_COMMAND_BLUE + honorifics = list("Captain", "Cpt.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// Captain gets all station accesses hardcoded in because it's the Captain. /datum/id_trim/job/captain/New() @@ -300,6 +308,9 @@ ACCESS_QM, ) job = /datum/job/cargo_technician + honorifics = list("Courier") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/job/chaplain assignment = JOB_CHAPLAIN @@ -322,6 +333,8 @@ ACCESS_HOP, ) job = /datum/job/chaplain + honorifics = list("Chaplain", "Reverend") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/chemist assignment = JOB_CHEMIST @@ -390,6 +403,8 @@ job = /datum/job/chief_engineer big_pointer = TRUE pointer_color = COLOR_ENGINEERING_ORANGE + honorifics = list("Chief") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/job/chief_medical_officer assignment = JOB_CHIEF_MEDICAL_OFFICER @@ -431,6 +446,8 @@ job = /datum/job/chief_medical_officer big_pointer = TRUE pointer_color = COLOR_MEDICAL_BLUE + honorifics = list(", PhD.", ", MD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/clown assignment = JOB_CLOWN @@ -473,10 +490,14 @@ ACCESS_HOP, ) job = /datum/job/cook + honorifics = list("Cook") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/cook/chef assignment = JOB_CHEF sechud_icon_state = SECHUD_CHEF + honorifics = list("Chef") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/coroner assignment = JOB_CORONER @@ -553,6 +574,8 @@ ACCESS_HOS, ) job = /datum/job/detective + honorifics = list("Detective", "Investigator") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/detective/refresh_trim_access() . = ..() @@ -697,6 +720,8 @@ job = /datum/job/head_of_security big_pointer = TRUE pointer_color = COLOR_SECURITY_RED + honorifics = list("Chief Officer", "Chief", "Officer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/head_of_security/refresh_trim_access() . = ..() @@ -727,6 +752,8 @@ ACCESS_CHANGE_IDS, ) job = /datum/job/janitor + honorifics = list("Custodian") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/lawyer assignment = JOB_LAWYER @@ -748,6 +775,8 @@ ACCESS_HOP, ) job = /datum/job/lawyer + honorifics = list(", Esq.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/medical_doctor assignment = JOB_MEDICAL_DOCTOR @@ -773,6 +802,8 @@ ACCESS_CMO, ) job = /datum/job/doctor + honorifics = list("Doctor", "Dr.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/mime assignment = JOB_MIME @@ -824,6 +855,8 @@ ACCESS_CMO, ) job = /datum/job/paramedic + honorifics = list("EMT") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/prisoner assignment = JOB_PRISONER @@ -839,6 +872,8 @@ ) job = /datum/job/prisoner threat_modifier = 1 // I'm watching you + honorifics = list("Convict") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/prisoner/one trim_state = "trim_prisoner_1" @@ -891,6 +926,8 @@ ACCESS_HOP, ) job = /datum/job/psychologist + honorifics = list(", PhD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/quartermaster assignment = JOB_QUARTERMASTER @@ -931,6 +968,8 @@ job = /datum/job/quartermaster big_pointer = TRUE pointer_color = COLOR_CARGO_BROWN + honorifics = list("Manager") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/research_director assignment = JOB_RESEARCH_DIRECTOR @@ -981,6 +1020,8 @@ job = /datum/job/research_director big_pointer = TRUE pointer_color = COLOR_SCIENCE_PINK + honorifics = list("Director", "Dir.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/roboticist assignment = JOB_ROBOTICIST @@ -1038,6 +1079,8 @@ ACCESS_RD, ) job = /datum/job/scientist + honorifics = list("Researcher") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// Sec officers have departmental variants. They each have their own trims with bonus departmental accesses. /datum/id_trim/job/security_officer @@ -1066,6 +1109,8 @@ ACCESS_HOS, ) job = /datum/job/security_officer + honorifics = list("Officer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /// List of bonus departmental accesses that departmental sec officers get by default. var/department_access = list() /// List of bonus departmental accesses that departmental security officers can in relation to how many overall security officers there are if the scaling system is set up. These can otherwise be granted via config settings. @@ -1144,6 +1189,7 @@ ACCESS_SURGERY, ACCESS_VIROLOGY, ) + honorifics = list("Orderly", "Officer") /datum/id_trim/job/security_officer/science assignment = JOB_SECURITY_OFFICER_SCIENCE @@ -1226,6 +1272,8 @@ ACCESS_CE, ) job = /datum/job/station_engineer + honorifics = list("Engineer") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/veteran_advisor assignment = JOB_VETERAN_ADVISOR @@ -1247,6 +1295,8 @@ template_access = list() job = /datum/job/veteran_advisor big_pointer = TRUE + honorifics = list("General", "Gen.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/veteran_advisor/refresh_trim_access() . = ..() @@ -1258,7 +1308,6 @@ if(CONFIG_GET(flag/security_has_maint_access)) access |= list(ACCESS_MAINT_TUNNELS) - /datum/id_trim/job/warden assignment = JOB_WARDEN trim_state = "trim_warden" @@ -1286,6 +1335,8 @@ ACCESS_HOS, ) job = /datum/job/warden + honorifics = list("Officer", "Watchman", "Lieutenant", "Lt.") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE /datum/id_trim/job/warden/refresh_trim_access() . = ..() diff --git a/code/datums/id_trim/outfits.dm b/code/datums/id_trim/outfits.dm index a2944a469f43e..c46938be6e094 100644 --- a/code/datums/id_trim/outfits.dm +++ b/code/datums/id_trim/outfits.dm @@ -71,6 +71,8 @@ department_color = COLOR_BLACK subdepartment_color = COLOR_GREEN threat_modifier = -1 // Cops recognise cops + honorifics = list("CISO") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_NONE /datum/id_trim/cyber_police/New() . = ..() diff --git a/code/datums/id_trim/syndicate.dm b/code/datums/id_trim/syndicate.dm index 41c76aaf3784c..28a0429d9352f 100644 --- a/code/datums/id_trim/syndicate.dm +++ b/code/datums/id_trim/syndicate.dm @@ -17,6 +17,10 @@ big_pointer = FALSE /// Interdyne medical Staff +/datum/id_trim/syndicom/Interdyne + honorifics = list(", PhD.") + honorific_positions = HONORIFIC_POSITION_LAST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/syndicom/Interdyne/pharmacist assignment = "Interdyne Pharmacist" trim_state = "trim_medicaldoctor" @@ -46,6 +50,9 @@ access = list(ACCESS_SYNDICATE, ACCESS_MAINT_TUNNELS) big_pointer = FALSE pointer_color = null + honorifics = list("Auditor") + honorific_positions = HONORIFIC_POSITION_FIRST | HONORIFIC_POSITION_LAST | HONORIFIC_POSITION_FIRST_FULL | HONORIFIC_POSITION_NONE + /datum/id_trim/syndicom/irs/auditor assignment = "Internal Revenue Service Head Auditor" diff --git a/code/datums/voice_of_god_command.dm b/code/datums/voice_of_god_command.dm index 21d4f460617b6..3bbd5768e21e3 100644 --- a/code/datums/voice_of_god_command.dm +++ b/code/datums/voice_of_god_command.dm @@ -52,12 +52,12 @@ GLOBAL_LIST_INIT(voice_of_god_commands, init_voice_of_god_commands()) listeners += candidate //Let's ensure the listener's name is not matched within another word or command (and viceversa). e.g. "Saul" in "somersault" - var/their_first_name = candidate.first_name() + var/their_first_name = first_name(candidate.name) if(!GLOB.all_voice_of_god_triggers.Find(their_first_name) && findtext(message, regex("(\\L|^)[their_first_name](\\L|$)", "i"))) specific_listeners += candidate //focus on those with the specified name to_remove_string += "[to_remove_string ? "|" : null][their_first_name]" continue - var/their_last_name = candidate.last_name() + var/their_last_name = last_name(candidate.name) if(their_last_name != their_first_name && !GLOB.all_voice_of_god_triggers.Find(their_last_name) && findtext(message, regex("(\\L|^)[their_last_name](\\L|$)", "i"))) specific_listeners += candidate // Ditto to_remove_string += "[to_remove_string ? "|" : null][their_last_name]" diff --git a/code/game/machinery/computer/arcade/orion.dm b/code/game/machinery/computer/arcade/orion.dm index a6685e4782ccd..c8236b5e8839f 100644 --- a/code/game/machinery/computer/arcade/orion.dm +++ b/code/game/machinery/computer/arcade/orion.dm @@ -85,7 +85,7 @@ /obj/machinery/computer/arcade/orion_trail/proc/newgame() // Set names of settlers in crew var/mob/living/player = usr - var/player_crew_name = player.first_name() + var/player_crew_name = first_name(player.name) settlers = list() for(var/i in 1 to ORION_STARTING_CREW_COUNT - 1) //one reserved to be YOU add_crewmember(update = FALSE) diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index afc121ab770c5..181bc6eef64c3 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -32,6 +32,8 @@ /// Cached icon that has been built for this card. Intended to be displayed in chat. Cardboards IDs and actual IDs use it. var/icon/cached_flat_icon + ///What is our honorific name/title combo to be displayed? + var/honorific_title /obj/item/card/suicide_act(mob/living/carbon/user) user.visible_message(span_suicide("[user] begins to swipe [user.p_their()] neck with \the [src]! It looks like [user.p_theyre()] trying to commit suicide!")) @@ -111,6 +113,11 @@ var/big_pointer = FALSE ///If set, the arrow will have a different color. var/pointer_color + /// Will this ID card use the first or last name as the name displayed with the honorific? + var/honorific_position = HONORIFIC_POSITION_NONE + /// What is our selected honorific? + var/chosen_honorific + /datum/armor/card_id fire = 100 @@ -142,6 +149,7 @@ register_context() RegisterSignal(src, COMSIG_ATOM_UPDATED_ICON, PROC_REF(update_in_wallet)) + RegisterSignal(src, COMSIG_ID_GET_HONORIFIC, PROC_REF(return_message_name_part)) if(prob(1)) ADD_TRAIT(src, TRAIT_TASTEFULLY_THICK_ID_CARD, ROUNDSTART_TRAIT) @@ -157,6 +165,20 @@ if(slot == ITEM_SLOT_ID) RegisterSignal(user, COMSIG_MOVABLE_POINTED, PROC_REF(on_pointed)) +/obj/item/card/id/proc/return_message_name_part(datum/source, list/stored_name, mob/living/carbon/carbon_human) + SIGNAL_HANDLER + var/voice_name = carbon_human.GetVoice() + var/end_string = "" + var/return_string = "" + if(carbon_human.name != voice_name) + end_string += " (as [registered_name])" + if(trim && honorific_position != HONORIFIC_POSITION_NONE && (carbon_human.name == voice_name)) //The voice and name are the same, so we display the title. + return_string += honorific_title + else + return_string += voice_name //Name on the ID ain't the same as the speaker, so we display their real name with no title. + return_string += end_string + stored_name[NAME_PART_INDEX] = return_string + /obj/item/card/id/proc/on_pointed(mob/living/user, atom/pointed, obj/effect/temp_visual/point/point) SIGNAL_HANDLER if((!big_pointer && !pointer_color) || HAS_TRAIT(user, TRAIT_UNKNOWN)) @@ -478,6 +500,8 @@ context[SCREENTIP_CONTEXT_ALT_RMB] = "Assign account" else if(registered_account.account_balance > 0) context[SCREENTIP_CONTEXT_ALT_LMB] = "Withdraw credits" + if(trim && length(trim.honorifics)) + context[SCREENTIP_CONTEXT_CTRL_LMB] = "Toggle honorific" return CONTEXTUAL_SCREENTIP_SET /obj/item/card/id/proc/try_project_paystand(mob/user, turf/target) @@ -786,7 +810,7 @@ for(var/mob/living/carbon/human/viewing_mob in viewers(user, 2)) if(viewing_mob.stat || viewing_mob == user) continue - viewing_mob.say("Is something wrong? [user.first_name()]... you're sweating.", forced = "psycho") + viewing_mob.say("Is something wrong? [first_name(user.name)]... you're sweating.", forced = "psycho") break /obj/item/card/id/examine_more(mob/user) @@ -845,7 +869,15 @@ /// Updates the name based on the card's vars and state. /obj/item/card/id/proc/update_label() - var/name_string = registered_name ? "[registered_name]'s ID Card" : initial(name) + var/name_string + if(registered_name) + if(trim && (honorific_position & ~HONORIFIC_POSITION_NONE)) + name_string = "[update_honorific()]'s ID Card" + else + name_string = "[registered_name]'s ID Card" + else + name_string = initial(name) + var/assignment_string if(is_intern) @@ -858,6 +890,24 @@ name = "[name_string] ([assignment_string])" +/// Re-generates the honorific title. Returns the compiled honorific_title value +/obj/item/card/id/proc/update_honorific() + var/is_mononym = is_mononym(registered_name) + switch(honorific_position) + if(HONORIFIC_POSITION_FIRST) + honorific_title = "[chosen_honorific] [first_name(registered_name)]" + if(HONORIFIC_POSITION_LAST) + honorific_title = "[chosen_honorific] [last_name(registered_name)]" + if(HONORIFIC_POSITION_FIRST_FULL) + honorific_title = "[chosen_honorific] [first_name(registered_name)]" + if(!is_mononym) + honorific_title += " [last_name(registered_name)]" + if(HONORIFIC_POSITION_LAST_FULL) + if(!is_mononym) + honorific_title += "[first_name(registered_name)] " + honorific_title += "[last_name(registered_name)][chosen_honorific]" + return honorific_title + /// Returns the trim assignment name. /obj/item/card/id/proc/get_trim_assignment() return trim?.assignment || assignment @@ -871,6 +921,55 @@ return insert_money(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING return NONE +/obj/item/card/id/item_ctrl_click(mob/user) + if(!in_contents_of(user) || user.incapacitated) //Check if the ID is in the ID slot, so it can be changed from there too. + return + + if(!trim) + balloon_alert(user, "card has no trim!") + return + + if(!length(trim.honorifics)) + balloon_alert(user, "card has no honorific to use!") + return + + var/list/choices = list() + var/list/readable_names = HONORIFIC_POSITION_BITFIELDS() + for(var/i in readable_names) //Filter out the options you don't have on your ID. + if(trim.honorific_positions & readable_names[i]) //If the positions list has the same bit value as the readable list. + choices += i + + var/chosen_position = tgui_input_list(user, "What position do you want your honorific in?", "Flair!", choices) + if(user.incapacitated || !in_contents_of(user)) + return + var/honorific_position_to_use = readable_names[chosen_position] + + honorific_position = initial(honorific_position) //In case you want to force an honorific on an ID, set a default that won't always be NONE. + honorific_title = null //We reset this regardless so that we don't stack titles on accident. + + if(honorific_position_to_use & HONORIFIC_POSITION_NONE) + balloon_alert(user, "honorific disabled") + else + var/new_honorific = tgui_input_list(user, "What honorific do you want to use?", "Flair!!!", trim.honorifics) + if(!new_honorific || user.incapacitated || !in_contents_of(user)) + return + chosen_honorific = new_honorific + switch(honorific_position_to_use) + if(HONORIFIC_POSITION_FIRST) + honorific_position = HONORIFIC_POSITION_FIRST + balloon_alert(user, "honorific set: display first name") + if(HONORIFIC_POSITION_LAST) + honorific_position = HONORIFIC_POSITION_LAST + balloon_alert(user, "honorific set: display last name") + if(HONORIFIC_POSITION_FIRST_FULL) + honorific_position = HONORIFIC_POSITION_FIRST_FULL + balloon_alert(user, "honorific set: start of full name") + if(HONORIFIC_POSITION_LAST_FULL) + honorific_position = HONORIFIC_POSITION_LAST_FULL + balloon_alert(user, "honorific set: end of full name") + + update_label() + /obj/item/card/id/away name = "\proper a perfectly generic identification card" desc = "A perfectly generic identification card. Looks like it could use some flavor." diff --git a/code/game/say.dm b/code/game/say.dm index 4a37bad451b49..e597ffc7b11f8 100644 --- a/code/game/say.dm +++ b/code/game/say.dm @@ -148,7 +148,18 @@ GLOBAL_LIST_INIT(freqtospan, list( //Speaker name var/namepart var/list/stored_name = list(null) - SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name) + + if(iscarbon(speaker)) //First, try to pull the modified title from a carbon's ID. This will override both visual and audible names. + var/mob/living/carbon/carbon_human = speaker + var/obj/item/id_slot = carbon_human.get_item_by_slot(ITEM_SLOT_ID) + if(id_slot) + var/obj/item/card/id/id_card = id_slot?.GetID() + if(id_card) + SEND_SIGNAL(id_card, COMSIG_ID_GET_HONORIFIC, stored_name, carbon_human) + + if(!stored_name[NAME_PART_INDEX]) //Otherwise, we just use whatever the name signal gives us. + SEND_SIGNAL(speaker, COMSIG_MOVABLE_MESSAGE_GET_NAME_PART, stored_name, visible_name) + namepart = stored_name[NAME_PART_INDEX] || "[speaker.GetVoice()]" //End name span. diff --git a/code/modules/hallucination/fake_chat.dm b/code/modules/hallucination/fake_chat.dm index 049a337c1101c..963e718eed865 100644 --- a/code/modules/hallucination/fake_chat.dm +++ b/code/modules/hallucination/fake_chat.dm @@ -50,7 +50,7 @@ chosen = pick(list("Help!", "[pick_list_replacements(HALLUCINATION_FILE, "people")] is [pick_list_replacements(HALLUCINATION_FILE, "accusations")]!", "[pick_list_replacements(HALLUCINATION_FILE, "threat")] in [pick_list_replacements(HALLUCINATION_FILE, "location")][prob(50)?"!":"!!"]", - "[pick("Where's [hallucinator.first_name()]?", "Set [hallucinator.first_name()] to arrest!")]", + "[pick("Where's [first_name(hallucinator.name)]?", "Set [first_name(hallucinator.name)] to arrest!")]", "[pick("C","Ai, c","Someone c","Rec")]all the shuttle!", "AI [pick("rogue", "is dead")]!!", "Borgs rogue!", @@ -58,7 +58,7 @@ else chosen = pick(list("[pick_list_replacements(HALLUCINATION_FILE, "suspicion")]", "[pick_list_replacements(HALLUCINATION_FILE, "conversation")]", - "[pick_list_replacements(HALLUCINATION_FILE, "greetings")][hallucinator.first_name()]!", + "[pick_list_replacements(HALLUCINATION_FILE, "greetings")][first_name(hallucinator.name)]!", "[pick_list_replacements(HALLUCINATION_FILE, "getout")]", "[pick_list_replacements(HALLUCINATION_FILE, "weird")]", "[pick_list_replacements(HALLUCINATION_FILE, "didyouhearthat")]", @@ -71,7 +71,7 @@ chosen = capitalize(chosen) - chosen = replacetext(chosen, "%TARGETNAME%", hallucinator.first_name()) + chosen = replacetext(chosen, "%TARGETNAME%", first_name(hallucinator.name)) // Log the message feedback_details += "Type: [is_radio ? "Radio" : "Talk"], Source: [speaker.real_name], Message: [chosen]" diff --git a/code/modules/hallucination/fake_death.dm b/code/modules/hallucination/fake_death.dm index 126e9dd3a2b48..9583418f23220 100644 --- a/code/modules/hallucination/fake_death.dm +++ b/code/modules/hallucination/fake_death.dm @@ -59,7 +59,7 @@ "FUCK", "git gud", "god damn it", - "hey [hallucinator.first_name()]", + "hey [first_name(hallucinator.name)]", "i[prob(50) ? " fucking" : ""] hate [pick(things_to_hate)]", "is the AI rogue?", "rip", diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 1d72b9b1f17ec..8166612a87333 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -45,7 +45,7 @@ return signal_face // no need to null-check, because force_set will always set a signal_face var/face_name = !isnull(signal_face) ? signal_face : get_face_name("") var/id_name = !isnull(signal_id) ? signal_id : get_id_name("") - if (force_real_name) + if(force_real_name) var/fake_name if (face_name && face_name != real_name) fake_name = face_name diff --git a/code/modules/mob/mob_helpers.dm b/code/modules/mob/mob_helpers.dm index 006b2684c9755..ffc201940847a 100644 --- a/code/modules/mob/mob_helpers.dm +++ b/code/modules/mob/mob_helpers.dm @@ -216,18 +216,6 @@ return M return 0 -///Find the first name of a mob from the real name with regex -/mob/proc/first_name() - var/static/regex/firstname = new("^\[^\\s-\]+") //First word before whitespace or "-" - firstname.Find(real_name) - return firstname.match - -/// Find the last name of a mob from the real name with regex -/mob/proc/last_name() - var/static/regex/lasttname = new("\[^\\s-\]+$") //First word before whitespace or "-" - lasttname.Find(real_name) - return lasttname.match - ///Returns a mob's real name between brackets. Useful when you want to display a mob's name alongside their real name /mob/proc/get_realname_string() if(real_name && real_name != name) From 2ac49eb11293b6418913e6517000edcbd2e9a395 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 20 Jan 2025 20:26:27 +0000 Subject: [PATCH 41/74] Automatic changelog for PR #88309 [ci skip] --- html/changelogs/AutoChangeLog-pr-88309.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-88309.yml diff --git a/html/changelogs/AutoChangeLog-pr-88309.yml b/html/changelogs/AutoChangeLog-pr-88309.yml new file mode 100644 index 0000000000000..8aacfcb95343c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-88309.yml @@ -0,0 +1,4 @@ +author: "Rhials" +delete-after: True +changes: + - 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." \ No newline at end of file From 54cac28b9987be87ca000b26f49fee25975e4f52 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 02:00:15 +0000 Subject: [PATCH 42/74] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-88309.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89047.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89095.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89137.yml | 4 ---- html/changelogs/archive/2025-01.yml | 12 ++++++++++++ 5 files changed, 12 insertions(+), 17 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-88309.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89047.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89095.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89137.yml diff --git a/html/changelogs/AutoChangeLog-pr-88309.yml b/html/changelogs/AutoChangeLog-pr-88309.yml deleted file mode 100644 index 8aacfcb95343c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-88309.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - 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." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89047.yml b/html/changelogs/AutoChangeLog-pr-89047.yml deleted file mode 100644 index 784e95a25ddc0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89047.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "NamelessFairy" -delete-after: True -changes: - - bugfix: "Admin fired stray syndicate cargo pods will not rebel against admin whims and launch themselves when cancelled." - - admin: "Admins have new categories to fill syndicate cargo pods with." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89095.yml b/html/changelogs/AutoChangeLog-pr-89095.yml deleted file mode 100644 index 4e52e9a2c38cc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89095.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - bugfix: "Fixes HFR moderator leaking not leaking properly when a part is cracked." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89137.yml b/html/changelogs/AutoChangeLog-pr-89137.yml deleted file mode 100644 index bc6196b6256b8..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89137.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "AyIong" -delete-after: True -changes: - - qol: "Vending machines got new design with 2 layouts: List and Grid (List by default)" \ No newline at end of file diff --git a/html/changelogs/archive/2025-01.yml b/html/changelogs/archive/2025-01.yml index d0707a54087d2..f1115177d0d77 100644 --- a/html/changelogs/archive/2025-01.yml +++ b/html/changelogs/archive/2025-01.yml @@ -547,3 +547,15 @@ mc-oofert: - refactor: mimics (bolt of animation, malf ai Machine Override, etc) are basicmobs - bugfix: crate mimics may now be opened +2025-01-21: + AyIong: + - qol: 'Vending machines got new design with 2 layouts: List and Grid (List by default)' + NamelessFairy: + - bugfix: Admin fired stray syndicate cargo pods will not rebel against admin whims + and launch themselves when cancelled. + - admin: Admins have new categories to fill syndicate cargo pods with. + Pickle-Coding: + - bugfix: Fixes HFR moderator leaking not leaking properly when a part is cracked. + 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. From fca15d8b03352fba686a0e68b065096a83e5496a Mon Sep 17 00:00:00 2001 From: kuricityy Date: Tue, 21 Jan 2025 00:55:41 -0500 Subject: [PATCH 43/74] Makes Icebox ruins not count towards blob total, as well as preventing them from spawning there. (#89113) ## About The Pull Request Makes icebox ruins not count towards blob total, also stops them from spawning there. ## Why It's Good For The Game I've been seeing a decent bit of blobs spawning on icebox ruins, such as Moffuchi's, the abandoned engineering outpost, Lizard gas, almost every ruin on icebox. The intent of blob isnt to cower off station, ensure likely no one can find you, then branch out onto the station. I understand that wastes blobs exist, but if they do it in the actual wastes, it doesnt count towards their total, and they actually have to branch out into the wastes before they begin. With Z level blobs already fucking over people majorly on icebox if the blob picks the right spot, I'm sure they wont need to be able to spawn in ruins to win. They also cannot spawn in ruins on any other station, so it just seems right to me. ## Changelog :cl: fix: Blob's can no longer place their core in ruins on Icebox. /:cl: --- code/game/area/areas/ruins/_ruins.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/game/area/areas/ruins/_ruins.dm b/code/game/area/areas/ruins/_ruins.dm index 46cf851b1ebd1..f2ecc7ac73e3e 100644 --- a/code/game/area/areas/ruins/_ruins.dm +++ b/code/game/area/areas/ruins/_ruins.dm @@ -5,7 +5,7 @@ icon = 'icons/area/areas_ruins.dmi' icon_state = "ruins" default_gravity = STANDARD_GRAVITY - area_flags = HIDDEN_AREA | BLOBS_ALLOWED | UNIQUE_AREA + area_flags = HIDDEN_AREA | UNIQUE_AREA ambience_index = AMBIENCE_RUINS flags_1 = CAN_BE_DIRTY_1 sound_environment = SOUND_ENVIRONMENT_STONEROOM From ee3693bfb09990cef02f2a91fa3d3a521edb38b7 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 07:10:24 +0000 Subject: [PATCH 44/74] Automatic changelog for PR #89113 [ci skip] --- html/changelogs/AutoChangeLog-pr-89113.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89113.yml diff --git a/html/changelogs/AutoChangeLog-pr-89113.yml b/html/changelogs/AutoChangeLog-pr-89113.yml new file mode 100644 index 0000000000000..a11767ec7085f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89113.yml @@ -0,0 +1,4 @@ +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 From 4f2ff570907053423b0f0a196ac8f61f0934b551 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Wed, 22 Jan 2025 05:21:22 +1100 Subject: [PATCH 45/74] The Big Bess ripley now uses the correct sprite while piloted by an AI. (#89148) --- code/modules/vehicles/mecha/working/ripley.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/vehicles/mecha/working/ripley.dm b/code/modules/vehicles/mecha/working/ripley.dm index c9fb6b8fdbe2a..29bc3fb4d4841 100644 --- a/code/modules/vehicles/mecha/working/ripley.dm +++ b/code/modules/vehicles/mecha/working/ripley.dm @@ -259,10 +259,11 @@ GLOBAL_DATUM(cargo_ripley, /obj/vehicle/sealed/mecha/ripley/cargo) /obj/vehicle/sealed/mecha/ripley/cargo - desc = "An ailing, old, repurposed cargo hauler. Most of its equipment wires are frayed or missing and its frame is rusted." name = "\improper APLU \"Big Bess\"" + desc = "An ailing, old, repurposed cargo hauler. Most of its equipment wires are frayed or missing and its frame is rusted." icon_state = "hauler" base_icon_state = "hauler" + silicon_icon_state = "hauler-empty" max_integrity = 100 //Has half the health of a normal RIPLEY mech, so it's harder to use as a weapon. /obj/vehicle/sealed/mecha/ripley/cargo/Initialize(mapload) From 6b74818ca80ddc3a472c945d809095b50bda0edf Mon Sep 17 00:00:00 2001 From: Arceniu <129214736+Arceniu@users.noreply.github.com> Date: Tue, 21 Jan 2025 21:21:40 +0300 Subject: [PATCH 46/74] fix: floortile gloves fishing (#89145) --- code/modules/clothing/gloves/combat.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/clothing/gloves/combat.dm b/code/modules/clothing/gloves/combat.dm index 55eeeba723f11..e7e12c8ee4b14 100644 --- a/code/modules/clothing/gloves/combat.dm +++ b/code/modules/clothing/gloves/combat.dm @@ -35,6 +35,6 @@ icon_state = "ftc_gloves" inhand_icon_state = "greyscale_gloves" -/obj/item/clothing/gloves/combat/floortiletile/Initialize(mapload) +/obj/item/clothing/gloves/combat/floortile/Initialize(mapload) . = ..() AddComponent(/datum/component/adjust_fishing_difficulty, -5) //tacticool From e14fce118714e3612372e1bfbe622460dc8eff47 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:21:41 +0000 Subject: [PATCH 47/74] Automatic changelog for PR #89148 [ci skip] --- html/changelogs/AutoChangeLog-pr-89148.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89148.yml diff --git a/html/changelogs/AutoChangeLog-pr-89148.yml b/html/changelogs/AutoChangeLog-pr-89148.yml new file mode 100644 index 0000000000000..ebd628d99c136 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89148.yml @@ -0,0 +1,4 @@ +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 From bc79dff6a75a5b95a5b6a29b3846adc2bad5db0f Mon Sep 17 00:00:00 2001 From: Gear <9438930+the-og-gear@users.noreply.github.com> Date: Tue, 21 Jan 2025 13:22:53 -0500 Subject: [PATCH 48/74] Make deluxe donks uncraftable unless learned (#89143) --- .../modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm index 522f6e9f695f8..130fcb57b696a 100644 --- a/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm +++ b/code/modules/food_and_drinks/recipes/tablecraft/recipes_pastry.dm @@ -418,6 +418,7 @@ ) result = /obj/item/food/donkpocket/deluxe category = CAT_PASTRY + crafting_flags = parent_type::crafting_flags | CRAFT_MUST_BE_LEARNED /datum/crafting_recipe/food/donkpocket/deluxe/nocarb time = 15 From 08a197fdbdd77213199b6c51205cd68bc442c21f Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:23:17 +0000 Subject: [PATCH 49/74] Automatic changelog for PR #89143 [ci skip] --- html/changelogs/AutoChangeLog-pr-89143.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89143.yml diff --git a/html/changelogs/AutoChangeLog-pr-89143.yml b/html/changelogs/AutoChangeLog-pr-89143.yml new file mode 100644 index 0000000000000..9edd1450dccd6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89143.yml @@ -0,0 +1,4 @@ +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 From 03203d50f419e1c67161c35a6f6587c828d9149a Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Tue, 21 Jan 2025 23:58:08 +0530 Subject: [PATCH 50/74] Fixes `atom_storage` breaking pockets when moving its item to hand (#89141) --- code/datums/storage/storage.dm | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/code/datums/storage/storage.dm b/code/datums/storage/storage.dm index b8bfcf80382de..fe54a84c0769e 100644 --- a/code/datums/storage/storage.dm +++ b/code/datums/storage/storage.dm @@ -856,15 +856,8 @@ GLOBAL_LIST_EMPTY(cached_storage_typecaches) return COMPONENT_CANCEL_ATTACK_CHAIN if(ishuman(user)) var/mob/living/carbon/human/hum = user - if(hum.l_store == parent && !hum.get_active_held_item()) - INVOKE_ASYNC(hum, TYPE_PROC_REF(/mob, put_in_hands), parent) - hum.l_store = null + if(hum.l_store == parent || hum.r_store == parent) return - if(hum.r_store == parent && !hum.get_active_held_item()) - INVOKE_ASYNC(hum, TYPE_PROC_REF(/mob, put_in_hands), parent) - hum.r_store = null - return - if(parent.loc == user) INVOKE_ASYNC(src, PROC_REF(open_storage), user) return COMPONENT_CANCEL_ATTACK_CHAIN From a43be97d422683f9e6cbb1d1b8b2e859b7064de7 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:28:44 +0000 Subject: [PATCH 51/74] Automatic changelog for PR #89141 [ci skip] --- html/changelogs/AutoChangeLog-pr-89141.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89141.yml diff --git a/html/changelogs/AutoChangeLog-pr-89141.yml b/html/changelogs/AutoChangeLog-pr-89141.yml new file mode 100644 index 0000000000000..a7315cab3523a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89141.yml @@ -0,0 +1,4 @@ +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 From 42664adb7799bb561e80774ce09aa60a6107e129 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Wed, 22 Jan 2025 00:26:42 +0530 Subject: [PATCH 52/74] Fixes fishing auto reel moving fixed objects (#89144) --- code/modules/fishing/fishing_equipment.dm | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/code/modules/fishing/fishing_equipment.dm b/code/modules/fishing/fishing_equipment.dm index 37aea262426bb..4961fdbc042c8 100644 --- a/code/modules/fishing/fishing_equipment.dm +++ b/code/modules/fishing/fishing_equipment.dm @@ -104,29 +104,30 @@ SIGNAL_HANDLER UnregisterSignal(rod, COMSIG_FISHING_ROD_HOOKED_ITEM) -/obj/item/fishing_line/auto_reel/proc/on_hooked_item(obj/item/fishing_rod/source, atom/target, mob/living/user) +/obj/item/fishing_line/auto_reel/proc/on_hooked_item(obj/item/fishing_rod/source, atom/movable/target, mob/living/user) SIGNAL_HANDLER - if(!ismovable(target)) + + if(!istype(target) || target.anchored || target.move_resist >= MOVE_FORCE_STRONG) return - var/atom/movable/movable_target = target var/please_be_gentle = FALSE var/atom/destination var/datum/callback/throw_callback - if(isliving(movable_target) || !isitem(movable_target)) + if(isliving(target) || !isitem(target)) destination = get_step_towards(user, target) please_be_gentle = TRUE else destination = user - throw_callback = CALLBACK(src, PROC_REF(clear_hitby_signal), movable_target) - RegisterSignal(movable_target, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(catch_it_chucklenut)) + throw_callback = CALLBACK(src, PROC_REF(clear_hitby_signal), target) + RegisterSignal(target, COMSIG_MOVABLE_PRE_IMPACT, PROC_REF(catch_it_chucklenut)) - if(!movable_target.safe_throw_at(destination, source.cast_range, 2, callback = throw_callback, gentle = please_be_gentle)) - UnregisterSignal(movable_target, COMSIG_MOVABLE_PRE_IMPACT) + if(!target.safe_throw_at(destination, source.cast_range, 2, callback = throw_callback, gentle = please_be_gentle)) + UnregisterSignal(target, COMSIG_MOVABLE_PRE_IMPACT) else playsound(src, 'sound/items/weapons/batonextend.ogg', 50, TRUE) /obj/item/fishing_line/auto_reel/proc/catch_it_chucklenut(obj/item/source, atom/hit_atom, datum/thrownthing/throwingdatum) SIGNAL_HANDLER + var/mob/living/user = throwingdatum.initial_target.resolve() if(QDELETED(user) || hit_atom != user) return NONE From 4124f54a1518e5eaa8bb2269f0a5561bc1785474 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 21 Jan 2025 18:57:01 +0000 Subject: [PATCH 53/74] Automatic changelog for PR #89144 [ci skip] --- html/changelogs/AutoChangeLog-pr-89144.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89144.yml diff --git a/html/changelogs/AutoChangeLog-pr-89144.yml b/html/changelogs/AutoChangeLog-pr-89144.yml new file mode 100644 index 0000000000000..f0551ec98139a --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89144.yml @@ -0,0 +1,4 @@ +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 From c3f3e9e9b9939b70b7236d517b4c5b153690abf9 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Tue, 21 Jan 2025 19:06:30 +0000 Subject: [PATCH 54/74] Fix flaky Ethereal test (#89123) --- code/datums/brain_damage/split_personality.dm | 9 +++++++-- .../surgery/organs/internal/heart/heart_ethereal.dm | 2 +- code/modules/unit_tests/ethereal_revival.dm | 1 + 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/code/datums/brain_damage/split_personality.dm b/code/datums/brain_damage/split_personality.dm index cef20687a84d5..bed12417218d4 100644 --- a/code/datums/brain_damage/split_personality.dm +++ b/code/datums/brain_damage/split_personality.dm @@ -15,12 +15,17 @@ var/poll_role = "split personality" /datum/brain_trauma/severe/split_personality/on_gain() - var/mob/living/M = owner - if(M.stat == DEAD || !M.client) //No use assigning people to a corpse or braindead + var/mob/living/brain_owner = owner + if(brain_owner.stat == DEAD || !GET_CLIENT(brain_owner)) //No use assigning people to a corpse or braindead qdel(src) return ..() make_backseats() + +#ifdef UNIT_TESTS + return // There's no ghosts in the unit test +#endif + get_ghost() /datum/brain_trauma/severe/split_personality/proc/make_backseats() diff --git a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm index 48f10a0613485..9d8ae8be5ee4f 100644 --- a/code/modules/surgery/organs/internal/heart/heart_ethereal.dm +++ b/code/modules/surgery/organs/internal/heart/heart_ethereal.dm @@ -228,13 +228,13 @@ playsound(get_turf(regenerating), 'sound/mobs/humanoids/ethereal/ethereal_revive.ogg', 100) to_chat(regenerating, span_notice("You burst out of the crystal with vigour... But at a cost.")) + regenerating.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) if(prob(10)) //10% chance for a severe trauma regenerating.gain_trauma_type(BRAIN_TRAUMA_SEVERE, TRAUMA_RESILIENCE_ABSOLUTE) else regenerating.gain_trauma_type(BRAIN_TRAUMA_MILD, TRAUMA_RESILIENCE_ABSOLUTE) - regenerating.revive(HEAL_ALL & ~HEAL_REFRESH_ORGANS) // revive calls fully heal -> deletes the crystal. // this qdeleted check is just for sanity. if(!QDELETED(src)) diff --git a/code/modules/unit_tests/ethereal_revival.dm b/code/modules/unit_tests/ethereal_revival.dm index 1420f14d0b4fe..02b73281e85e3 100644 --- a/code/modules/unit_tests/ethereal_revival.dm +++ b/code/modules/unit_tests/ethereal_revival.dm @@ -5,6 +5,7 @@ var/mob/living/carbon/human/victim = allocate(/mob/living/carbon/human/consistent) var/obj/item/organ/heart/ethereal/respawn_heart = new() respawn_heart.Insert(victim, special = TRUE, movement_flags = DELETE_IF_REPLACED) // Pretend this guy is an ethereal + victim.mock_client = new() victim.death() TEST_ASSERT_NOTNULL(respawn_heart.crystalize_timer_id, "Ethereal heart didn't respond to host death.") From 8196190aa1b428184be3db117351be6ed440589b Mon Sep 17 00:00:00 2001 From: Penelope Haze Date: Tue, 21 Jan 2025 16:09:57 -0500 Subject: [PATCH 55/74] Removes a a at at be be of of and and have have (#89155) ## About The Pull Request I just had to one-up https://github.com/tgstation/tgstation/pull/89127. ## Why It's Good For The Game Removes a a at at be be of of and and have have ## Changelog N/A --- .../hud/rendering/plane_masters/plane_master_subtypes.dm | 2 +- code/datums/memory/general_memories.dm | 2 +- code/datums/ruins/icemoon.dm | 2 +- code/game/gamemodes/objective_items.dm | 2 +- code/game/machinery/computer/arcade/orion_event.dm | 2 +- code/game/objects/items.dm | 2 +- code/game/objects/items/chromosome.dm | 2 +- code/game/objects/items/robot/robot_upgrades.dm | 4 ++-- code/game/objects/items/stacks/tiles/tile_types.dm | 2 +- code/game/objects/structures/window.dm | 4 ++-- code/modules/admin/topic.dm | 2 +- code/modules/clothing/head/garlands.dm | 2 +- code/modules/clothing/neck/collar_bomb.dm | 2 +- code/modules/events/ion_storm.dm | 2 +- code/modules/library/skill_learning/job_skillchips/clown.dm | 2 +- code/modules/mapping/mapping_helpers.dm | 2 +- code/modules/mob/living/carbon/human/species_types/monkeys.dm | 2 +- code/modules/unit_tests/designs.dm | 2 +- 18 files changed, 20 insertions(+), 20 deletions(-) diff --git a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm index 582253e0b926b..96a02afb5749b 100644 --- a/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm +++ b/code/_onclick/hud/rendering/plane_masters/plane_master_subtypes.dm @@ -380,7 +380,7 @@ /atom/movable/screen/plane_master/ghost name = "Ghost" - documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not not how we HIDE ghosts from people, that's done with invisible and see_invisible." + documentation = "Ghosts draw here, so they don't get mixed up in the visuals of the game world. Note, this is not how we HIDE ghosts from people, that's done with invisible and see_invisible." plane = GHOST_PLANE render_relay_planes = list(RENDER_PLANE_NON_GAME) diff --git a/code/datums/memory/general_memories.dm b/code/datums/memory/general_memories.dm index eca745d3283a6..8fa8420527d23 100644 --- a/code/datums/memory/general_memories.dm +++ b/code/datums/memory/general_memories.dm @@ -95,7 +95,7 @@ /datum/memory/high_five/get_starts() return list( - "[protagonist_name] and [deuteragonist_name] having a a legendary [high_five_type]", + "[protagonist_name] and [deuteragonist_name] having a legendary [high_five_type]", "[protagonist_name] giving [deuteragonist_name] a [high_five_type]", "[protagonist_name] and [deuteragonist_name] giving each other a [high_five_type]", ) diff --git a/code/datums/ruins/icemoon.dm b/code/datums/ruins/icemoon.dm index ef241d61127ba..6ab7539cecd9a 100644 --- a/code/datums/ruins/icemoon.dm +++ b/code/datums/ruins/icemoon.dm @@ -64,7 +64,7 @@ /datum/map_template/ruin/icemoon/Lodge name = "Ice-Ruin Hunters Lodge" id = "lodge" - description = "An old hunting hunting lodge. I wonder if anyone is still home?" + description = "An old hunting lodge. I wonder if anyone is still home?" suffix = "icemoon_surface_lodge.dmm" /datum/map_template/ruin/icemoon/frozen_phonebooth diff --git a/code/game/gamemodes/objective_items.dm b/code/game/gamemodes/objective_items.dm index eb74dc5df1e65..7f88dc68758ce 100644 --- a/code/game/gamemodes/objective_items.dm +++ b/code/game/gamemodes/objective_items.dm @@ -561,7 +561,7 @@ exists_on_map = TRUE difficulty = 4 steal_hint = "The station's data Blackbox, found solely within Telecommunications." - destruction_method = "Too strong to be be destroyed via normal means - needs to be dusted via the supermatter, or burnt in the chapel's crematorium." + destruction_method = "Too strong to be destroyed via normal means - needs to be dusted via the supermatter, or burnt in the chapel's crematorium." /obj/item/blackbox/add_stealing_item_objective() return add_item_to_steal(src, /obj/item/blackbox) diff --git a/code/game/machinery/computer/arcade/orion_event.dm b/code/game/machinery/computer/arcade/orion_event.dm index d39766200dc52..7c834800f1dd2 100644 --- a/code/game/machinery/computer/arcade/orion_event.dm +++ b/code/game/machinery/computer/arcade/orion_event.dm @@ -219,7 +219,7 @@ var/lostfuel = rand(4,7) var/deadname = game.remove_crewmember() game.fuel -= lostfuel - text = "[deadname] was lost deep in the wreckage, and your own vessel lost [lostfuel] Fuel maneuvering to the the abandoned ship." + text = "[deadname] was lost deep in the wreckage, and your own vessel lost [lostfuel] Fuel maneuvering to the abandoned ship." event_responses += BUTTON_WHERE_DID_YOU_GO if(36 to 65) var/oldfood = rand(5,11) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b389438f0f9be..01bab10c962ed 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -1400,7 +1400,7 @@ return discover_after if(w_class > WEIGHT_CLASS_TINY) //small items like soap or toys that don't have mat datums - to_chat(victim, span_warning("[source_item? "Something strange was in the \the [source_item]..." : "I just bit something strange..."] ")) + to_chat(victim, span_warning("[source_item? "Something strange was in \the [source_item]..." : "I just bit something strange..."] ")) return discover_after // victim's chest (for cavity implanting the item) diff --git a/code/game/objects/items/chromosome.dm b/code/game/objects/items/chromosome.dm index dcfc7930ebfe2..43afbd43bd533 100644 --- a/code/game/objects/items/chromosome.dm +++ b/code/game/objects/items/chromosome.dm @@ -76,6 +76,6 @@ /obj/item/chromosome/energy name = "energetic chromosome" - desc = "A chromosome that reduces action based mutation cooldowns by by 50%." + desc = "A chromosome that reduces action based mutation cooldowns by 50%." icon_state = "energy" energy_coeff = 0.5 diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index bbebd91e7cb0c..f448ec0ed591e 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -688,7 +688,7 @@ /obj/item/borg/upgrade/transform name = "borg model picker (Standard)" - desc = "Allows you to to turn a cyborg into a standard cyborg." + desc = "Allows you to turn a cyborg into a standard cyborg." icon_state = "module_general" var/obj/item/robot_model/new_model = null @@ -699,7 +699,7 @@ /obj/item/borg/upgrade/transform/clown name = "borg model picker (Clown)" - desc = "Allows you to to turn a cyborg into a clown, honk." + desc = "Allows you to turn a cyborg into a clown, honk." icon_state = "module_honk" new_model = /obj/item/robot_model/clown diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm index 20ee0e69df6d7..f2c860d2d7644 100644 --- a/code/game/objects/items/stacks/tiles/tile_types.dm +++ b/code/game/objects/items/stacks/tiles/tile_types.dm @@ -1044,7 +1044,7 @@ /obj/item/stack/tile/tram/plate name = "linear induction tram tiles" - singular_name = "linear induction tram tile tile" + singular_name = "linear induction tram tile" desc = "A tile with an aluminium plate for tram propulsion." icon_state = "darkiron_plate" inhand_icon_state = "tile-neon" diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 9924713d93908..8c8a39aa59f26 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -860,7 +860,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/plasma/plastitanium name = "plastitanium window" - desc = "A durable looking window made of an alloy of of plasma and titanium." + desc = "A durable looking window made of an alloy of plasma and titanium." icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' icon_state = "plastitanium_window-0" base_icon_state = "plastitanium_window" @@ -883,7 +883,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/window/reinforced/tinted/frosted/spaw /obj/structure/window/reinforced/plasma/plastitanium/indestructible name = "plastitanium window" - desc = "A durable looking window made of an alloy of of plasma and titanium." + desc = "A durable looking window made of an alloy of plasma and titanium." icon = 'icons/obj/smooth_structures/plastitanium_window.dmi' icon_state = "plastitanium_window-0" base_icon_state = "plastitanium_window" diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index e8d117fdc94ff..71374bf2464ff 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -497,7 +497,7 @@ var/new_value = input(usr, "Enter the forced threat level for dynamic mode.", "Forced threat level") as num if (new_value > 100) - return tgui_alert(usr, "The value must be be under 100.") + return tgui_alert(usr, "The value must be under 100.") GLOB.dynamic_forced_threat_level = new_value log_admin("[key_name(usr)] set 'forced_threat_level' to [GLOB.dynamic_forced_threat_level].") diff --git a/code/modules/clothing/head/garlands.dm b/code/modules/clothing/head/garlands.dm index 4de0604044e32..374bd2fdafd4b 100644 --- a/code/modules/clothing/head/garlands.dm +++ b/code/modules/clothing/head/garlands.dm @@ -47,7 +47,7 @@ /obj/item/clothing/head/costume/garland/lily name = "lily crown" - desc = "A leafy flower crown with a cluster of large white lilies at at the front." + desc = "A leafy flower crown with a cluster of large white lilies at the front." icon_state = "lily_crown" worn_icon_state = "lily_crown" diff --git a/code/modules/clothing/neck/collar_bomb.dm b/code/modules/clothing/neck/collar_bomb.dm index 7a5314f4c18c6..372c6ab7cc58a 100644 --- a/code/modules/clothing/neck/collar_bomb.dm +++ b/code/modules/clothing/neck/collar_bomb.dm @@ -109,7 +109,7 @@ return var/mob/living/carbon/human/brian = collar.loc if(brian.get_item_by_slot(ITEM_SLOT_NECK) == collar) - brian.investigate_log("has has their [collar] triggered by [user] via yellow button.", INVESTIGATE_DEATHS) + brian.investigate_log("has had their [collar] triggered by [user] via yellow button.", INVESTIGATE_DEATHS) /obj/item/collar_bomb_button/Destroy() diff --git a/code/modules/events/ion_storm.dm b/code/modules/events/ion_storm.dm index 9c9d81d01d73f..1141b94e82286 100644 --- a/code/modules/events/ion_storm.dm +++ b/code/modules/events/ion_storm.dm @@ -459,7 +459,7 @@ if(6) //X is a job message = "YOU MUST HARM [ioncrew1] AND NOT ALLOW [ioncrew1], THROUGH INACTION, TO ESCAPE HARM" if(7) //X is two jobs - message = "YOU MUST HARM [ioncrew1] AND [ioncrew2] AND AND NOT ALLOW EITHER, THROUGH INACTION, TO ESCAPE HARM" + message = "YOU MUST HARM [ioncrew1] AND [ioncrew2] AND NOT ALLOW EITHER, THROUGH INACTION, TO ESCAPE HARM" if(2) //Protect switch(rand(1,7)) //What is X? diff --git a/code/modules/library/skill_learning/job_skillchips/clown.dm b/code/modules/library/skill_learning/job_skillchips/clown.dm index 3cd88ff70963d..f8836b41dcad3 100644 --- a/code/modules/library/skill_learning/job_skillchips/clown.dm +++ b/code/modules/library/skill_learning/job_skillchips/clown.dm @@ -3,7 +3,7 @@ desc = "This biochip contain several terabytes of uncannily religious, Honkmother praising guides on how to reshape balloons into silly animals." auto_traits = list(TRAIT_BALLOON_SUTRA) skill_name = "Balloon Sutra" - skill_description = "Learn the the ancient Honkmotherian arts of balloon-sutra." + skill_description = "Learn the ancient Honkmotherian arts of balloon-sutra." skill_icon = "face-grin-tears" activate_message = span_notice("Blessed wisdom of Honkmother enwraps you, and with it, governship upon form of balloonkind.") deactivate_message = span_notice("'Remember, then, that true clownery requires freedom and willingness to bend, like ones of a floating balloon.'... Whatever that meant?") diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index c122b8abc1cd7..d04e6e0afd15b 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -102,7 +102,7 @@ /obj/effect/baseturf_helper/reinforced_plating/ceiling/replace_baseturf(turf/thing) var/turf/ceiling = get_step_multiz(thing, UP) if(isnull(ceiling)) - CRASH("baseturf helper is attempting to modify the Z level above but there is no Z level above above it.") + CRASH("baseturf helper is attempting to modify the Z level above but there is no Z level above it.") if(isspaceturf(ceiling) || istype(ceiling, /turf/open/openspace)) return return ..(ceiling) diff --git a/code/modules/mob/living/carbon/human/species_types/monkeys.dm b/code/modules/mob/living/carbon/human/species_types/monkeys.dm index c953274646245..aa58299115821 100644 --- a/code/modules/mob/living/carbon/human/species_types/monkeys.dm +++ b/code/modules/mob/living/carbon/human/species_types/monkeys.dm @@ -166,7 +166,7 @@ else monkey_brain.tripping = TRUE background_icon_state = "bg_default_on" - to_chat(monkey_brain.owner, span_notice("You will now stumble while while colliding with people who are in combat mode.")) + to_chat(monkey_brain.owner, span_notice("You will now stumble while colliding with people who are in combat mode.")) build_all_button_icons() /obj/item/organ/brain/primate/on_mob_insert(mob/living/carbon/primate) diff --git a/code/modules/unit_tests/designs.dm b/code/modules/unit_tests/designs.dm index 0495ebdc7d9ae..729f2facf81d0 100644 --- a/code/modules/unit_tests/designs.dm +++ b/code/modules/unit_tests/designs.dm @@ -15,7 +15,7 @@ TEST_FAIL("Design [current_design.type] has default or null name var but has an ID") if ((!isnull(current_design.materials) && LAZYLEN(current_design.materials)) || (!isnull(current_design.reagents_list) && LAZYLEN(current_design.reagents_list))) //Design requires materials if ((isnull(current_design.build_path) || current_design.build_path == default_design.build_path) && (isnull(current_design.make_reagent) || current_design.make_reagent == default_design.make_reagent)) //Check if design gives any output - TEST_FAIL("Design [current_design.type] requires materials but does not have have any build_path or make_reagent set") + TEST_FAIL("Design [current_design.type] requires materials but does not have either build_path or make_reagent set") else if (!isnull(current_design.build_path) || !isnull(current_design.build_path)) // //Design requires no materials but creates stuff TEST_FAIL("Design [current_design.type] requires NO materials but has build_path or make_reagent set") if (length(current_design.reagents_list) && !(current_design.build_type & LIMBGROWER)) From b72368fd03e6dc58a49dd8f70f2700e393a8de8f Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Wed, 22 Jan 2025 10:17:23 +1100 Subject: [PATCH 56/74] #87754: Batons have their stamina damage reduced by armor, get stun armor penetration, but not a test and actually intended to be merged (#88830) ## About The Pull Request This PR is literally just https://github.com/tgstation/tgstation/pull/87754 so you should probably go read the contents of that PR to learn more. ### Sorry, No Stunsword in this PR. Stunbaton inhand tips change color as the cell it has inside increases in capacity. They also have different animations based on the cell, to make it clearer which one you are looking at. ![image](https://github.com/user-attachments/assets/95be1499-47b7-4991-a3c1-03833f329d7f) ## Why It's Good For The Game So, two things; A) The test showed that there is more work to be done, but that this was actually improving survivability to some degree against batons when properly geared, while not necessarily impacting the average tider arrest attempts. It didn't solve the issue of alleviating the need for anti-baton knockdown tools, but it did help a bit. Enough that I think this could be worked on further as a foundation for solving that problem. B) People have been asking me to, or have made it obvious that they would like to see this actually merged into the game. So uh...here is that PR if any maints care for it. I think there is still more to do for testing and possible changes to address the issues I was trying to investigate in the test. However, I actually think this change could be an important step towards accomplishing some of those changes. It isn't quite enough to start pulling out baton resistance from various sources just yet, but it is a start. ## Changelog :cl: 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. /:cl: --------- Co-authored-by: SmArtKar <44720187+SmArtKar@users.noreply.github.com> --- code/game/objects/items.dm | 2 + code/game/objects/items/melee/baton.dm | 129 ++++++++++++++++-- code/game/objects/items_reskin.dm | 7 + .../modules/hallucination/nearby_fake_item.dm | 2 +- code/modules/jobs/job_types/captain.dm | 2 +- code/modules/jobs/job_types/chief_engineer.dm | 2 +- .../jobs/job_types/chief_medical_officer.dm | 2 +- .../jobs/job_types/head_of_personnel.dm | 2 +- .../jobs/job_types/head_of_security.dm | 1 + code/modules/jobs/job_types/quartermaster.dm | 2 +- .../jobs/job_types/research_director.dm | 2 +- .../inhands/equipment/security_lefthand.dmi | Bin 2791 -> 9169 bytes .../inhands/equipment/security_righthand.dmi | Bin 3400 -> 10396 bytes icons/obj/weapons/baton.dmi | Bin 3005 -> 3836 bytes 14 files changed, 138 insertions(+), 15 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 01bab10c962ed..b70d105953e95 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -239,6 +239,8 @@ var/current_skin /// List of options to reskin. var/list/unique_reskin + /// If reskins change base icon state as well + var/unique_reskin_changes_base_icon_state = FALSE /// If reskins change inhands as well var/unique_reskin_changes_inhand = FALSE /// Do we apply a click cooldown when resisting this object if it is restraining them? diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 03df05140388a..1b5f9a9fd901f 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -29,6 +29,10 @@ var/clumsy_knockdown_time = 18 SECONDS /// How much stamina damage we deal on a successful hit against a living, non-cyborg mob. var/stamina_damage = 55 + /// How much armor does our baton ignore? This operates as armour penetration, but only applies to the stun attack. + var/stun_armour_penetration = 15 + /// What armor does our stun attack check before delivering the attack? + var/armour_type_against_stun = MELEE /// Chance of causing force_say() when stunning a human mob var/force_say_chance = 33 /// Can we stun cyborgs? @@ -44,6 +48,9 @@ /// Boolean on whether people with chunky fingers can use this baton. var/chunky_finger_usable = FALSE + /// What term do we use to describe our baton being 'ready', or the phrase to use when var/active is TRUE. + var/activated_word = "ready" + /// The context to show when the baton is active and targeting a living thing var/context_living_target_active = "Stun" @@ -64,12 +71,31 @@ /obj/item/melee/baton/Initialize(mapload) . = ..() - // Adding an extra break for the sake of presentation - if(stamina_damage != 0) - offensive_notes = "It takes [span_warning("[CEILING(100 / stamina_damage, 1)] stunning hit\s")] to stun an enemy." register_item_context() +/obj/item/melee/baton/add_weapon_description() + AddElement(/datum/element/weapon_description, attached_proc = PROC_REF(add_baton_notes)) + +/obj/item/melee/baton/proc/add_baton_notes() + var/list/readout = list() + + if(affect_cyborg) + readout += "It can stun cyborgs for [round((stun_time_cyborg/10), 1)] seconds." + + readout += "\n[active ? "It is currently [span_warning("[activated_word]")], and capable of stunning." : "It is [span_warning("not [activated_word]")], and not capable of stunning."]" + + if(stamina_damage <= 0) // The advanced baton actually does have 0 stamina damage so...yeah. + readout += "Either is is [span_warning("completely unable to perform a stunning strike")], or it [span_warning("attacks via some unusual method")]." + return readout.Join("\n") + + readout += "It takes [span_warning("[HITS_TO_CRIT(stamina_damage)] strike\s")] to stun an enemy." + + readout += "\nThe effects of each strike can be mitigated by utilizing [span_warning("[armour_type_against_stun]")] armor." + + readout += "\nIt has a stun armor-piercing capability of [span_warning("[get_stun_penetration_value()]%")]." + return readout.Join("\n") + /** * Ok, think of baton attacks like a melee attack chain: * @@ -210,7 +236,9 @@ var/mob/living/carbon/human/human_target = target if(prob(force_say_chance)) human_target.force_say() - target.apply_damage(stamina_damage, STAMINA) + var/effective_armour_penetration = get_stun_penetration_value() + var/armour_block = target.run_armor_check(null, armour_type_against_stun, null, null, effective_armour_penetration) + target.apply_damage(stamina_damage, STAMINA, blocked = armour_block) if(!trait_check) target.Knockdown((isnull(stun_override) ? knockdown_time : stun_override)) additional_effects_non_cyborg(target, user) @@ -295,6 +323,10 @@ user.do_attack_animation(user) return +/// Handles the penetration value of our baton, called during baton_effect() +/obj/item/melee/baton/proc/get_stun_penetration_value() + return stun_armour_penetration + /obj/item/conversion_kit name = "conversion kit" desc = "A strange box containing wood working tools and an instruction paper to turn stun batons into something else." @@ -321,6 +353,7 @@ bare_wound_bonus = 5 clumsy_knockdown_time = 15 SECONDS active = FALSE + activated_word = "extended" var/folded_drop_sound = 'sound/items/baton/telescopic_baton_folded_drop.ogg' var/folded_pickup_sound = 'sound/items/baton/telescopic_baton_folded_pickup.ogg' var/unfolded_drop_sound = 'sound/items/baton/telescopic_baton_unfolded_drop.ogg' @@ -392,6 +425,24 @@ playsound(src, on_sound, 50, TRUE) return COMPONENT_NO_DEFAULT_MESSAGE +/obj/item/melee/baton/telescopic/bronze + name = "bronze-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked BRONZE, and thus has mediocre penetrative power." + icon_state = "telebaton_bronze" + stun_armour_penetration = 20 + +/obj/item/melee/baton/telescopic/silver + name = "silver-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked SILVER, and thus has decent penetrative power." + icon_state = "telebaton_silver" + stun_armour_penetration = 40 + +/obj/item/melee/baton/telescopic/gold + name = "gold-capped telescopic baton" + desc = "A compact yet robust personal defense weapon. Can be concealed when folded. This one is ranked GOLD, and thus has exceptional penetrative power." + icon_state = "telebaton_gold" + stun_armour_penetration = 60 + /obj/item/melee/baton/telescopic/contractor_baton name = "contractor baton" desc = "A compact, specialised baton assigned to Syndicate contractors. Applies light electrical shocks to targets." @@ -408,6 +459,7 @@ cooldown = 2.5 SECONDS force_say_chance = 80 //very high force say chance because it's funny stamina_damage = 85 + stun_armour_penetration = 40 clumsy_knockdown_time = 24 SECONDS affect_cyborg = TRUE on_stun_sound = 'sound/items/weapons/contractor_baton/contractorbatonhit.ogg' @@ -432,7 +484,8 @@ desc_controls = "Left click to stun, right click to harm." icon = 'icons/obj/weapons/baton.dmi' icon_state = "stunbaton" - inhand_icon_state = "baton" + base_icon_state = "stunbaton" + inhand_icon_state = "stunbaton" worn_icon_state = "baton" icon_angle = -45 force = 10 @@ -443,12 +496,16 @@ throwforce = 7 force_say_chance = 50 stamina_damage = 60 + armour_type_against_stun = ENERGY + // This value is added to our stun armour penetration when called by get_stun_penetration_value(). For giving some batons extra OOMPH. + var/additional_stun_armour_penetration = 0 knockdown_time = 5 SECONDS clumsy_knockdown_time = 15 SECONDS cooldown = 2.5 SECONDS on_stun_sound = 'sound/items/weapons/egloves.ogg' on_stun_volume = 50 active = FALSE + activated_word = "activated" context_living_rmb_active = "Harmful Stun" light_range = 1.5 light_system = OVERLAY_LIGHT @@ -469,6 +526,10 @@ var/cell_hit_cost = STANDARD_CELL_CHARGE var/can_remove_cell = TRUE var/convertible = TRUE //if it can be converted with a conversion kit + ///Whether or not our inhand changes when active. + var/active_changes_inhand = TRUE + ///Whether or not our baton visibly changes the inhand sprite based on inserted cell + var/tip_changes_color = TRUE /datum/armor/baton_security bomb = 50 @@ -534,12 +595,19 @@ /obj/item/melee/baton/security/update_icon_state() if(active) - icon_state = "[initial(icon_state)]_active" + icon_state = "[base_icon_state]_active" + if(active_changes_inhand) + if(tip_changes_color) + inhand_icon_state = "[base_icon_state]_active_[get_baton_tip_color()]" + else + inhand_icon_state = "[base_icon_state]_active" return ..() if(!cell) - icon_state = "[initial(icon_state)]_nocell" + icon_state = "[base_icon_state]_nocell" + inhand_icon_state = "[base_icon_state]" return ..() - icon_state = "[initial(icon_state)]" + icon_state = "[base_icon_state]" + inhand_icon_state = "[base_icon_state]" return ..() /obj/item/melee/baton/security/examine(mob/user) @@ -594,9 +662,36 @@ /// Toggles the stun baton's light /obj/item/melee/baton/security/proc/toggle_light() + set_light_color(get_baton_tip_color(TRUE)) set_light_on(!light_on) return +/// Change our baton's top color based on the contained cell. +/obj/item/melee/baton/security/proc/get_baton_tip_color(set_light = FALSE) + var/tip_type_to_set + var/tip_light_to_set + + if(cell) + var/chargepower = cell.maxcharge + var/zap_value = clamp(chargepower/STANDARD_CELL_CHARGE, 0, 100) + switch(zap_value) + if(-INFINITY to 10) + tip_type_to_set = "orange" + tip_light_to_set = LIGHT_COLOR_ORANGE + if(11 to 20) + tip_type_to_set = "red" + tip_light_to_set = LIGHT_COLOR_INTENSE_RED + if(21 to 30) + tip_type_to_set = "green" + tip_light_to_set = LIGHT_COLOR_GREEN + if(31 to INFINITY) + tip_type_to_set = "blue" + tip_light_to_set = LIGHT_COLOR_BLUE + else + tip_type_to_set = "orange" + + return set_light ? tip_light_to_set : tip_type_to_set + /obj/item/melee/baton/security/proc/turn_on(mob/user) active = TRUE playsound(src, SFX_SPARKS, 75, TRUE, -1) @@ -653,6 +748,13 @@ stun_override = 0 //Avoids knocking people down prematurely. return ..() +/obj/item/melee/baton/security/get_stun_penetration_value() + if(cell) + var/chargepower = cell.maxcharge + var/zap_pen = clamp(chargepower/STANDARD_CELL_CHARGE, 0, 100) + return zap_pen + additional_stun_armour_penetration + return stun_armour_penetration + additional_stun_armour_penetration + /* * After a target is hit, we apply some status effects. * After a period of time, we then check to see what stun duration we give. @@ -719,6 +821,9 @@ /obj/item/melee/baton/security/loaded //this one starts with a cell pre-installed. preload_cell_type = /obj/item/stock_parts/power_store/cell/high +/obj/item/melee/baton/security/loaded/hos + preload_cell_type = /obj/item/stock_parts/power_store/cell/super + //Makeshift stun baton. Replacement for stun gloves. /obj/item/melee/baton/security/cattleprod name = "stunprod" @@ -726,6 +831,7 @@ desc_controls = "Left click to stun, right click to harm." icon = 'icons/obj/weapons/spear.dmi' icon_state = "stunprod" + base_icon_state = "stunprod" inhand_icon_state = "prod" worn_icon_state = null icon_angle = -45 @@ -738,6 +844,8 @@ throw_stun_chance = 10 slot_flags = ITEM_SLOT_BACK convertible = FALSE + active_changes_inhand = FALSE + tip_changes_color = FALSE var/obj/item/assembly/igniter/sparkler ///Determines whether or not we can improve the cattleprod into a new type. Prevents turning the cattleprod subtypes into different subtypes, or wasting materials on making it....another version of itself. var/can_upgrade = TRUE @@ -794,6 +902,7 @@ throw_speed = 1 icon = 'icons/obj/weapons/thrown.dmi' icon_state = "boomerang" + base_icon_state = "boomerang" inhand_icon_state = "boomerang" force = 5 throwforce = 5 @@ -801,6 +910,8 @@ cell_hit_cost = STANDARD_CELL_CHARGE * 2 throw_stun_chance = 99 //Have you prayed today? convertible = FALSE + active_changes_inhand = FALSE + tip_changes_color = FALSE custom_materials = list(/datum/material/iron = SHEET_MATERIAL_AMOUNT * 5, /datum/material/glass = SHEET_MATERIAL_AMOUNT*2, /datum/material/silver = SHEET_MATERIAL_AMOUNT*5, /datum/material/gold = SHEET_MATERIAL_AMOUNT) /obj/item/melee/baton/security/boomerang/Initialize(mapload) @@ -823,6 +934,7 @@ desc = "A prod with a bluespace crystal on the end. The crystal doesn't look too fun to touch." w_class = WEIGHT_CLASS_NORMAL icon_state = "teleprod" + base_icon_state = "teleprod" inhand_icon_state = "teleprod" slot_flags = null can_upgrade = FALSE @@ -844,6 +956,7 @@ desc = "A prod with a telecrystal on the end. It sparks with a desire for theft and subversion." w_class = WEIGHT_CLASS_NORMAL icon_state = "telecrystalprod" + base_icon_state = "telecrystalprod" inhand_icon_state = "telecrystalprod" slot_flags = null throw_stun_chance = 50 //I think it'd be funny diff --git a/code/game/objects/items_reskin.dm b/code/game/objects/items_reskin.dm index b73df0a487b72..98a3165b5e2ab 100644 --- a/code/game/objects/items_reskin.dm +++ b/code/game/objects/items_reskin.dm @@ -64,8 +64,15 @@ return current_skin = pick icon_state = unique_reskin[pick] + + if (unique_reskin_changes_base_icon_state) + base_icon_state = icon_state + if (unique_reskin_changes_inhand) inhand_icon_state = icon_state + + update_appearance() + to_chat(user, "[src] is now skinned as '[pick].'") SEND_SIGNAL(src, COMSIG_OBJ_RESKIN, user, pick) diff --git a/code/modules/hallucination/nearby_fake_item.dm b/code/modules/hallucination/nearby_fake_item.dm index 10d08ee47c96f..1896d28d34042 100644 --- a/code/modules/hallucination/nearby_fake_item.dm +++ b/code/modules/hallucination/nearby_fake_item.dm @@ -89,7 +89,7 @@ /datum/hallucination/nearby_fake_item/baton left_hand_file = 'icons/mob/inhands/equipment/security_lefthand.dmi' right_hand_file = 'icons/mob/inhands/equipment/security_righthand.dmi' - image_icon_state = "baton" + image_icon_state = "stunbaton" /datum/hallucination/nearby_fake_item/baton/generate_fake_image(mob/living/carbon/human/holder, file) hallucinator.playsound_local(get_turf(holder), SFX_SPARKS, 75, TRUE, -1) diff --git a/code/modules/jobs/job_types/captain.dm b/code/modules/jobs/job_types/captain.dm index 35155a7c7b70d..fff1c5ed170b4 100644 --- a/code/modules/jobs/job_types/captain.dm +++ b/code/modules/jobs/job_types/captain.dm @@ -67,7 +67,7 @@ uniform = /obj/item/clothing/under/rank/captain suit = /obj/item/clothing/suit/armor/vest/capcarapace backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/gold = 1, /obj/item/station_charter = 1, ) belt = /obj/item/modular_computer/pda/heads/captain diff --git a/code/modules/jobs/job_types/chief_engineer.dm b/code/modules/jobs/job_types/chief_engineer.dm index f85c2c54973b9..3a9a9fbc397b6 100644 --- a/code/modules/jobs/job_types/chief_engineer.dm +++ b/code/modules/jobs/job_types/chief_engineer.dm @@ -67,7 +67,7 @@ id_trim = /datum/id_trim/job/chief_engineer uniform = /obj/item/clothing/under/rank/engineering/chief_engineer backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, /obj/item/construction/rcd/ce = 1, ) belt = /obj/item/storage/belt/utility/chief/full diff --git a/code/modules/jobs/job_types/chief_medical_officer.dm b/code/modules/jobs/job_types/chief_medical_officer.dm index c9f126bb750bc..13a9eb97515f1 100644 --- a/code/modules/jobs/job_types/chief_medical_officer.dm +++ b/code/modules/jobs/job_types/chief_medical_officer.dm @@ -62,7 +62,7 @@ suit = /obj/item/clothing/suit/toggle/labcoat/cmo suit_store = /obj/item/flashlight/pen/paramedic backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/cmo ears = /obj/item/radio/headset/heads/cmo diff --git a/code/modules/jobs/job_types/head_of_personnel.dm b/code/modules/jobs/job_types/head_of_personnel.dm index 1b8480f0d0b57..ed35cbf365f56 100644 --- a/code/modules/jobs/job_types/head_of_personnel.dm +++ b/code/modules/jobs/job_types/head_of_personnel.dm @@ -59,7 +59,7 @@ id_trim = /datum/id_trim/job/head_of_personnel uniform = /obj/item/clothing/under/rank/civilian/head_of_personnel backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/hop ears = /obj/item/radio/headset/heads/hop diff --git a/code/modules/jobs/job_types/head_of_security.dm b/code/modules/jobs/job_types/head_of_security.dm index b9560708114be..431e0aaaf6b44 100644 --- a/code/modules/jobs/job_types/head_of_security.dm +++ b/code/modules/jobs/job_types/head_of_security.dm @@ -57,6 +57,7 @@ suit_store = /obj/item/gun/energy/e_gun backpack_contents = list( /obj/item/evidencebag = 1, + /obj/item/melee/baton/security/loaded/hos = 1, ) belt = /obj/item/modular_computer/pda/heads/hos ears = /obj/item/radio/headset/heads/hos/alt diff --git a/code/modules/jobs/job_types/quartermaster.dm b/code/modules/jobs/job_types/quartermaster.dm index 32053daa5d8c8..251032662bf53 100644 --- a/code/modules/jobs/job_types/quartermaster.dm +++ b/code/modules/jobs/job_types/quartermaster.dm @@ -42,7 +42,7 @@ name = "Quartermaster" jobtype = /datum/job/quartermaster backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/bronze = 1, ) id_trim = /datum/id_trim/job/quartermaster id = /obj/item/card/id/advanced/silver diff --git a/code/modules/jobs/job_types/research_director.dm b/code/modules/jobs/job_types/research_director.dm index 420138a6b9fba..cfd5044c267b0 100644 --- a/code/modules/jobs/job_types/research_director.dm +++ b/code/modules/jobs/job_types/research_director.dm @@ -62,7 +62,7 @@ uniform = /obj/item/clothing/under/rank/rnd/research_director/turtleneck suit = /obj/item/clothing/suit/toggle/labcoat/research_director backpack_contents = list( - /obj/item/melee/baton/telescopic = 1, + /obj/item/melee/baton/telescopic/silver = 1, ) belt = /obj/item/modular_computer/pda/heads/rd head = /obj/item/clothing/head/beret/science/rd diff --git a/icons/mob/inhands/equipment/security_lefthand.dmi b/icons/mob/inhands/equipment/security_lefthand.dmi index 993834e0d60847e855e3b2e76ac05a3b43703d6f..91306c0a093c1602b8ad0e17f4622bc6fb37e397 100644 GIT binary patch literal 9169 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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 zcmcInc|6o>7yrqU>~1f~a+5^aFD92VLyaVtQHdl=mo$S=$v#61S(2R^Yu1FBG!2TG z(Q7TsSYjB=*c!qZOqQ{Xcii{=_kQksKcDyg=RD{8ob!1;&vVY_e9w8}>})N?MdU>Q z01&sj0KE(Vd^{Bx7Z&2l1@k&P-qIXqe=QJt>%PZ5L_i?I-wyynauR!OL>}u&36A59 zTMFhgxpiHoCt9Li%?oYOJuja8R{3MiCD0kIwI56i*OM8gh8vmn2QNfFe2;5<1`_>?_pk4bv0xv5l|N&nL%szf6@$kPuMxc4$|2P#q889&JO2o?>vUhAb~@ z+{_A1(?6gtoon-ESXjk0DHI)W%H(&<>1nZ{V#VN$w7K4JvFXPl>e?7E;obvs;QaJx z`~=xY1O8M9P4qaTSd1AT6?&ot0Adg;sJVSe4s*;6e&d#W+w#ooyQMmVz9*mDQM)8m zrdQc-ukc$V?bF?fCj5ka5mE z7?zZc&dVI`$RZ4Ur718$_kJxQa>?KTc!rg5(R5}s zrfqz@AnlQGZwtox{h{m_8?Of7U0`TqLu#AY{%l!N-E|;tPbHvWhjvor; zDiZw&o~H+1_u`x&Rx%}D9@<8lXZcffK!?VhXgadbkgwI)H`EtOg z)baOg@!?ib=I9+`q;I#g>5=fMaGSRtT|jL9gqoUK;U~&z&jwPLn`5>fjjr|>8{FR9 z3{_oWo1{*M`=cr8G5q@_1n!E?R*>!1JdP>2^4V7mC?A?D@~4NV4Qfd!{yN^;+FDo% znMJO?Y(+KWQ!&GR+Kru^zomi(I13cVD#P1SkfAo7&-JRz&r+`ky!}G+(fA0~QwCLK zM&B6bd7;YT{?yb|`50?)v)CM@d-?F(6`3cL+nHs;w4&icU z##SIW6ns6Kfr5XvMY<~vL(Up=kgGhb>XJ}K<^o^K#%csVW3fO-`{|5OMnf! zTcpoqnt4R!eH^H=bKm!RnCCLz`ltH*cri;3YFylM@o_L@!1U88r>0J=lM9r{N;b!&Si5QY5T6JIByx8Do-8cq=DFBO@bUlDmE_lc$ zHcd*fQc6B{M0U^hj`~l%rRSw#zIzDGqqIVTgKM+V=r7yI{_7DxSUyR8FIwE@Qnt3) zE&1m{U6fISKRBIOrz_z?^F&E^Z*Psc#YKsg%X%<%(ghRTucHCIgP2F;)VLw))%KRp zx`hyaqMX3clVnuWTXZJBa{9=_22(aa`Z`K8K)9AaXS;E1LY9{ilGy*V#`f3{{|}(# z^2ygMNp`P4JpA3^S5+CDTE8aXM8-u-QBjknZru0TS-T_2N%CENAw9qB{_r;Je_iVb zq+dKvq0#aJZFH$4BLn-Vi_U8$9!%kpd750m+sHmRdSPb)yNnvN&xXaywQVN|sst#VdFWU(@4T|WBY|(CfX`r5kl6bJ8l3*3Vq~c2=U5S`VN-V5- zLrQuz%?&!;-kuy0!VotOoVAetOx~7M3cCb8!;Vord|0F~hRmT$0|o{Lz1_J44RvdD zcaHJN)4^+Rz%SA;Dd(k*n1(G4XiJ)E>PkY2T)tFfJb`GkyKd+m7!>p|I$G0@MI*T0zUwhjF3^v3|cM>%S~SMG}R<3$-&oFjp)$b%~cQc zGeh(Za{4wSoAs4+;drsB6Rg7#;Bk_<)}Ukls|Cx;YU)iJ@d5eBn0M;)h?78TTboOj zL&7_5!TP{$`7LS6mrXIL7Y-!oQim=nu-lk3od(nAl%(8syPHpaO5Rx_)G(%?)w9oi z>3N?&7#*>!@efvyw^(&OM@?IOo=H?#S{TOd#r0E!c}Wlnv1kd$nbqI}MVFSEBz@LX zPW-`(JzfueNA!TRA9j-vd-V6@l&GhhbuF;WPd*2U>sd7F+7Z4Z+g_8o4=@8S+nW8) z!aFD)<&B?%LN!>WpVn!`pvPf^#k`2QxB|xR^c7fL7y(1WkqNzTaE!8j zjulspe)&cEYQ@#{@yC)EtFNWAXUMm?Q?Iu+H%Gg&jlQ)ViA=BCjf;zeZmkiFx_tWH z^jErK>ysedYg8(A+A(S8ax0fh?j-LvvexP~={t^obfPvtKYt(G&^~PKgVBKZ0Ac{~ zUDln~D69tUXK-$A_&&7x-Hsi7ef`vn%y5vtzDkSsdIe<}Z-jpE^U$o@#@zbBm5kUk zM4J-SB!;`(5D|72y1DAZ*_&jpV|w9G7GC=U-w1D3=cbD@evD&WDrPn zqJ{K=<%%5Wf79O=%OvMqjd!crgPMUqTs_aysDC3sDy`S zQ#=4qKeVeza9J8lK!<2AQ-3PsSwuWMzkG3y`rHCZsvTSTk0rHKMlV#%!?Ocj3xtOC zAg~si?kjSw?XoEG7XUNr^A)*c&JIMOfKL{bvdFOW9iI~HmgO-pdTOg+8yzW_>9i{1 z9x6QjkntINST9u6!;}2SK{a1p6TBLywV$PE&l81`pGqxN3o+$GU+}++!wMNZPZGdY zeWUMdUN7MF%YpD?>P;yMN*W(~UrqLr!|u?O7PB4>jtZR(GuL+DSZpylIa6Uy18(tY_XhoPH zi-RP&tmsuWnSBCLcN&D==1sJNNcFm+>XE6!z=$v~#gieLdVe;X?;J_~aMJNoKw%i~ 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 57/74] 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 58/74] 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 59/74] 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 60/74] 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 61/74] 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 62/74] 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 63/74] 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 64/74] 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 65/74] 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 66/74] 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 67/74] 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 68/74] 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 69/74] 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 70/74] 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 71/74] 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 72/74] 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 73/74] 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 74/74] 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