From 333c8a8ed10670340f88e0d810a5ed05c772b97e Mon Sep 17 00:00:00 2001 From: siliconOpossum <138069572+siliconOpossum@users.noreply.github.com> Date: Sun, 2 Feb 2025 10:08:17 -0600 Subject: [PATCH 001/104] Fix unscrollable lathe UI on 516 (#89312) ## About The Pull Request The UI for lathes is broken in 516 ATM, the scrollbar doesn't scroll below the lowest visible item, and the materials under the items aren't visible either. I tested this on 515 as well and it didn't seem to break anything or change behavior that I could tell. ## Why It's Good For The Game It's good when things work ![image](https://github.com/user-attachments/assets/220170e2-f579-4373-9e0b-498ce8188c10) ## Changelog :cl: fix: Lathes interfaces are no longer unscrollable on 516 /:cl: --- tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx b/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx index 82c4fe7dfe755..d42b929cc725d 100644 --- a/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx +++ b/tgui/packages/tgui/interfaces/Fabrication/DesignBrowser.tsx @@ -276,7 +276,7 @@ export const DesignBrowser = ( -
+
{searchText.length > 0 ? ( {sortBy( From 0e46471aec7861fcf7df3fbdc6d51d9c887a447a Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 2 Feb 2025 16:08:37 +0000 Subject: [PATCH 002/104] Automatic changelog for PR #89312 [ci skip] --- html/changelogs/AutoChangeLog-pr-89312.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89312.yml diff --git a/html/changelogs/AutoChangeLog-pr-89312.yml b/html/changelogs/AutoChangeLog-pr-89312.yml new file mode 100644 index 0000000000000..cd52ff8cf07cd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89312.yml @@ -0,0 +1,4 @@ +author: "siliconOpossum" +delete-after: True +changes: + - bugfix: "Lathes interfaces are no longer unscrollable on 516" \ No newline at end of file From e725c98a2721645693f931f0f8155e9b128fbc7c Mon Sep 17 00:00:00 2001 From: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com> Date: Sun, 2 Feb 2025 11:09:46 -0500 Subject: [PATCH 003/104] Fix the "Debug Controller" verb (#89301) ## About The Pull Request The "Debug Controller" verb wasn't doing anything. You'd click on it, and nothing would happen. Turns out, it was searching for controllers in the wrong place - controllers are considered globals, not part of `/world`. This PR fixes that. Now you get this fancy box instead of nothing: ![image](https://github.com/user-attachments/assets/af4d76d2-0ad4-4549-8606-8b423762c700) (As an aside - choosing the Global Variables controller causes several seconds of lag, due to the mass amount of data that needs to be rendered. Perhaps a new verb should be added specifically for going through Global Variables?) ## Why It's Good For The Game Enables coders to debug the various controllers with less need for debug printing statements. ## Why It's Terrible For The Game Enables admins with debug permission to abuse the live server even harder. ## Changelog No player-facing changes. This regards a verb that should only be used during debugging (i.e. locally). --- code/controllers/admin.dm | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/code/controllers/admin.dm b/code/controllers/admin.dm index 5056e3804ef11..d96b362847c51 100644 --- a/code/controllers/admin.dm +++ b/code/controllers/admin.dm @@ -59,11 +59,12 @@ ADMIN_VERB(debug_controller, R_DEBUG, "Debug Controller", "Debug the various per var/list/controllers = list() var/list/controller_choices = list() - for (var/datum/controller/controller in world) - if (istype(controller, /datum/controller/subsystem)) + for (var/var_key in global.vars) + var/datum/controller/controller = global.vars[var_key] + if(!istype(controller) || istype(controller, /datum/controller/subsystem)) continue - controllers["[controller] (controller.type)"] = controller //we use an associated list to ensure clients can't hold references to controllers - controller_choices += "[controller] (controller.type)" + controllers[controller.name] = controller //we use an associated list to ensure clients can't hold references to controllers + controller_choices += controller.name var/datum/controller/controller_string = input("Select controller to debug", "Debug Controller") as null|anything in controller_choices var/datum/controller/controller = controllers[controller_string] From 10a3bbf57860237da444931be9a2bf165ab9b45b Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Sun, 2 Feb 2025 08:10:18 -0800 Subject: [PATCH 004/104] Fixes dropdown names in prefs [No gbp] (#89283) ## About The Pull Request Troubleshooting an issue with @vinylspiders revealed this component wasn't working properly for us either. displayNames doesn't like being assigned in a useEffect so it never really has a value. I've fixed it, it's working, it's also more idiomatic react ## Why It's Good For The Game This should fix prefs showing up as "male" "female" instead of being properly converted via display names ## Changelog :cl: fix: Character pref dropdowns should have their display names fixed /:cl: --- .../preferences/features/dropdowns.tsx | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx index 08c082c4bc5df..368afb2f7b124 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/dropdowns.tsx @@ -30,19 +30,16 @@ export function FeatureDropdownInput(props: DropdownInputProps) { const [dropdownOptions, setDropdownOptions] = useState([]); - let displayNames: Record = {}; - function populateOptions() { if (!serverData) return; const { choices = [] } = serverData; - displayNames = serverData.display_names as Record; let newOptions: DropdownOptions = []; for (const choice of choices) { - let displayText: ReactNode = displayNames - ? displayNames[choice] + let displayText: ReactNode = serverData.display_names + ? serverData.display_names[choice] : capitalizeFirst(choice); newOptions.push({ @@ -60,10 +57,7 @@ export function FeatureDropdownInput(props: DropdownInputProps) { } }, [serverData]); - let displayText = value; - if (displayNames) { - displayText = displayNames[value]; - } + const displayText = serverData?.display_names?.[value] || String(value); return ( = {}; - const [dropdownOptions, setDropdownOptions] = useState([]); function populateOptions() { if (!serverData) return; const { icons = {}, choices = [] } = serverData; - displayNames = serverData.display_names as Record; let newOptions: DropdownOptions = []; for (const choice of choices) { - let displayText: ReactNode = displayNames - ? displayNames[choice] + let displayText: ReactNode = serverData.display_names?.[choice] + ? serverData.display_names?.[choice] : capitalizeFirst(choice); if (serverData.icons?.[choice]) { @@ -127,10 +117,7 @@ export function FeatureIconnedDropdownInput(props: IconnedDropdownInputProps) { } }, [serverData]); - let displayText = capitalizeFirst(value || ''); - if (displayNames) { - displayText = displayNames[value]; - } + const displayText = serverData?.display_names?.[value] || String(value); return ( Date: Sun, 2 Feb 2025 16:10:38 +0000 Subject: [PATCH 005/104] Automatic changelog for PR #89283 [ci skip] --- html/changelogs/AutoChangeLog-pr-89283.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89283.yml diff --git a/html/changelogs/AutoChangeLog-pr-89283.yml b/html/changelogs/AutoChangeLog-pr-89283.yml new file mode 100644 index 0000000000000..30d5a8d1d42c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89283.yml @@ -0,0 +1,4 @@ +author: "jlsnow301" +delete-after: True +changes: + - bugfix: "Character pref dropdowns should have their display names fixed" \ No newline at end of file From a13470f260af583b53549a3eedb3a4fc25c021c4 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Sun, 2 Feb 2025 17:10:49 +0100 Subject: [PATCH 006/104] Fixes persisting brimbeams (#89318) ## About The Pull Request If a brimdemon gets destroyed instantly, their beams would persist because of a runtime here as owner in actions can be null. Fixes https://github.com/tgstation/tgstation/issues/81994 ## Changelog :cl: fix: Fixed an issue with persisting brimbeams /:cl: --- code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm index 5900289cae569..2daef4e1ae9aa 100644 --- a/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm +++ b/code/modules/mob/living/basic/lavaland/brimdemon/brimbeam.dm @@ -86,7 +86,8 @@ /datum/action/cooldown/mob_cooldown/brimbeam/proc/extinguish_laser() if(!length(beam_parts)) return FALSE - owner.move_resist = initial(owner.move_resist) + if (owner) + owner.move_resist = initial(owner.move_resist) for(var/obj/effect/brimbeam/beam in beam_parts) beam.disperse() beam_parts = list() From c991aef6b2a3b2b841c37de5af9e9e00df81af85 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 2 Feb 2025 16:11:11 +0000 Subject: [PATCH 007/104] Automatic changelog for PR #89318 [ci skip] --- html/changelogs/AutoChangeLog-pr-89318.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89318.yml diff --git a/html/changelogs/AutoChangeLog-pr-89318.yml b/html/changelogs/AutoChangeLog-pr-89318.yml new file mode 100644 index 0000000000000..cada27af96d98 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89318.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed an issue with persisting brimbeams" \ No newline at end of file From 845ab5c5f3bbe4a3fc5dcaa5a392688b9ef88975 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Mon, 3 Feb 2025 08:02:43 +1100 Subject: [PATCH 008/104] Increases the base force of standard toolboxes by exactly one. (#89302) --- code/game/objects/items/storage/toolbox.dm | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index b3fac29554de6..f23198efd4c9d 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -7,8 +7,8 @@ lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi' righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi' obj_flags = CONDUCTS_ELECTRICITY - force = 12 - throwforce = 12 + force = 13 + throwforce = 13 throw_speed = 2 throw_range = 7 demolition_mod = 1.25 @@ -203,8 +203,8 @@ var/power = 0 for (var/obj/item/stack/telecrystal/stored_crystals in get_all_contents()) power += (stored_crystals.amount / 2) - force = 19 + power - throwforce = 22 + power + force = initial(force) + power + throwforce = initial(throwforce) + power /obj/item/storage/toolbox/mechanical/old/clean/attack(mob/target, mob/living/user) calc_damage() From e90d8c7c3e6977f70af1e876a8d34c16b89408b3 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 2 Feb 2025 21:03:03 +0000 Subject: [PATCH 009/104] Automatic changelog for PR #89302 [ci skip] --- html/changelogs/AutoChangeLog-pr-89302.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89302.yml diff --git a/html/changelogs/AutoChangeLog-pr-89302.yml b/html/changelogs/AutoChangeLog-pr-89302.yml new file mode 100644 index 0000000000000..77d3b162960a3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89302.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - balance: "The force of most standard varieties of toolboxes has increased from 12 to 13 force." + - code_imp: "Removed some magic numbers from the calculations for ancient toolboxes damage scaling." \ No newline at end of file From 8e14c5472e315f4139ae78e4ce1892d9033951bc Mon Sep 17 00:00:00 2001 From: Lucy Date: Sun, 2 Feb 2025 16:44:13 -0500 Subject: [PATCH 010/104] Fix the chat reliability subsystem (#89316) --- tgui/packages/tgui-panel/chat/middleware.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tgui/packages/tgui-panel/chat/middleware.js b/tgui/packages/tgui-panel/chat/middleware.js index 83fc28dc86a99..f221f3a7c53f6 100644 --- a/tgui/packages/tgui-panel/chat/middleware.js +++ b/tgui/packages/tgui-panel/chat/middleware.js @@ -135,13 +135,14 @@ export const chatMiddleware = (store) => { requesting < sequence; requesting++ ) { - requested_sequences.push(requesting); + sequences_requested.push(requesting); Byond.sendMessage('chat/resend', requesting); } } } chatRenderer.processBatch([payload_obj.content]); + sequences.push(sequence); return; } if (type === loadChat.type) { From 4e99e5f2fca7342c56326c45a7e2af49cd3aa09d Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Sun, 2 Feb 2025 21:44:32 +0000 Subject: [PATCH 011/104] Automatic changelog for PR #89316 [ci skip] --- html/changelogs/AutoChangeLog-pr-89316.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89316.yml diff --git a/html/changelogs/AutoChangeLog-pr-89316.yml b/html/changelogs/AutoChangeLog-pr-89316.yml new file mode 100644 index 0000000000000..8a418cbf0e4fa --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89316.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Random messages should no longer be dropped and not appear in chat." \ No newline at end of file From 74e63cdff19f9fe3df9b643cf2339a97b9d69347 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 00:26:42 +0000 Subject: [PATCH 012/104] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89283.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89302.yml | 5 ----- html/changelogs/AutoChangeLog-pr-89312.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89316.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89318.yml | 4 ---- html/changelogs/archive/2025-02.yml | 14 ++++++++++++++ 6 files changed, 14 insertions(+), 21 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89283.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89302.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89312.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89316.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89318.yml diff --git a/html/changelogs/AutoChangeLog-pr-89283.yml b/html/changelogs/AutoChangeLog-pr-89283.yml deleted file mode 100644 index 30d5a8d1d42c4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89283.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "jlsnow301" -delete-after: True -changes: - - bugfix: "Character pref dropdowns should have their display names fixed" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89302.yml b/html/changelogs/AutoChangeLog-pr-89302.yml deleted file mode 100644 index 77d3b162960a3..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89302.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - balance: "The force of most standard varieties of toolboxes has increased from 12 to 13 force." - - code_imp: "Removed some magic numbers from the calculations for ancient toolboxes damage scaling." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89312.yml b/html/changelogs/AutoChangeLog-pr-89312.yml deleted file mode 100644 index cd52ff8cf07cd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89312.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "siliconOpossum" -delete-after: True -changes: - - bugfix: "Lathes interfaces are no longer unscrollable on 516" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89316.yml b/html/changelogs/AutoChangeLog-pr-89316.yml deleted file mode 100644 index 8a418cbf0e4fa..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89316.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "Random messages should no longer be dropped and not appear in chat." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89318.yml b/html/changelogs/AutoChangeLog-pr-89318.yml deleted file mode 100644 index cada27af96d98..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89318.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed an issue with persisting brimbeams" \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index b8f62a6d620be..99f19638c2aa6 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -34,3 +34,17 @@ in the ruin, however. zoomachina: - bugfix: showers wash things under them when they're turned on again +2025-02-03: + Absolucy: + - bugfix: Random messages should no longer be dropped and not appear in chat. + SmArtKar: + - bugfix: Fixed an issue with persisting brimbeams + jlsnow301: + - bugfix: Character pref dropdowns should have their display names fixed + necromanceranne: + - balance: The force of most standard varieties of toolboxes has increased from + 12 to 13 force. + - code_imp: Removed some magic numbers from the calculations for ancient toolboxes + damage scaling. + siliconOpossum: + - bugfix: Lathes interfaces are no longer unscrollable on 516 From 3f46e2f0d07854bc3dd6ce3aa4f9c98df04cc27c Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Mon, 3 Feb 2025 12:47:59 +1100 Subject: [PATCH 013/104] Fixes MOD holster having required slots which prevent it from working without basically fully deploying anyway (#89239) ## About The Pull Request Originally, this module could be activated while the core was inactive. Now, it doesn't because it needs you to deploy the vast majority of your modsuit even while inactive. Kind of lame. This corrects that so you can still deploy your firearm without the suit being more or less deployed. ## Why It's Good For The Game Looks like a copy-paste job to me. Or not understanding what this module was. Hard to say. ## Changelog :cl: fix: Allows MOD holsters to once again activate while the modsuit is inactive and undeployed. /:cl: --- code/modules/mod/modules/modules_security.dm | 1 - 1 file changed, 1 deletion(-) diff --git a/code/modules/mod/modules/modules_security.dm b/code/modules/mod/modules/modules_security.dm index f4bad41dd02c2..06bd9352a9c2c 100644 --- a/code/modules/mod/modules/modules_security.dm +++ b/code/modules/mod/modules/modules_security.dm @@ -112,7 +112,6 @@ incompatible_modules = list(/obj/item/mod/module/holster) cooldown_time = 0.5 SECONDS allow_flags = MODULE_ALLOW_INACTIVE - required_slots = list(ITEM_SLOT_OCLOTHING|ITEM_SLOT_GLOVES|ITEM_SLOT_FEET) /// Gun we have holstered. var/obj/item/gun/holstered From bef168fe1cbc2da5fab50e95508680e4be36ca78 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Mon, 3 Feb 2025 01:48:19 +0000 Subject: [PATCH 014/104] Automatic changelog for PR #89239 [ci skip] --- html/changelogs/AutoChangeLog-pr-89239.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89239.yml diff --git a/html/changelogs/AutoChangeLog-pr-89239.yml b/html/changelogs/AutoChangeLog-pr-89239.yml new file mode 100644 index 0000000000000..dbf79c0fdf2b3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89239.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "Allows MOD holsters to once again activate while the modsuit is inactive and undeployed." \ No newline at end of file From 3a36656ae8a67249934d7237f2cd796df86ce629 Mon Sep 17 00:00:00 2001 From: 1393F <59183821+1393F@users.noreply.github.com> Date: Sun, 2 Feb 2025 20:48:42 -0500 Subject: [PATCH 015/104] Adds trailing comma to lists/canisters.dm and removes single letter vars from cargo/exports/large_objects.dm (#89273) ## About The Pull Request title ## Why It's Good For The Game slightly better code quality? ## Changelog not player facing --- code/_globalvars/lists/canisters.dm | 2 +- code/modules/cargo/exports/large_objects.dm | 41 ++++++++++----------- 2 files changed, 20 insertions(+), 23 deletions(-) diff --git a/code/_globalvars/lists/canisters.dm b/code/_globalvars/lists/canisters.dm index f8ec95f602051..746a8456d71c3 100644 --- a/code/_globalvars/lists/canisters.dm +++ b/code/_globalvars/lists/canisters.dm @@ -25,5 +25,5 @@ GLOBAL_LIST_INIT(gas_id_to_canister, init_gas_id_to_canister()) GAS_ZAUKER = /obj/machinery/portable_atmospherics/canister/zauker, GAS_HELIUM = /obj/machinery/portable_atmospherics/canister/helium, GAS_ANTINOBLIUM = /obj/machinery/portable_atmospherics/canister/antinoblium, - GAS_HALON = /obj/machinery/portable_atmospherics/canister/halon + GAS_HALON = /obj/machinery/portable_atmospherics/canister/halon, )) diff --git a/code/modules/cargo/exports/large_objects.dm b/code/modules/cargo/exports/large_objects.dm index 1871d69eb452e..ed65563b02ca3 100644 --- a/code/modules/cargo/exports/large_objects.dm +++ b/code/modules/cargo/exports/large_objects.dm @@ -40,9 +40,8 @@ cost = CARGO_CRATE_VALUE * 0.5 // +0-400 depending on amount of reagents left var/contents_cost = CARGO_CRATE_VALUE * 0.8 -/datum/export/large/reagent_dispenser/get_cost(obj/O) - var/obj/structure/reagent_dispensers/D = O - var/ratio = D.reagents.total_volume / D.reagents.maximum_volume +/datum/export/large/reagent_dispenser/get_cost(obj/structure/reagent_dispensers/dispenser) + var/ratio = dispenser.reagents.total_volume / dispenser.reagents.maximum_volume return ..() + round(contents_cost * ratio) @@ -60,7 +59,6 @@ contents_cost = CARGO_CRATE_VALUE * 3.5 export_types = list(/obj/structure/reagent_dispensers/beerkeg) - /datum/export/large/pipedispenser cost = CARGO_CRATE_VALUE * 2.5 unit_name = "pipe dispenser" @@ -120,27 +118,26 @@ export_types = list(/obj/machinery/portable_atmospherics/canister) k_elasticity = 0.00033 -/datum/export/large/gas_canister/get_cost(obj/O) - var/obj/machinery/portable_atmospherics/canister/C = O +/datum/export/large/gas_canister/get_cost(obj/machinery/portable_atmospherics/canister/canister) var/worth = cost - var/datum/gas_mixture/canister_mix = C.return_air() + var/datum/gas_mixture/canister_mix = canister.return_air() var/canister_gas = canister_mix.gases var/list/gases_to_check = list( - /datum/gas/bz, - /datum/gas/nitrium, - /datum/gas/hypernoblium, - /datum/gas/miasma, - /datum/gas/tritium, - /datum/gas/pluoxium, - /datum/gas/freon, - /datum/gas/hydrogen, - /datum/gas/healium, - /datum/gas/proto_nitrate, - /datum/gas/zauker, - /datum/gas/helium, - /datum/gas/antinoblium, - /datum/gas/halon, - ) + /datum/gas/bz, + /datum/gas/nitrium, + /datum/gas/hypernoblium, + /datum/gas/miasma, + /datum/gas/tritium, + /datum/gas/pluoxium, + /datum/gas/freon, + /datum/gas/hydrogen, + /datum/gas/healium, + /datum/gas/proto_nitrate, + /datum/gas/zauker, + /datum/gas/helium, + /datum/gas/antinoblium, + /datum/gas/halon, + ) for(var/gasID in gases_to_check) canister_mix.assert_gas(gasID) From e63360d8138471e7773e5a5565d0298114b8b2ed Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 00:25:31 +0000 Subject: [PATCH 016/104] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89239.yml | 4 ---- html/changelogs/archive/2025-02.yml | 4 ++++ 2 files changed, 4 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89239.yml diff --git a/html/changelogs/AutoChangeLog-pr-89239.yml b/html/changelogs/AutoChangeLog-pr-89239.yml deleted file mode 100644 index dbf79c0fdf2b3..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89239.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Allows MOD holsters to once again activate while the modsuit is inactive and undeployed." \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index 99f19638c2aa6..c2a45e239f948 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -48,3 +48,7 @@ damage scaling. siliconOpossum: - bugfix: Lathes interfaces are no longer unscrollable on 516 +2025-02-04: + necromanceranne: + - bugfix: Allows MOD holsters to once again activate while the modsuit is inactive + and undeployed. From 165d5632313b953e1f2aa27da5b93f8c08065a31 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Mon, 3 Feb 2025 20:48:04 -0600 Subject: [PATCH 017/104] Map Vote printout has a tooltip explaining where the tallies are coming from (#89236) ## About The Pull Request Hovering over `Current Tallies` offers a tooltip explaining how they work ## Why It's Good For The Game The Tallies aren't an immediately obvious system so this should help people understand it ## Changelog :cl: Melbert qol: Map vote tallies explains how they work if you hover them /:cl: --------- Co-authored-by: san7890 --- code/controllers/subsystem/map_vote.dm | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/code/controllers/subsystem/map_vote.dm b/code/controllers/subsystem/map_vote.dm index f57d73d773e63..d8a05cb9a817c 100644 --- a/code/controllers/subsystem/map_vote.dm +++ b/code/controllers/subsystem/map_vote.dm @@ -53,7 +53,7 @@ SUBSYSTEM_DEF(map_vote) last_message_at = world.time var/list/messages = args.Copy() - to_chat(world, span_purple(boxed_message("Map Vote\n
[messages.Join("\n")]"))) + to_chat(world, span_purple(boxed_message("Map Vote

[jointext(messages, "
")]"))) /datum/controller/subsystem/map_vote/proc/finalize_map_vote(datum/vote/map_vote/map_vote) if(already_voted) @@ -170,4 +170,7 @@ SUBSYSTEM_DEF(map_vote) for(var/map_id in map_vote_cache) var/datum/map_config/map = config.maplist[map_id] data += "[map.map_name] - [map_vote_cache[map_id]]" - tally_printout = boxed_message("Current Tallies\n
[data.Join("\n")]") + var/tally_msg = span_tooltip("A map's tallies are reset after it wins a vote. \ + Otherwise, they are carried over and added onto from the next vote on the next round, \ + until it eventually wins and is reset.", "Current Tallies") + tally_printout = boxed_message("[tally_msg]

[jointext(data, "
")]") From 7c0eefc49a61cd7adc72bffb7a671544b18e7c9e Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Tue, 4 Feb 2025 02:58:31 +0000 Subject: [PATCH 018/104] Automatic changelog for PR #89236 [ci skip] --- html/changelogs/AutoChangeLog-pr-89236.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89236.yml diff --git a/html/changelogs/AutoChangeLog-pr-89236.yml b/html/changelogs/AutoChangeLog-pr-89236.yml new file mode 100644 index 0000000000000..df8500d6d25c4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89236.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - qol: "Map vote tallies explains how they work if you hover them" \ No newline at end of file From bb4cfb21be91e5f1d95f4c91385b4d0c04102af2 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 00:31:06 +0000 Subject: [PATCH 019/104] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89236.yml | 4 ---- html/changelogs/archive/2025-02.yml | 3 +++ 2 files changed, 3 insertions(+), 4 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89236.yml diff --git a/html/changelogs/AutoChangeLog-pr-89236.yml b/html/changelogs/AutoChangeLog-pr-89236.yml deleted file mode 100644 index df8500d6d25c4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89236.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - qol: "Map vote tallies explains how they work if you hover them" \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index c2a45e239f948..9489c669b8d8f 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -52,3 +52,6 @@ necromanceranne: - bugfix: Allows MOD holsters to once again activate while the modsuit is inactive and undeployed. +2025-02-05: + Melbert: + - qol: Map vote tallies explains how they work if you hover them From 191b9e1a7592e00c8672c9b2c690687ad4cbefdc Mon Sep 17 00:00:00 2001 From: StaringGasMask <62149527+Exester509@users.noreply.github.com> Date: Wed, 5 Feb 2025 02:29:40 +0100 Subject: [PATCH 020/104] Improvements to the Syndicate Lavaland base (#89231) ## About The Pull Request Makes the Lavaland Syndicate base more sustainable without its crew. Now, two more turrets guard previously unchecked access points, so miners have to put some effort in something other than crossing the lava. On top of that, RTGs now generate 20kW of power, same as abductor and debug ones, removing the need for the turbine to be set up every time. Finally, the Syndicate agents inside now get a full mechanical toolbox in their rooms, so they can break out if a miner managed to enter the base and wall off their rooms. On top of all that, a message monitoring console has been added to the only telecomms random room that didn't have it, and its atmosphere has been sealed off from outside (which it wasn't for some reason). Finally, a single defibrillator has been added to the medbay ## Why It's Good For The Game The base, despite being a decent ghost spawn, would be borderline unrecoverable if it didn't get crew early in the shift. Power-wise, the RTG output was insufficient, and APCs would start losing power, until the entire base was practically non-functional. Setting the turbine at this point was also marginally harder than before, which made getting out of the powerless state unnecessarily hard. Talking about the turbine, it's a deathtrap if the crew doesn't know what they're doing. It not being necessary anymore would help the operator stay alive and be able to do whatever they joined to do. And now, even if you do die, you can be revived by your comrades with the new defibrillator available in the base's medbay. On the topic of defenses, it was rather easy for a miner with an RCD or a lava boat to cross the lake, take all the loot with minimal effort, and wall the agents inside. This is now slightly harder due to the additional turrets. On top of that, if a miner does manage to break in and take everything, a simple wall won't lock the operatives in anymore, since they now have tools to break out. Finally, the changes to the telecomms random rooms seek to let the comms agents do roughly the same things, most importantly, mess with the PDA messages. ## Changelog :cl: map: The Syndicate Lavaland base has been generally improved, with more defenses and comms equipment. /:cl: --- .../lavaland_surface_syndicate_base1.dmm | 22 +++++++++--- .../commswilding_1.dmm | 6 +++- .../commswilding_3.dmm | 36 +++++++++++-------- .../mob_spawn/ghost_roles/mining_roles.dm | 4 +++ code/modules/power/rtg.dm | 2 +- 5 files changed, 49 insertions(+), 21 deletions(-) diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm index b73cf11fda63e..6bdb976de4bbc 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1.dmm @@ -667,6 +667,9 @@ /area/ruin/syndicate_lava_base/chemistry) "fx" = ( /obj/structure/sign/warning/secure_area, +/obj/machinery/porta_turret/syndicate{ + dir = 9 + }, /turf/closed/wall/mineral/plastitanium/nodiagonal, /area/ruin/syndicate_lava_base/cargo) "fA" = ( @@ -1593,6 +1596,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/east, /obj/effect/mapping_helpers/airalarm/syndicate_access, +/obj/item/defibrillator/loaded, /turf/open/floor/iron/white/side{ dir = 4 }, @@ -1866,6 +1870,9 @@ /area/ruin/syndicate_lava_base/arrivals) "oF" = ( /obj/structure/sign/warning/secure_area, +/obj/machinery/porta_turret/syndicate{ + dir = 9 + }, /turf/closed/wall/mineral/plastitanium/nodiagonal, /area/ruin/syndicate_lava_base/arrivals) "oH" = ( @@ -2163,6 +2170,10 @@ /obj/machinery/light/small/directional/east, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/cargo) +"sB" = ( +/obj/structure/sign/warning/secure_area, +/turf/closed/wall/mineral/plastitanium/nodiagonal, +/area/ruin/syndicate_lava_base/cargo) "sH" = ( /obj/machinery/door/airlock/virology/glass{ name = "Monkey Pen" @@ -3316,7 +3327,6 @@ /obj/structure/table/wood, /obj/item/ammo_box/magazine/m9mm, /obj/machinery/airalarm/directional/north, -/obj/item/crowbar/red, /obj/effect/mapping_helpers/airalarm/syndicate_access, /turf/open/floor/carpet/red, /area/ruin/syndicate_lava_base/dormitories) @@ -3648,6 +3658,10 @@ }, /turf/open/floor/iron, /area/ruin/syndicate_lava_base/engineering) +"Oj" = ( +/obj/structure/sign/warning/secure_area, +/turf/closed/wall/mineral/plastitanium/nodiagonal, +/area/ruin/syndicate_lava_base/arrivals) "Oq" = ( /obj/effect/spawner/random/vending/colavend{ hacked = 1 @@ -4127,7 +4141,6 @@ /obj/item/ammo_box/magazine/m9mm, /obj/item/ammo_box/magazine/sniper_rounds, /obj/machinery/airalarm/directional/north, -/obj/item/crowbar/red, /obj/effect/mapping_helpers/airalarm/syndicate_access, /turf/open/floor/carpet/red, /area/ruin/syndicate_lava_base/dormitories) @@ -4506,7 +4519,6 @@ /obj/structure/table/wood, /obj/item/ammo_box/magazine/m9mm, /obj/item/ammo_box/magazine/sniper_rounds, -/obj/item/crowbar/red, /turf/open/floor/carpet/red, /area/ruin/syndicate_lava_base/dormitories) "Zw" = ( @@ -5325,7 +5337,7 @@ Vb mT mT mT -oF +Oj ab ab ab @@ -6648,7 +6660,7 @@ ab ab ab ab -fx +sB gh fx si diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_1.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_1.dmm index 92338633ecfb3..8ca5c0cd2b50e 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_1.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_1.dmm @@ -135,6 +135,10 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/ruin/syndicate_lava_base/telecomms) +"R" = ( +/obj/structure/filingcabinet/medical, +/turf/open/floor/iron/dark, +/area/ruin/syndicate_lava_base/telecomms) "U" = ( /obj/machinery/light/small/directional/east, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -216,7 +220,7 @@ f (6,1,1) = {" a e -c +R Z m C diff --git a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_3.dmm b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_3.dmm index dd00fa974852e..cd6670dfb21f1 100644 --- a/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_3.dmm +++ b/_maps/RandomRuins/LavaRuins/lavaland_surface_syndicate_base1/commswilding_3.dmm @@ -41,6 +41,10 @@ /obj/item/paper_bin, /obj/item/pen, /obj/structure/closet/cardboard, +/obj/item/modular_computer/pda/chameleon/broken{ + pixel_x = 5; + pixel_y = 4 + }, /turf/open/floor/iron, /area/ruin/syndicate_lava_base/telecomms) "m" = ( @@ -63,7 +67,7 @@ /turf/open/floor/iron, /area/ruin/syndicate_lava_base/telecomms) "q" = ( -/obj/structure/girder, +/obj/effect/spawner/structure/window/reinforced/plasma/plastitanium, /turf/open/floor/plating/lavaland_atmos, /area/ruin/syndicate_lava_base/telecomms) "r" = ( @@ -75,16 +79,12 @@ /area/ruin/syndicate_lava_base/telecomms) "t" = ( /obj/structure/sign/poster/contraband/syndiemoth/directional/west, -/obj/item/radio/intercom{ - freerange = 1; - name = "Syndicate Radio Intercom"; - pixel_y = 5 - }, -/obj/structure/table/reinforced, /obj/effect/decal/cleanable/cobweb, -/obj/item/phone{ - pixel_x = -4; - pixel_y = -4 +/obj/machinery/computer/message_monitor{ + dir = 4 + }, +/obj/item/paper/monitorkey{ + pixel_x = 5 }, /turf/open/floor/iron/grimy, /area/ruin/syndicate_lava_base/telecomms) @@ -99,6 +99,7 @@ /obj/machinery/door/poddoor{ id = "lavalandsyndi_fredrickleft" }, +/obj/structure/fans/tiny, /turf/open/floor/plating, /area/ruin/syndicate_lava_base/telecomms) "y" = ( @@ -112,16 +113,21 @@ /turf/open/floor/iron/grimy, /area/ruin/syndicate_lava_base/telecomms) "z" = ( -/obj/item/modular_computer/pda/chameleon/broken{ - pixel_x = 5; - pixel_y = 4 - }, /obj/structure/table/reinforced, /obj/item/food/cherrycupcake{ pixel_x = -7; pixel_y = 13 }, +/obj/item/radio/intercom{ + freerange = 1; + name = "Syndicate Radio Intercom"; + pixel_y = 5 + }, /obj/effect/decal/cleanable/dirt, +/obj/item/phone{ + pixel_x = -4; + pixel_y = -4 + }, /turf/open/floor/iron/grimy, /area/ruin/syndicate_lava_base/telecomms) "A" = ( @@ -189,6 +195,7 @@ /obj/effect/turf_decal/tile/red{ dir = 1 }, +/obj/structure/filingcabinet/security, /turf/open/floor/iron, /area/ruin/syndicate_lava_base/telecomms) "K" = ( @@ -199,6 +206,7 @@ "O" = ( /obj/effect/mapping_helpers/airalarm/syndicate_access, /obj/machinery/airalarm/directional/north, +/obj/structure/filingcabinet/medical, /turf/open/floor/iron, /area/ruin/syndicate_lava_base/telecomms) "P" = ( diff --git a/code/modules/mob_spawn/ghost_roles/mining_roles.dm b/code/modules/mob_spawn/ghost_roles/mining_roles.dm index 3edfbb3416ac7..fb2d4073e971a 100644 --- a/code/modules/mob_spawn/ghost_roles/mining_roles.dm +++ b/code/modules/mob_spawn/ghost_roles/mining_roles.dm @@ -309,6 +309,8 @@ shoes = /obj/item/clothing/shoes/combat r_pocket = /obj/item/gun/ballistic/automatic/pistol r_hand = /obj/item/gun/ballistic/rifle/sniper_rifle + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding/up implants = list(/obj/item/implant/weapons_auth) @@ -320,6 +322,8 @@ suit = /obj/item/clothing/suit/armor/vest mask = /obj/item/clothing/mask/chameleon/gps r_hand = /obj/item/melee/energy/sword/saber + belt = /obj/item/storage/belt/utility/full + glasses = /obj/item/clothing/glasses/welding/up /datum/outfit/lavaland_syndicate/comms/icemoon name = "Icemoon Syndicate Comms Agent" diff --git a/code/modules/power/rtg.dm b/code/modules/power/rtg.dm index 69693af3a4a92..99f61186180d7 100644 --- a/code/modules/power/rtg.dm +++ b/code/modules/power/rtg.dm @@ -112,7 +112,7 @@ name = "Lava powered RTG" desc = "This device only works when exposed to the toxic fumes of Lavaland" circuit = null - power_gen = 1500 + power_gen = 20000 anchored = TRUE resistance_flags = LAVA_PROOF From 58b2567325efb52b27fb64a9376bedcb65953738 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 02:30:48 +0100 Subject: [PATCH 021/104] Fixes another two missing areas on icebox (#89337) ## About The Pull Request ![image](https://github.com/user-attachments/assets/4ba1efb9-eac4-4300-a5ca-77e30bef6f7b) ## Changelog :cl: fix: Fixed another two missing areas on icebox /:cl: --- _maps/map_files/IceBoxStation/IceBoxStation.dmm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index d03e68a03371a..4671dce46ab65 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -267257,7 +267257,7 @@ ooL ooL ooL ooL -nXb +omh buU omh skW @@ -267514,7 +267514,7 @@ bln bln lSu lSu -nXb +omh omh omh xTy From 4dd98e8b25e570315dda5aa20ce2b07870740c55 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 01:37:00 +0000 Subject: [PATCH 022/104] Automatic changelog for PR #89231 [ci skip] --- html/changelogs/AutoChangeLog-pr-89231.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89231.yml diff --git a/html/changelogs/AutoChangeLog-pr-89231.yml b/html/changelogs/AutoChangeLog-pr-89231.yml new file mode 100644 index 0000000000000..4bb6f363a93d1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89231.yml @@ -0,0 +1,4 @@ +author: "Exester509" +delete-after: True +changes: + - map: "The Syndicate Lavaland base has been generally improved, with more defenses and comms equipment." \ No newline at end of file From f1b3f9f744740ffdf7c99ba5806affa18b3e1fb1 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 01:37:36 +0000 Subject: [PATCH 023/104] Automatic changelog for PR #89337 [ci skip] --- html/changelogs/AutoChangeLog-pr-89337.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89337.yml diff --git a/html/changelogs/AutoChangeLog-pr-89337.yml b/html/changelogs/AutoChangeLog-pr-89337.yml new file mode 100644 index 0000000000000..dc3cb897530eb --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89337.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed another two missing areas on icebox" \ No newline at end of file From e74e288ae1265475169a96573c7c2777d1fb07e6 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 15:06:03 +0100 Subject: [PATCH 024/104] Adds cooling loops and cold tiles to all kitchen freezers (#89245) ## About The Pull Request Makes all freezers cold roundstart (wasn't the case for Meta, Delta and Birdshot) and adds cooling loops to all freezers (those were missing from all maps bar Meta and Delta) This is a commission for @RaveRadbury
Previews Birdshot: ![image](https://github.com/user-attachments/assets/f00d01aa-016e-478e-992a-99722a882ea5) NebulaStation: ![image](https://github.com/user-attachments/assets/ca6e4134-d0a2-4108-aec3-8b453a3bef07) Tramstation: ![image](https://github.com/user-attachments/assets/e349a7f1-04a4-493c-b919-6101476f5e1e) Wawastation: ![image](https://github.com/user-attachments/assets/355a7199-bfc7-4256-a823-faf42e638275) Icebox has a temperature unit-less loop, instead utilizing natural cold of the ice moon: ![image](https://github.com/user-attachments/assets/aaa5ace7-b0fe-45ed-a06c-fe4d9a804f3d)
## Why It's Good For The Game Map parity, makes sure that all freezers are naturally cold and stay that way throughout the shift. ## Changelog :cl: map: Added cooling loops and cold tiles to all kitchen freezers that were missing them /:cl: --- _maps/map_files/Birdshot/birdshot.dmm | 104 ++++--- .../map_files/Deltastation/DeltaStation2.dmm | 49 +-- .../map_files/IceBoxStation/IceBoxStation.dmm | 287 ++++++++++++++---- _maps/map_files/MetaStation/MetaStation.dmm | 7 +- .../map_files/NebulaStation/NebulaStation.dmm | 49 ++- _maps/map_files/tramstation/tramstation.dmm | 75 ++++- _maps/map_files/wawastation/wawastation.dmm | 89 ++++-- code/game/turfs/open/floor/iron_floor.dm | 10 + .../machinery/air_alarm/_air_alarm.dm | 6 + .../air_alarm/air_alarm_thresholds.dm | 6 + code/modules/mapping/mapping_helpers.dm | 14 +- icons/effects/mapping_helpers.dmi | Bin 27225 -> 22929 bytes 12 files changed, 522 insertions(+), 174 deletions(-) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index 758a5c877925e..1940705b466f4 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -533,14 +533,16 @@ "amK" = ( /obj/effect/turf_decal/weather/snow, /obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/turf_decal/weather/snow/corner{ dir = 9 }, /obj/structure/cable, /obj/machinery/airalarm/directional/west, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/components/binary/pump/on, +/obj/effect/mapping_helpers/airalarm/tlv_cold_room, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "amX" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -3895,14 +3897,14 @@ /turf/open/floor/iron/white/small, /area/station/security/warden) "bvP" = ( -/obj/machinery/door/airlock{ - name = "Kitchen" - }, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/structure/cable, /obj/structure/disposalpipe/segment, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden, +/obj/machinery/door/airlock{ + name = "Maintenance" + }, /turf/open/floor/plating, /area/station/maintenance/central/greater) "bwz" = ( @@ -3949,9 +3951,8 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 1 }, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/food_cart, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "bxI" = ( /obj/structure/cable, @@ -4719,10 +4720,10 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ - dir = 1 +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 4 }, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "bMt" = ( /obj/structure/cable, @@ -7465,11 +7466,11 @@ id = "kitchenshutters"; name = "Kitchen Shutter Control" }, -/obj/machinery/disposal/bin, -/obj/structure/disposalpipe/trunk{ - dir = 8 +/obj/machinery/smartfridge/drying, +/obj/effect/turf_decal/siding/end{ + dir = 4 }, -/turf/open/floor/iron/kitchen/small, +/turf/open/floor/iron/dark/textured_large, /area/station/service/kitchen) "cMG" = ( /obj/machinery/door/poddoor/incinerator_atmos_aux, @@ -8506,7 +8507,8 @@ /obj/structure/disposalpipe/segment{ dir = 10 }, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold4w, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "ddK" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -9402,9 +9404,8 @@ /turf/open/floor/iron/white, /area/station/science/robotics/augments) "duj" = ( -/obj/structure/disposalpipe/segment{ - dir = 5 - }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/iron/kitchen/small, /area/station/service/kitchen) "dun" = ( @@ -23047,7 +23048,10 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 1 }, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "hWU" = ( /obj/machinery/door/airlock{ @@ -26234,7 +26238,10 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "iSb" = ( /obj/structure/frame/computer{ @@ -30565,7 +30572,11 @@ }, /obj/machinery/power/apc/auto_name/directional/west, /obj/structure/cable, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/components/unary/vent_pump/on/layer4{ + dir = 1 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "kjO" = ( /obj/machinery/portable_atmospherics/canister/air, @@ -33549,7 +33560,10 @@ /obj/machinery/light/small/directional/north, /obj/machinery/icecream_vat, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "lji" = ( /obj/structure/flora/tree/jungle/style_2, @@ -36987,6 +37001,7 @@ /obj/effect/turf_decal/siding/end{ dir = 8 }, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/dark/textured_large, /area/station/service/kitchen) "moj" = ( @@ -44319,6 +44334,11 @@ /obj/effect/turf_decal/siding{ dir = 8 }, +/obj/item/book/manual/chef_recipes, +/obj/item/stack/package_wrap{ + pixel_y = 2 + }, +/obj/item/holosign_creator/robot_seat/restaurant, /turf/open/floor/iron/dark/textured_large, /area/station/service/kitchen) "oTN" = ( @@ -46399,6 +46419,9 @@ name = "Freezer" }, /obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 1 + }, /turf/open/floor/iron/freezer, /area/station/service/kitchen) "pFk" = ( @@ -52236,15 +52259,13 @@ /turf/open/floor/iron/smooth, /area/station/hallway/secondary/command) "rxZ" = ( -/obj/item/book/manual/chef_recipes, -/obj/item/stack/package_wrap{ - pixel_y = 2 - }, -/obj/item/holosign_creator/robot_seat/restaurant, /obj/effect/turf_decal/siding{ dir = 9 }, -/obj/structure/table, +/obj/machinery/disposal/bin, +/obj/structure/disposalpipe/trunk{ + dir = 1 + }, /turf/open/floor/iron/dark/textured_large, /area/station/service/kitchen) "rya" = ( @@ -54932,7 +54953,10 @@ dir = 5 }, /obj/effect/turf_decal/weather/snow, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "sta" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -63679,11 +63703,12 @@ /area/station/science/robotics/mechbay) "vfI" = ( /obj/machinery/light_switch/directional/north, -/obj/structure/disposalpipe/segment{ - dir = 4 +/obj/effect/turf_decal/siding/end{ + dir = 8 + }, +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom{ + dir = 8 }, -/obj/effect/turf_decal/siding/end, -/obj/machinery/smartfridge/drying, /turf/open/floor/iron/dark/textured_large, /area/station/service/kitchen) "vfK" = ( @@ -65364,6 +65389,10 @@ }, /turf/open/floor/iron/dark, /area/station/science/xenobiology) +"vCu" = ( +/obj/structure/disposalpipe/segment, +/turf/open/floor/iron/kitchen/small, +/area/station/service/kitchen) "vCO" = ( /obj/structure/disposalpipe/segment, /turf/open/floor/iron/white, @@ -67010,7 +67039,10 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 6 }, -/turf/open/floor/iron/freezer, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "wbd" = ( /obj/structure/cable, @@ -100294,7 +100326,7 @@ ljg ddF pEU duj -aTg +vCu rxZ fhp oTM diff --git a/_maps/map_files/Deltastation/DeltaStation2.dmm b/_maps/map_files/Deltastation/DeltaStation2.dmm index e11938e405dca..afeceb69f4760 100644 --- a/_maps/map_files/Deltastation/DeltaStation2.dmm +++ b/_maps/map_files/Deltastation/DeltaStation2.dmm @@ -3158,7 +3158,7 @@ }, /obj/structure/window/reinforced/spawner/directional/east, /obj/effect/turf_decal/delivery, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "aMK" = ( /obj/structure/chair/pew/left, @@ -8221,7 +8221,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 1 }, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "bWZ" = ( /obj/effect/landmark/start/hangover, @@ -18636,7 +18636,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/duct, /mob/living/basic/goat/pete, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "eFj" = ( /obj/structure/window/reinforced/spawner/directional/west, @@ -23442,7 +23442,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/north, /obj/effect/mapping_helpers/airalarm/tlv_cold_room, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "fOz" = ( /obj/structure/disposalpipe/segment{ @@ -27339,7 +27339,7 @@ /area/station/science/xenobiology) "gIJ" = ( /obj/machinery/gibber, -/turf/open/floor/iron/dark/textured, +/turf/open/floor/iron/kitchen_coldroom/dark/textured, /area/station/service/kitchen/coldroom) "gIM" = ( /obj/machinery/atmospherics/components/unary/passive_vent{ @@ -27801,7 +27801,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "gPt" = ( /obj/effect/landmark/event_spawn, @@ -30515,7 +30515,7 @@ "hBF" = ( /obj/structure/kitchenspike, /obj/effect/turf_decal/bot/left, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "hBL" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -32126,6 +32126,7 @@ /obj/effect/decal/cleanable/dirt, /obj/machinery/airalarm/directional/west, /obj/machinery/duct, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "hXx" = ( @@ -32726,7 +32727,7 @@ "idQ" = ( /obj/structure/kitchenspike, /obj/effect/turf_decal/bot/right, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "idT" = ( /turf/closed/wall/r_wall, @@ -36643,7 +36644,7 @@ dir = 1 }, /obj/effect/turf_decal/siding/white, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "jeo" = ( /turf/open/floor/plating, @@ -40161,7 +40162,7 @@ dir = 1 }, /obj/effect/decal/cleanable/dirt, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "jUV" = ( /obj/effect/turf_decal/trimline/neutral/filled/line{ @@ -56826,7 +56827,7 @@ pixel_x = -3; pixel_y = -3 }, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "okJ" = ( /obj/effect/turf_decal/bot, @@ -58680,7 +58681,7 @@ dir = 4 }, /obj/effect/turf_decal/stripes/line, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "oLV" = ( /obj/effect/landmark/start/hangover, @@ -59332,7 +59333,7 @@ }, /obj/machinery/light/small/directional/east, /obj/item/radio/intercom/directional/east, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "oTC" = ( /obj/effect/decal/cleanable/dirt, @@ -71398,7 +71399,7 @@ dir = 4 }, /obj/effect/turf_decal/siding/white/corner, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "rQZ" = ( /obj/machinery/modular_computer/preset/id{ @@ -73380,7 +73381,7 @@ /obj/effect/turf_decal/bot, /obj/item/food/meat/slab/monkey, /obj/item/food/meat/slab/monkey, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "sqT" = ( /obj/structure/cable, @@ -76683,7 +76684,7 @@ dir = 8 }, /obj/effect/landmark/event_spawn, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "thB" = ( /obj/structure/window/reinforced/spawner/directional/west, @@ -89432,7 +89433,7 @@ /obj/effect/turf_decal/bot, /obj/structure/closet/secure_closet/freezer/kitchen, /obj/item/reagent_containers/condiment/flour, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "wqn" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -89585,7 +89586,7 @@ "wrP" = ( /obj/structure/reagent_dispensers/cooking_oil, /obj/effect/turf_decal/delivery, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "wrZ" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -92228,7 +92229,7 @@ /obj/item/reagent_containers/condiment/milk, /obj/item/reagent_containers/condiment/milk, /obj/item/reagent_containers/condiment/soymilk, -/turf/open/floor/iron/dark, +/turf/open/floor/iron/kitchen_coldroom/dark, /area/station/service/kitchen/coldroom) "xcd" = ( /obj/item/stack/cable_coil, @@ -94250,7 +94251,7 @@ }, /obj/structure/disposalpipe/segment, /obj/machinery/duct, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "xAu" = ( /obj/effect/turf_decal/trimline/neutral/warning{ @@ -95267,7 +95268,7 @@ /obj/effect/turf_decal/stripes/line{ dir = 4 }, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "xNv" = ( /obj/item/kirbyplants/random, @@ -95380,7 +95381,7 @@ dir = 10; name = "service camera" }, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "xOP" = ( /obj/structure/cable, @@ -96035,7 +96036,7 @@ /obj/machinery/light/small/directional/west, /obj/machinery/firealarm/directional/west, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "xYW" = ( /obj/effect/decal/cleanable/dirt, @@ -96333,7 +96334,7 @@ dir = 8 }, /obj/effect/decal/cleanable/food/flour, -/turf/open/floor/iron/freezer, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "ydp" = ( /obj/structure/table, diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 4671dce46ab65..846042ad52e9e 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -833,6 +833,12 @@ /obj/structure/window/reinforced/tinted/spawner/directional/north, /turf/open/floor/plating, /area/station/security/prison/safe) +"anW" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "anZ" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle{ dir = 4 @@ -1156,6 +1162,12 @@ }, /turf/open/floor/iron, /area/station/command/bridge) +"aqH" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "aqQ" = ( /obj/structure/table, /obj/item/stack/package_wrap, @@ -1271,6 +1283,12 @@ /obj/item/storage/crayons, /turf/open/floor/iron, /area/station/commons/dorms) +"asf" = ( +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 8 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "asg" = ( /obj/structure/closet, /obj/effect/spawner/random/maintenance/two, @@ -4318,11 +4336,9 @@ name = "The Ice Box"; req_access = list("kitchen") }, -/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ - dir = 1 - }, /obj/effect/turf_decal/siding/white, /obj/item/radio/intercom/directional/east, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden, /turf/open/floor/iron/freezer, /area/station/service/kitchen/coldroom) "biE" = ( @@ -5195,6 +5211,7 @@ /obj/structure/railing{ dir = 1 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/freezer, /area/station/service/kitchen/coldroom) "bts" = ( @@ -5503,6 +5520,12 @@ }, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/surface/outdoors/nospawn) +"bxb" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "bxe" = ( /turf/closed/wall/r_wall, /area/station/maintenance/solars/starboard/fore) @@ -7976,11 +7999,9 @@ /turf/open/floor/iron/dark, /area/station/service/chapel/office) "ceQ" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/structure/cable, /obj/structure/minecart_rail/railbreak, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "ceS" = ( @@ -9550,6 +9571,9 @@ }, /turf/open/floor/iron/dark, /area/station/ai_monitored/turret_protected/ai_upload) +"cBY" = ( +/turf/open/misc/asteroid/snow/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "cCb" = ( /obj/structure/flora/tree/pine/style_random, /turf/open/misc/asteroid/snow/icemoon, @@ -12616,6 +12640,12 @@ /obj/effect/turf_decal/siding/thinplating, /turf/open/floor/plating/snowed/smoothed/icemoon, /area/icemoon/underground/explored) +"dvk" = ( +/obj/structure/fence/corner{ + dir = 9 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "dvl" = ( /obj/machinery/camera/motion/directional/north{ c_tag = "Armory - External" @@ -13202,6 +13232,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /turf/open/floor/carpet, /area/station/security/prison/rec) +"dED" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "dEI" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -14813,6 +14850,9 @@ "ees" = ( /obj/structure/kitchenspike, /obj/machinery/status_display/evac/directional/west, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "eeD" = ( @@ -15797,6 +15837,14 @@ }, /turf/open/floor/iron/showroomfloor, /area/station/security/processing) +"esY" = ( +/obj/effect/decal/cleanable/dirt/dust, +/obj/structure/disposalpipe/segment{ + dir = 9 + }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "eta" = ( /obj/machinery/camera/directional/west{ c_tag = "Central Hallway East" @@ -16103,6 +16151,7 @@ dir = 4 }, /obj/effect/spawner/structure/window/reinforced/tinted, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) "eyb" = ( @@ -18581,8 +18630,9 @@ /turf/open/floor/circuit/telecomms/mainframe, /area/station/tcommsat/server) "fja" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 +/obj/machinery/light/cold/directional/east, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) @@ -19116,6 +19166,7 @@ /obj/structure/disposalpipe/segment{ dir = 5 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/starboard/lesser) "frN" = ( @@ -20584,6 +20635,7 @@ dir = 6 }, /obj/effect/decal/cleanable/dirt/dust, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) "fOU" = ( @@ -20685,6 +20737,7 @@ /obj/machinery/camera/directional/south{ c_tag = "Service - Electrical Maintenace Lower" }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/starboard/lesser) "fQk" = ( @@ -24539,15 +24592,7 @@ /turf/open/floor/plating, /area/station/maintenance/aft/greater) "gWi" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, -/obj/machinery/door/airlock/freezer{ - desc = "The freezer where the chef keeps all the stuff that needs to be kept cold. Ice cold."; - name = "The Ice Box" - }, -/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, -/turf/open/floor/plating, +/turf/closed/wall, /area/station/service/kitchen/coldroom) "gWn" = ( /obj/machinery/atmospherics/components/trinary/filter/flipped{ @@ -28600,6 +28645,12 @@ /obj/effect/mapping_helpers/airlock/access/all/medical/morgue, /turf/open/floor/iron/dark, /area/station/medical/morgue) +"ieb" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "iem" = ( /obj/structure/railing{ dir = 8 @@ -29998,15 +30049,15 @@ /turf/open/floor/iron/white, /area/station/maintenance/port/fore) "iBi" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/structure/table, /obj/item/food/grown/carrot, /obj/item/food/grown/carrot{ pixel_x = -2; pixel_y = 4 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "iBl" = ( @@ -33367,6 +33418,9 @@ /area/station/security/warden) "jBB" = ( /obj/structure/kitchenspike, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 8 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "jBR" = ( @@ -33480,6 +33534,10 @@ /obj/structure/flora/bush/flowers_br/style_random, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/surface/outdoors/nospawn) +"jDF" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "jDG" = ( /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -34686,14 +34744,14 @@ /turf/open/floor/iron/dark, /area/station/science/server) "jUb" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/structure/table, /obj/item/stack/sheet/mineral/coal{ pixel_x = 6; pixel_y = 3 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "jUi" = ( @@ -40173,6 +40231,7 @@ /obj/structure/disposalpipe/trunk/multiz{ dir = 8 }, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) "lvG" = ( @@ -41441,6 +41500,9 @@ frequency = 1453; name = "Kitchen Intercom" }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "lOI" = ( @@ -42363,6 +42425,13 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /turf/open/floor/iron/smooth_large, /area/station/command/heads_quarters/hos) +"mcI" = ( +/obj/structure/lattice/catwalk, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/openspace/icemoon, +/area/icemoon/underground/explored) "mcW" = ( /turf/open/floor/iron/white, /area/station/medical/medbay/central) @@ -48930,10 +48999,10 @@ /turf/open/floor/iron/white, /area/station/science/robotics/lab) "nVJ" = ( +/obj/structure/cable, /obj/structure/disposalpipe/segment{ - dir = 4 + dir = 10 }, -/obj/structure/cable, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "nVR" = ( @@ -49972,6 +50041,7 @@ dir = 4 }, /obj/effect/spawner/random/engineering/flashlight, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/iron/smooth, /area/station/maintenance/starboard/lesser) "olV" = ( @@ -52511,6 +52581,7 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/catwalk_floor/iron_smooth, /area/station/maintenance/starboard/lesser) "oTA" = ( @@ -53411,6 +53482,15 @@ /obj/effect/decal/cleanable/blood/splatter, /turf/open/misc/asteroid/snow/icemoon, /area/icemoon/underground/explored) +"pgR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 8 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "pgY" = ( /obj/machinery/cryo_cell, /obj/effect/turf_decal/stripes/line{ @@ -54142,7 +54222,12 @@ /turf/open/floor/plating, /area/station/science/xenobiology) "prX" = ( -/obj/machinery/light/cold/directional/east, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/components/binary/valve/on{ + dir = 4 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "psb" = ( @@ -56227,9 +56312,8 @@ /turf/open/genturf, /area/icemoon/surface/outdoors/unexplored/rivers/no_monsters) "pWE" = ( -/obj/structure/disposalpipe/segment{ - dir = 9 - }, +/obj/structure/disposalpipe/segment, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/floor/plating, /area/station/maintenance/starboard/lesser) "pWJ" = ( @@ -59166,6 +59250,12 @@ /obj/effect/mapping_helpers/airlock/access/all/engineering/general, /turf/open/floor/plating, /area/station/engineering/storage_shared) +"qNe" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "qNf" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, @@ -60346,6 +60436,15 @@ /obj/effect/turf_decal/tile/neutral/fourcorners, /turf/open/floor/iron/dark, /area/station/command/gateway) +"rcR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/turf/open/floor/plating/snowed/coldroom, +/area/station/service/kitchen/coldroom) "rcS" = ( /obj/effect/turf_decal/weather/snow/corner{ dir = 9 @@ -60371,6 +60470,13 @@ }, /turf/open/floor/iron/dark, /area/station/command/heads_quarters/captain) +"rdg" = ( +/obj/structure/fence/corner{ + dir = 5 + }, +/obj/structure/sign/warning/secure_area, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "rdn" = ( /obj/item/radio/intercom/directional/north, /turf/open/floor/iron, @@ -63028,6 +63134,12 @@ /obj/structure/minecart_rail{ dir = 1 }, +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 5 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "rSe" = ( @@ -63861,9 +63973,6 @@ /turf/open/floor/wood, /area/station/security/prison/rec) "sdF" = ( -/obj/structure/disposalpipe/segment{ - dir = 4 - }, /obj/structure/table, /obj/item/grown/log/tree, /obj/item/grown/log/tree{ @@ -64536,6 +64645,13 @@ }, /turf/open/floor/iron, /area/station/hallway/primary/starboard) +"snJ" = ( +/obj/structure/fence/corner{ + dir = 2 + }, +/obj/structure/sign/warning/secure_area, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "snL" = ( /obj/item/pickaxe{ desc = "Someone left their pickaxe out here, must not have known about the boulder processing machines inside."; @@ -67440,6 +67556,9 @@ /obj/structure/railing{ dir = 1 }, +/obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ + dir = 4 + }, /turf/open/floor/iron/freezer, /area/station/service/kitchen/coldroom) "tei" = ( @@ -68152,6 +68271,18 @@ /obj/effect/mapping_helpers/broken_floor, /turf/open/floor/wood, /area/station/maintenance/fore) +"tnR" = ( +/obj/structure/disposalpipe/segment{ + dir = 4 + }, +/obj/machinery/door/airlock/freezer{ + desc = "The freezer where the chef keeps all the stuff that needs to be kept cold. Ice cold."; + name = "The Ice Box" + }, +/obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "tnY" = ( /obj/structure/sign/nanotrasen{ pixel_x = -32 @@ -74418,6 +74549,7 @@ /obj/machinery/processor{ pixel_y = 6 }, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/white/smooth_large, /area/station/service/kitchen) "vjJ" = ( @@ -77054,6 +77186,12 @@ }, /turf/open/floor/iron/large, /area/station/engineering/lobby) +"vYU" = ( +/obj/structure/fence{ + dir = 4 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "vZa" = ( /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, @@ -78322,6 +78460,10 @@ }, /turf/open/floor/iron/dark, /area/station/service/hydroponics/garden) +"wtv" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/explored) "wtM" = ( /obj/machinery/door/airlock/external{ dir = 4; @@ -80515,6 +80657,15 @@ /obj/item/toy/figure/botanist, /turf/open/floor/iron/dark, /area/station/service/hydroponics) +"wZZ" = ( +/obj/effect/spawner/structure/window/hollow/reinforced/middle{ + dir = 4 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 4 + }, +/turf/open/floor/plating, +/area/station/maintenance/starboard/lesser) "xad" = ( /obj/effect/spawner/structure/window/hollow/reinforced/middle, /obj/structure/cable, @@ -83396,6 +83547,9 @@ /area/mine/mechbay) "xOc" = ( /obj/machinery/light/cold/directional/west, +/obj/structure/disposalpipe/segment{ + dir = 5 + }, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "xOk" = ( @@ -84135,6 +84289,7 @@ /area/icemoon/surface/outdoors/nospawn) "xZv" = ( /obj/machinery/status_display/ai/directional/east, +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply, /turf/open/floor/plating/snowed/coldroom, /area/station/service/kitchen/coldroom) "xZy" = ( @@ -84265,6 +84420,12 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, /turf/open/floor/iron/showroomfloor, /area/station/security/prison/mess) +"yba" = ( +/obj/structure/fence/corner{ + dir = 2 + }, +/turf/open/floor/plating/snowed/smoothed/icemoon, +/area/icemoon/underground/unexplored/rivers/deep/shoreline) "ybb" = ( /obj/effect/turf_decal/trimline/green/filled/line{ dir = 1 @@ -189107,9 +189268,9 @@ tVF kUo iKd ees -mQk +jDF sdF -mQk +rcR fwB fwB fwB @@ -189364,9 +189525,9 @@ sRz tec vcD jBB -mQk +anW jUb -mQk +dED mQk fwB nNg @@ -189620,10 +189781,10 @@ jre tAT btq nRn -mQk -mQk +asf +anW iBi -mQk +pgR mbM oje gYq @@ -189878,7 +190039,7 @@ dLA pnw biu xZv -mQk +aqH fja prX eud @@ -190137,7 +190298,7 @@ jre jre jre gWi -jre +tnR jre jre jre @@ -190394,7 +190555,7 @@ wSs oXE fOS pWE -oXE +esY wSs tpc jre @@ -191675,9 +191836,9 @@ xMq jre jre jre +wZZ jre -jre -jre +wZZ jre aZj aCo @@ -191932,9 +192093,9 @@ iDt iDt xMq lvt +mcI lvt -xMq -xMq +mcI jre jre jre @@ -192187,13 +192348,13 @@ scw iDt iDt iDt -rcY +qau lvt +mcI lvt -xMq -thA -thA -thA +bxb +cBY +vYU thA thA thA @@ -192444,13 +192605,13 @@ scw scw iDt cCb -syw -pJm -pJm -pCG -iDt -thA -thA +gsd +xvp +qNe +wtv +ieb +dvk +yba thA thA thA @@ -192702,11 +192863,11 @@ iDt scw iDt iDt -iDt -iDt -iDt -iDt -thA +rdg +pJm +nvB +pJm +snJ thA thA thA diff --git a/_maps/map_files/MetaStation/MetaStation.dmm b/_maps/map_files/MetaStation/MetaStation.dmm index 4a78966445fff..6d5d3a4400498 100644 --- a/_maps/map_files/MetaStation/MetaStation.dmm +++ b/_maps/map_files/MetaStation/MetaStation.dmm @@ -2179,6 +2179,7 @@ /obj/effect/turf_decal/tile/neutral/opposingcorners{ dir = 1 }, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen) "aNQ" = ( @@ -31313,12 +31314,12 @@ /obj/structure/cable, /obj/effect/decal/cleanable/dirt, /obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden, -/obj/machinery/door/airlock{ - name = "Kitchen Cold Room" - }, /obj/machinery/duct, /obj/structure/disposalpipe/segment, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, +/obj/machinery/door/airlock/freezer{ + name = "Freezer" + }, /turf/open/floor/iron/cafeteria, /area/station/service/kitchen/coldroom) "lbh" = ( diff --git a/_maps/map_files/NebulaStation/NebulaStation.dmm b/_maps/map_files/NebulaStation/NebulaStation.dmm index a386fe33b1a97..d0497c1988f8e 100644 --- a/_maps/map_files/NebulaStation/NebulaStation.dmm +++ b/_maps/map_files/NebulaStation/NebulaStation.dmm @@ -9598,6 +9598,9 @@ dir = 4 }, /obj/machinery/duct, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold{ + dir = 1 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "byG" = ( @@ -12914,6 +12917,9 @@ dir = 4 }, /obj/machinery/duct, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 8 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "bVR" = ( @@ -13265,10 +13271,6 @@ /obj/structure/cable, /turf/open/floor/iron, /area/station/service/kitchen) -"bYy" = ( -/obj/structure/disposalpipe/segment, -/turf/closed/wall, -/area/station/maintenance/fore/greater) "bYA" = ( /obj/effect/turf_decal/siding/wideplating_new/dark{ dir = 8 @@ -25169,9 +25171,6 @@ /turf/open/floor/iron/dark, /area/station/service/chapel) "dMb" = ( -/obj/machinery/door/airlock{ - name = "Kitchen Cold Room" - }, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, @@ -25184,6 +25183,9 @@ dir = 4 }, /obj/machinery/duct, +/obj/machinery/door/airlock/freezer{ + name = "Freezer" + }, /turf/open/floor/iron/dark, /area/station/service/kitchen/coldroom) "dMg" = ( @@ -33526,6 +33528,7 @@ /obj/effect/turf_decal/trimline/brown/corner{ dir = 4 }, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/white/small, /area/station/service/kitchen) "eXC" = ( @@ -41346,8 +41349,10 @@ /obj/structure/disposalpipe/segment{ dir = 4 }, -/obj/machinery/atmospherics/pipe/heat_exchanging/simple, /obj/machinery/duct, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 5 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "ggh" = ( @@ -57574,12 +57579,14 @@ /obj/machinery/door/airlock/maintenance, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/structure/cable, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/disposalpipe/segment{ dir = 4 }, /obj/machinery/duct, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 4 + }, /turf/open/floor/plating, /area/station/maintenance/port/fore) "iAX" = ( @@ -69075,14 +69082,14 @@ /turf/open/floor/iron/dark/textured_large, /area/station/cargo/lobby) "kla" = ( -/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ - dir = 9 - }, /obj/effect/turf_decal/weather/snow/corner, /obj/effect/turf_decal/weather/snow, /obj/effect/turf_decal/weather/snow/corner{ dir = 1 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "kle" = ( @@ -105408,6 +105415,9 @@ dir = 4 }, /obj/machinery/duct, +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 8 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "pCo" = ( @@ -108939,6 +108949,10 @@ }, /turf/open/floor/iron/dark/textured, /area/station/commons/fitness/recreation/lasertag) +"qfe" = ( +/obj/structure/disposalpipe/segment, +/turf/closed/wall, +/area/station/maintenance/fore/greater) "qfk" = ( /obj/effect/turf_decal/siding{ dir = 10 @@ -141776,6 +141790,9 @@ /obj/structure/railing{ dir = 8 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "vcM" = ( @@ -264684,7 +264701,7 @@ oDZ aHU rNJ eIp -bYy +qfe cDg vOl dAJ @@ -266232,7 +266249,7 @@ bzt jkE nLg cij -bYy +qfe loK kCi nKp @@ -266489,7 +266506,7 @@ giL pPi qIG jDn -ybp +qfe pKk wtb iWl @@ -266746,7 +266763,7 @@ tNK wNx nJU vBf -bYy +qfe rqn wik jyw diff --git a/_maps/map_files/tramstation/tramstation.dmm b/_maps/map_files/tramstation/tramstation.dmm index 22a3adce038d4..ca9cc19b6e31d 100644 --- a/_maps/map_files/tramstation/tramstation.dmm +++ b/_maps/map_files/tramstation/tramstation.dmm @@ -1314,6 +1314,9 @@ /turf/open/floor/plating/airless, /area/station/asteroid) "aeo" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 1 + }, /turf/open/misc/asteroid/snow/coldroom, /area/station/service/kitchen/coldroom) "aeq" = ( @@ -1321,6 +1324,9 @@ /obj/effect/turf_decal/weather/snow/corner, /obj/effect/turf_decal/weather/snow, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "aer" = ( @@ -1330,6 +1336,9 @@ /obj/effect/turf_decal/weather/snow, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "aes" = ( @@ -1395,6 +1404,14 @@ "aeF" = ( /obj/machinery/power/apc/auto_name/directional/south, /obj/structure/cable, +/obj/effect/spawner/random/structure{ + name = "random snowman spawner"; + loot = list(/obj/structure/statue/snow/snowman); + spawn_loot_chance = 10 + }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 5 + }, /turf/open/misc/asteroid/snow/coldroom, /area/station/service/kitchen/coldroom) "aeG" = ( @@ -1435,13 +1452,13 @@ /turf/open/floor/plating/airless, /area/station/asteroid) "aeN" = ( -/obj/machinery/door/airlock{ - name = "Kitchen Access" - }, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/structure/cable, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/door/airlock/freezer{ + name = "Freezer" + }, /turf/open/floor/catwalk_floor, /area/station/service/kitchen/coldroom) "aeO" = ( @@ -2931,7 +2948,9 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 4 }, -/obj/structure/kitchenspike, +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "apr" = ( @@ -2940,6 +2959,12 @@ }, /turf/open/floor/iron, /area/station/engineering/atmos/pumproom) +"apA" = ( +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, +/turf/open/misc/asteroid/snow/coldroom, +/area/station/service/kitchen/coldroom) "apC" = ( /turf/closed/wall, /area/station/maintenance/department/crew_quarters/dorms) @@ -6514,12 +6539,10 @@ /turf/open/floor/iron/white, /area/station/security/medical) "bje" = ( -/obj/effect/spawner/random/structure{ - name = "random snowman spawner"; - loot = list(/obj/structure/statue/snow/snowman); - spawn_loot_chance = 10 - }, /obj/machinery/light_switch/directional/south, +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 8 + }, /turf/open/misc/asteroid/snow/coldroom, /area/station/service/kitchen/coldroom) "bjK" = ( @@ -6938,6 +6961,7 @@ "btg" = ( /obj/effect/mapping_helpers/airalarm/tlv_cold_room, /obj/machinery/airalarm/directional/south, +/obj/machinery/atmospherics/pipe/smart/manifold4w/dark/visible, /turf/open/misc/asteroid/snow/coldroom, /area/station/service/kitchen/coldroom) "btC" = ( @@ -8942,6 +8966,9 @@ /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2{ dir = 4 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 5 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "caN" = ( @@ -10558,6 +10585,9 @@ /obj/effect/turf_decal/weather/snow, /obj/effect/turf_decal/weather/snow/corner, /obj/machinery/icecream_vat, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "cDK" = ( @@ -11386,6 +11416,9 @@ /obj/machinery/camera/directional/north{ c_tag = "Civilian - Kitchen Freezer" }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "cRf" = ( @@ -11635,6 +11668,9 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 8 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "cVw" = ( @@ -17591,6 +17627,9 @@ /obj/effect/turf_decal/weather/snow/corner, /obj/item/radio/intercom/directional/north, /obj/machinery/food_cart, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "fhc" = ( @@ -21140,6 +21179,9 @@ "gvC" = ( /obj/structure/closet/secure_closet/freezer/meat, /obj/effect/turf_decal/weather/snow, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold{ + dir = 1 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "gvI" = ( @@ -43818,6 +43860,7 @@ /obj/effect/turf_decal/weather/snow/corner{ dir = 8 }, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "owm" = ( @@ -61540,6 +61583,7 @@ /obj/structure/closet/secure_closet/freezer/fridge, /obj/effect/turf_decal/bot_white, /obj/machinery/airalarm/directional/north, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/white/side, /area/station/service/kitchen) "uEE" = ( @@ -64912,9 +64956,12 @@ /turf/open/floor/iron/white, /area/station/medical/medbay/central) "vLB" = ( -/obj/structure/reagent_dispensers/cooking_oil, /obj/effect/turf_decal/weather/snow, /obj/machinery/light/cold/directional/north, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, +/obj/structure/reagent_dispensers/cooking_oil, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "vLL" = ( @@ -67877,6 +67924,9 @@ "wQr" = ( /obj/effect/turf_decal/weather/snow, /obj/machinery/vending/wardrobe/chef_wardrobe, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, /turf/open/floor/iron/kitchen_coldroom, /area/station/service/kitchen/coldroom) "wQN" = ( @@ -69768,6 +69818,9 @@ "xCR" = ( /obj/structure/ladder, /obj/structure/extinguisher_cabinet/directional/south, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 4 + }, /turf/open/misc/asteroid/snow/coldroom, /area/station/service/kitchen/coldroom) "xDJ" = ( @@ -104061,7 +104114,7 @@ voF jFC nUP cDD -aeo +apA aeF iRL quF diff --git a/_maps/map_files/wawastation/wawastation.dmm b/_maps/map_files/wawastation/wawastation.dmm index feae642f8b108..a6812f5a3a0b8 100644 --- a/_maps/map_files/wawastation/wawastation.dmm +++ b/_maps/map_files/wawastation/wawastation.dmm @@ -1633,6 +1633,9 @@ "aAg" = ( /obj/effect/landmark/event_spawn, /obj/machinery/atmospherics/components/unary/vent_scrubber/on/layer2, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 8 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "aAk" = ( @@ -2137,6 +2140,9 @@ "aJv" = ( /obj/structure/reagent_dispensers/cooking_oil, /obj/machinery/camera/autoname/directional/south, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "aJz" = ( @@ -4187,6 +4193,9 @@ /area/station/command/bridge) "byb" = ( /obj/machinery/atmospherics/components/unary/vent_pump/on/layer4, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold{ + dir = 1 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "byf" = ( @@ -8231,6 +8240,7 @@ /obj/machinery/airalarm/directional/south, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/effect/mapping_helpers/airalarm/tlv_kitchen, /turf/open/floor/iron/kitchen, /area/station/service/kitchen) "cXP" = ( @@ -8285,6 +8295,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /mob/living/basic/goat/pete, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 4 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "cYP" = ( @@ -10063,6 +10076,9 @@ /area/station/engineering/main) "dCh" = ( /obj/machinery/gibber, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 9 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "dCi" = ( @@ -11612,9 +11628,13 @@ /turf/open/floor/iron, /area/station/engineering/atmos) "edv" = ( -/obj/machinery/computer/order_console/cook, -/turf/open/floor/iron, -/area/station/hallway/secondary/service) +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/components/binary/pump/on{ + dir = 8 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/station/service/kitchen/coldroom) "edH" = ( /obj/effect/turf_decal/tile/red/half/contrasted{ dir = 8 @@ -15588,6 +15608,14 @@ /obj/structure/disposalpipe/segment, /turf/open/floor/iron, /area/station/hallway/primary/central) +"fBA" = ( +/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, +/obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/heat_exchanging/manifold{ + dir = 8 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/station/service/kitchen/coldroom) "fBD" = ( /obj/effect/spawner/random/structure/grille, /turf/open/floor/plating, @@ -37663,7 +37691,9 @@ /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, -/obj/machinery/power/apc/auto_name/directional/west, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 5 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "nlI" = ( @@ -40526,9 +40556,9 @@ /area/station/science/explab) "otA" = ( /obj/structure/cable/multilayer/multiz, -/obj/item/assembly/mousetrap/armed, -/obj/machinery/light/directional/north, -/turf/open/floor/plating, +/obj/machinery/computer/order_console/cook, +/obj/effect/turf_decal/tile/dark_green/opposingcorners, +/turf/open/floor/iron, /area/station/hallway/secondary/service) "otH" = ( /obj/structure/closet/crate/cardboard, @@ -41103,8 +41133,9 @@ /turf/closed/wall/r_wall, /area/station/engineering/supermatter) "oEo" = ( -/obj/effect/turf_decal/tile/dark_green/opposingcorners, -/turf/closed/wall, +/obj/machinery/light/directional/north, +/obj/item/assembly/mousetrap/armed, +/turf/open/floor/plating, /area/station/hallway/secondary/service) "oEp" = ( /obj/effect/spawner/structure/window, @@ -44521,6 +44552,13 @@ dir = 1 }, /area/station/service/chapel) +"pMV" = ( +/obj/machinery/power/apc/auto_name/directional/west, +/obj/machinery/atmospherics/components/unary/thermomachine/freezer/on/coldroom{ + dir = 1 + }, +/turf/open/floor/iron/kitchen_coldroom/freezerfloor, +/area/station/service/kitchen/coldroom) "pNa" = ( /obj/machinery/door/window/left/directional/east, /turf/open/floor/grass, @@ -44870,6 +44908,9 @@ "pTn" = ( /obj/structure/kitchenspike, /obj/machinery/light/directional/west, +/obj/machinery/atmospherics/pipe/heat_exchanging/junction{ + dir = 1 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "pTt" = ( @@ -48057,13 +48098,13 @@ /turf/open/floor/iron/white, /area/station/ai_monitored/turret_protected/ai_upload_foyer) "rbt" = ( -/obj/machinery/door/airlock{ - name = "Kitchen Cold Room" - }, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/structure/cable, +/obj/machinery/door/airlock/freezer{ + name = "Freezer" + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "rbw" = ( @@ -50352,6 +50393,9 @@ "rNs" = ( /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 10 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "rNJ" = ( @@ -53842,12 +53886,14 @@ /turf/open/floor/catwalk_floor, /area/station/maintenance/central/lesser) "sUI" = ( -/obj/machinery/door/airlock{ - name = "Kitchen Cold Room" - }, /obj/effect/mapping_helpers/airlock/access/all/service/kitchen, -/obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, +/obj/machinery/atmospherics/pipe/layer_manifold/supply/hidden{ + dir = 4 + }, +/obj/machinery/door/airlock/freezer{ + name = "Freezer" + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "sUM" = ( @@ -55367,6 +55413,9 @@ "twW" = ( /obj/structure/kitchenspike, /obj/item/radio/intercom/directional/west, +/obj/machinery/atmospherics/pipe/heat_exchanging/simple{ + dir = 6 + }, /turf/open/floor/iron/kitchen_coldroom/freezerfloor, /area/station/service/kitchen/coldroom) "txo" = ( @@ -93468,7 +93517,7 @@ mMT mMT mMT mMT -edv +mMT eBb hRB cXe @@ -93724,7 +93773,7 @@ mMT mMT twW pTn -mMT +pMV mMT hwk hRB @@ -93980,7 +94029,7 @@ fDN mMT uZg byb -rNs +fBA nlz rbt cXL @@ -94493,7 +94542,7 @@ atX mUW mMT fNy -rNs +edv rNs dCh mMT diff --git a/code/game/turfs/open/floor/iron_floor.dm b/code/game/turfs/open/floor/iron_floor.dm index c3869ccc962ce..16f74866a1c1d 100644 --- a/code/game/turfs/open/floor/iron_floor.dm +++ b/code/game/turfs/open/floor/iron_floor.dm @@ -434,6 +434,16 @@ name = "cold room floor" initial_gas_mix = KITCHEN_COLDROOM_ATMOS +/turf/open/floor/iron/kitchen_coldroom/dark + icon_state = "darkfull" + base_icon_state = "darkfull" + floor_tile = /obj/item/stack/tile/iron/dark + +/turf/open/floor/iron/kitchen_coldroom/dark/textured + icon_state = "textured_dark" + base_icon_state = "textured_dark" + floor_tile = /obj/item/stack/tile/iron/dark/textured + /turf/open/floor/iron/kitchen_coldroom/freezerfloor icon_state = "freezerfloor" base_icon_state = "freezerfloor" diff --git a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm index 47287197d4354..66ae237886de7 100644 --- a/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm +++ b/code/modules/atmospherics/machinery/air_alarm/_air_alarm.dm @@ -58,6 +58,8 @@ /// Used for air alarm helper called tlv_cold_room to adjust alarm thresholds for cold room. var/tlv_cold_room = FALSE + /// Used for air alarm helper called tlv_kitchen to adjust temperature thresholds for kitchen. + var/tlv_kitchen = FALSE /// Used for air alarm helper called tlv_no_ckecks to remove alarm thresholds. var/tlv_no_checks = FALSE @@ -695,6 +697,10 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/airalarm, 27) tlv_collection["temperature"] = new /datum/tlv/cold_room_temperature tlv_collection["pressure"] = new /datum/tlv/cold_room_pressure +///Used for air alarm kitchen tlv helper, which ensures that kitchen air alarm doesn't trigger from cold room air +/obj/machinery/airalarm/proc/set_tlv_kitchen() + tlv_collection["temperature"] = new /datum/tlv/kitchen_temperature + ///Used for air alarm no tlv helper, which removes alarm thresholds /obj/machinery/airalarm/proc/set_tlv_no_checks() tlv_collection["temperature"] = new /datum/tlv/no_checks diff --git a/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm index 197e0f520a61f..0d289a27031ae 100644 --- a/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm +++ b/code/modules/atmospherics/machinery/air_alarm/air_alarm_thresholds.dm @@ -109,3 +109,9 @@ hazard_min = COLD_ROOM_TEMP - 40 warning_max = COLD_ROOM_TEMP + 20 hazard_max = COLD_ROOM_TEMP + 40 + +/datum/tlv/kitchen_temperature + warning_min = COLD_ROOM_TEMP - 20 + hazard_min = COLD_ROOM_TEMP - 40 + warning_max = BODYTEMP_HEAT_WARNING_1-27 + hazard_max = BODYTEMP_HEAT_WARNING_1 diff --git a/code/modules/mapping/mapping_helpers.dm b/code/modules/mapping/mapping_helpers.dm index da7d288d161fe..d6ed4ebf8e4f0 100644 --- a/code/modules/mapping/mapping_helpers.dm +++ b/code/modules/mapping/mapping_helpers.dm @@ -308,9 +308,11 @@ if(target.tlv_cold_room) target.set_tlv_cold_room() + if(target.tlv_kitchen) + target.set_tlv_kitchen() if(target.tlv_no_checks) target.set_tlv_no_checks() - if(target.tlv_no_checks && target.tlv_cold_room) + if(target.tlv_no_checks + target.tlv_cold_room + target.tlv_kitchen > 1) CRASH("Tried to apply incompatible air alarm threshold helpers!") if(target.syndicate_access) @@ -402,6 +404,16 @@ log_mapping("[src] at [AREACOORD(src)] [(area.type)] tried to adjust [target]'s tlv to cold_room but it's already changed!") target.tlv_cold_room = TRUE +/obj/effect/mapping_helpers/airalarm/tlv_kitchen + name = "airalarm kitchen tlv helper" + icon_state = "airalarm_tlv_kitchen_helper" + +/obj/effect/mapping_helpers/airalarm/tlv_kitchen/payload(obj/machinery/airalarm/target) + if(target.tlv_kitchen) + var/area/area = get_area(target) + log_mapping("[src] at [AREACOORD(src)] [(area.type)] tried to adjust [target]'s tlv to kitchen but it's already changed!") + target.tlv_kitchen = TRUE + /obj/effect/mapping_helpers/airalarm/tlv_no_checks name = "airalarm no checks tlv helper" icon_state = "airalarm_tlv_no_checks_helper" diff --git a/icons/effects/mapping_helpers.dmi b/icons/effects/mapping_helpers.dmi index c415d4dcff1f4d4e04b30619682e5bc941cf0796..cd8d331a5e7e61214a8a261683656ab8aebda930 100644 GIT binary patch literal 22929 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 literal 27225 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 From beb93ff2874981e48ae57e1e45eaab3983ce9325 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:06:27 +0000 Subject: [PATCH 025/104] Automatic changelog for PR #89245 [ci skip] --- html/changelogs/AutoChangeLog-pr-89245.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89245.yml diff --git a/html/changelogs/AutoChangeLog-pr-89245.yml b/html/changelogs/AutoChangeLog-pr-89245.yml new file mode 100644 index 0000000000000..ad15f3b2dcc17 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89245.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - map: "Added cooling loops and cold tiles to all kitchen freezers that were missing them" \ No newline at end of file From 39afc43e31733f529e0fd544399f2ae680f1a397 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:43:07 +0100 Subject: [PATCH 026/104] Fixes plant analyzer attack chain heck (#89352) ## About The Pull Request Closes #89187 ## Changelog :cl: fix: Fixed plant analyzers not being placeable on tables/in backpacks /:cl: --- .../items/devices/scanners/plant_analyzer.dm | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/code/game/objects/items/devices/scanners/plant_analyzer.dm b/code/game/objects/items/devices/scanners/plant_analyzer.dm index 25bfab652f796..363ae5067b0df 100644 --- a/code/game/objects/items/devices/scanners/plant_analyzer.dm +++ b/code/game/objects/items/devices/scanners/plant_analyzer.dm @@ -64,13 +64,15 @@ if(isliving(interacting_with)) playsound(src, SFX_INDUSTRIAL_SCAN, 20, TRUE, -2, TRUE, FALSE) - var/mob/living/L = interacting_with - if(L.mob_biotypes & MOB_PLANT) - plant_biotype_health_scan(interacting_with, user) + var/mob/living/living_target = interacting_with + if(living_target.mob_biotypes & MOB_PLANT) + plant_biotype_health_scan(living_target, user) return ITEM_INTERACT_SUCCESS + return ITEM_INTERACT_BLOCKING - analyze(user, interacting_with) - return ITEM_INTERACT_SUCCESS + if(analyze(user, interacting_with)) + return ITEM_INTERACT_SUCCESS + return NONE /// Same as above, but with right click. Right-clicking scans for chemicals. /obj/item/plant_analyzer/interact_with_atom_secondary(atom/interacting_with, mob/living/user, list/modifiers) @@ -78,7 +80,10 @@ if(!user.can_read(src)) return ITEM_INTERACT_BLOCKING - return do_plant_chem_scan(interacting_with, user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING + if(do_plant_chem_scan(interacting_with, user)) + return ITEM_INTERACT_SUCCESS + + return NONE /* * Scan the target on chemical scan mode. This prints chemical genes and reagents to the user. @@ -91,10 +96,10 @@ */ /obj/item/plant_analyzer/proc/do_plant_chem_scan(atom/scan_target, mob/user) if(isliving(scan_target)) - var/mob/living/L = scan_target - if(L.mob_biotypes & MOB_PLANT) + var/mob/living/living_target = scan_target + if(living_target.mob_biotypes & MOB_PLANT) plant_biotype_chem_scan(scan_target, user) - return TRUE + return TRUE return analyze(user, scan_target) From a2f193079f94cc7f5b7be87dd6891185c9ff390c Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 16:43:27 +0000 Subject: [PATCH 027/104] Automatic changelog for PR #89352 [ci skip] --- html/changelogs/AutoChangeLog-pr-89352.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89352.yml diff --git a/html/changelogs/AutoChangeLog-pr-89352.yml b/html/changelogs/AutoChangeLog-pr-89352.yml new file mode 100644 index 0000000000000..bf0b2036cd2d0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89352.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed plant analyzers not being placeable on tables/in backpacks" \ No newline at end of file From bc19447758a19a7369849adab3b67e92c210d654 Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 5 Feb 2025 12:51:43 -0500 Subject: [PATCH 028/104] Fix blades equipped to a void cloak having visible sprites (#89343) ## About The Pull Request Fixes https://github.com/tgstation/tgstation/issues/87345 This adds a new item trait, `TRAIT_NO_WORN_ICON`, which is exactly what it says on the tin - the worn overlay for said item will not be added when the trait is present, so we give it to items hidden by the hood. I also refactored the `EXAMINE_SKIP` item flag into `TRAIT_EXAMINE_SKIP`. ![2025-02-03 (1738625986) ~ dreamseeker](https://github.com/user-attachments/assets/5e6fec83-580b-419c-a2c6-9dd388471fec) ## Why It's Good For The Game stealth thing having an obvious sprite tell is bad. bugfix good. ## Changelog :cl: fix: Void Cloaks now properly hide blades and such in the suit storage from the wearer's sprite. /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/__DEFINES/obj_flags.dm | 13 +++--- code/__DEFINES/traits/declarations.dm | 4 ++ code/_globalvars/bitfields.dm | 1 - code/_globalvars/traits/_traits.dm | 2 + code/datums/brain_damage/phobia.dm | 2 +- code/datums/elements/dextrous.dm | 2 +- code/datums/elements/strippable.dm | 2 +- code/game/objects/items.dm | 3 ++ .../heretic/items/heretic_armor.dm | 17 +++---- .../antagonists/traitor/objectives/steal.dm | 6 ++- code/modules/clothing/head/wig.dm | 4 +- .../modules/hallucination/inhand_fake_item.dm | 4 +- code/modules/mob/living/basic/drone/_drone.dm | 2 +- code/modules/mob/living/carbon/examine.dm | 46 +++++++++---------- .../living/carbon/human/human_update_icons.dm | 29 ++++++++---- code/modules/mod/modules/modules_antag.dm | 4 +- 16 files changed, 78 insertions(+), 63 deletions(-) diff --git a/code/__DEFINES/obj_flags.dm b/code/__DEFINES/obj_flags.dm index 9f575de9fbc55..2771139a3dca5 100644 --- a/code/__DEFINES/obj_flags.dm +++ b/code/__DEFINES/obj_flags.dm @@ -35,17 +35,16 @@ #define SURGICAL_TOOL (1<<12) //Tool commonly used for surgery: won't attack targets in an active surgical operation on help intent (in case of mistakes) #define CRUEL_IMPLEMENT (1<<13) //This object, when used for surgery, is a lot worse at the job if the target is alive rather than dead #define HAND_ITEM (1<<14) // If an item is just your hand (circled hand, slapper) and shouldn't block things like riding -#define EXAMINE_SKIP (1<<15) // Makes the Examine proc not read out this item. -#define XENOMORPH_HOLDABLE (1<<16) // A Xenomorph can hold this item. -#define NO_PIXEL_RANDOM_DROP (1<<17) //if dropped, it wont have a randomized pixel_x/pixel_y +#define XENOMORPH_HOLDABLE (1<<15) // A Xenomorph can hold this item. +#define NO_PIXEL_RANDOM_DROP (1<<16) //if dropped, it wont have a randomized pixel_x/pixel_y ///Can be equipped on digitigrade legs. -#define IGNORE_DIGITIGRADE (1<<18) +#define IGNORE_DIGITIGRADE (1<<17) /// Has contextual screentips when HOVERING OVER OTHER objects -#define ITEM_HAS_CONTEXTUAL_SCREENTIPS (1 << 19) +#define ITEM_HAS_CONTEXTUAL_SCREENTIPS (1 << 18) /// No blood overlay is allowed to appear on this item, and it cannot gain blood DNA forensics -#define NO_BLOOD_ON_ITEM (1 << 20) +#define NO_BLOOD_ON_ITEM (1 << 19) /// Whether this item should skip the /datum/component/fantasy applied on spawn on the RPG event. Used on things like stacks -#define SKIP_FANTASY_ON_SPAWN (1<<21) +#define SKIP_FANTASY_ON_SPAWN (1<<20) // Flags for the clothing_flags var on /obj/item/clothing diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 434927ac78adc..7006b1041c9f6 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -872,6 +872,10 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_CONTRABAND_BLOCKER "contraband_blocker" /// For edible items that cannot be composted inside hydro trays #define TRAIT_UNCOMPOSTABLE "uncompostable" +/// Items with this trait will not have their worn icon overlayed. +#define TRAIT_NO_WORN_ICON "no_worn_icon" +/// Items with this trait will not appear when examined. +#define TRAIT_EXAMINE_SKIP "examine_skip" //quirk traits #define TRAIT_ALCOHOL_TOLERANCE "alcohol_tolerance" diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm index 689750ff9ce88..3bde6663a02a4 100644 --- a/code/_globalvars/bitfields.dm +++ b/code/_globalvars/bitfields.dm @@ -173,7 +173,6 @@ DEFINE_BITFIELD(item_flags, list( "ABSTRACT" = ABSTRACT, "BEING_REMOVED" = BEING_REMOVED, "DROPDEL" = DROPDEL, - "EXAMINE_SKIP" = EXAMINE_SKIP, "FORCE_STRING_OVERRIDE" = FORCE_STRING_OVERRIDE, "HAND_ITEM" = HAND_ITEM, "IGNORE_DIGITIGRADE" = IGNORE_DIGITIGRADE, diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index a244e1493bb04..b2747ebfa64d6 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -601,6 +601,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CONTRABAND_BLOCKER" = TRAIT_CONTRABAND_BLOCKER, "TRAIT_CUSTOM_TAP_SOUND" = TRAIT_CUSTOM_TAP_SOUND, "TRAIT_DANGEROUS_OBJECT" = TRAIT_DANGEROUS_OBJECT, + "TRAIT_EXAMINE_SKIP" = TRAIT_EXAMINE_SKIP, "TRAIT_FIREDOOR_OPENER" = TRAIT_FIREDOOR_OPENER, "TRAIT_FISHING_BAIT" = TRAIT_FISHING_BAIT, "TRAIT_FOOD_BBQ_GRILLED" = TRAIT_FOOD_BBQ_GRILLED, @@ -618,6 +619,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_NO_TELEPORT" = TRAIT_NO_TELEPORT, "TRAIT_NO_SIDE_KICK" = TRAIT_NO_SIDE_KICK, "TRAIT_NODROP" = TRAIT_NODROP, + "TRAIT_NO_WORN_ICON" = TRAIT_NO_WORN_ICON, "TRAIT_OMNI_BAIT" = TRAIT_OMNI_BAIT, "TRAIT_PLANT_WILDMUTATE" = TRAIT_PLANT_WILDMUTATE, "TRAIT_POISONOUS_BAIT" = TRAIT_POISONOUS_BAIT, diff --git a/code/datums/brain_damage/phobia.dm b/code/datums/brain_damage/phobia.dm index e9733293cff13..132bf835396b7 100644 --- a/code/datums/brain_damage/phobia.dm +++ b/code/datums/brain_damage/phobia.dm @@ -90,7 +90,7 @@ if (!isitem(checked)) return TRUE var/obj/item/checked_item = checked - return !(checked_item.item_flags & EXAMINE_SKIP) + return !HAS_TRAIT(checked_item, TRAIT_EXAMINE_SKIP) /datum/brain_trauma/mild/phobia/handle_hearing(datum/source, list/hearing_args) if(!owner.can_hear() || owner == hearing_args[HEARING_SPEAKER] || !owner.has_language(hearing_args[HEARING_LANGUAGE])) //words can't trigger you if you can't hear them *taps head* diff --git a/code/datums/elements/dextrous.dm b/code/datums/elements/dextrous.dm index 240cfc88494d3..a73d58e18788a 100644 --- a/code/datums/elements/dextrous.dm +++ b/code/datums/elements/dextrous.dm @@ -67,7 +67,7 @@ /datum/element/dextrous/proc/on_examined(mob/living/examined, mob/user, list/examine_list) SIGNAL_HANDLER for(var/obj/item/held_item in examined.held_items) - if(held_item.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) + if((held_item.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_item, TRAIT_EXAMINE_SKIP)) continue examine_list += span_info("[examined.p_They()] [examined.p_have()] [held_item.examine_title(user)] in [examined.p_their()] \ [examined.get_held_index_name(examined.get_held_index_of_item(held_item))].") diff --git a/code/datums/elements/strippable.dm b/code/datums/elements/strippable.dm index 14cdda8e4cf52..8269128e1b08f 100644 --- a/code/datums/elements/strippable.dm +++ b/code/datums/elements/strippable.dm @@ -362,7 +362,7 @@ continue var/obj/item/item = item_data.get_item(owner) - if (isnull(item) || (HAS_TRAIT(item, TRAIT_NO_STRIP) || (item.item_flags & EXAMINE_SKIP))) + if (isnull(item) || (HAS_TRAIT(item, TRAIT_NO_STRIP) || HAS_TRAIT(item, TRAIT_EXAMINE_SKIP))) items[strippable_key] = result continue diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index b70d105953e95..3a5351d08f2c4 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -696,6 +696,7 @@ if(item_flags & DROPDEL && !QDELETED(src)) qdel(src) item_flags &= ~IN_INVENTORY + UnregisterSignal(src, list(SIGNAL_ADDTRAIT(TRAIT_EXAMINE_SKIP), SIGNAL_REMOVETRAIT(TRAIT_EXAMINE_SKIP))) SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user) if(!silent) playsound(src, drop_sound, DROP_SOUND_VOLUME, vary = sound_vary, ignore_walls = FALSE) @@ -760,6 +761,7 @@ give_item_action(action, user, slot) item_flags |= IN_INVENTORY + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_EXAMINE_SKIP), SIGNAL_REMOVETRAIT(TRAIT_EXAMINE_SKIP)), PROC_REF(update_slot_icon), override = TRUE) if(!initial) if(equip_sound && (slot_flags & slot)) playsound(src, equip_sound, EQUIP_SOUND_VOLUME, TRUE, ignore_walls = FALSE) @@ -924,6 +926,7 @@ return null /obj/item/proc/update_slot_icon() + SIGNAL_HANDLER if(!ismob(loc)) return var/mob/owner = loc diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm index a07150919aa36..b425c77a5034b 100644 --- a/code/modules/antagonists/heretic/items/heretic_armor.dm +++ b/code/modules/antagonists/heretic/items/heretic_armor.dm @@ -56,7 +56,6 @@ icon_state = "void_cloak" flags_inv = NONE flags_cover = NONE - item_flags = EXAMINE_SKIP armor_type = /datum/armor/cult_hoodie_void /datum/armor/cult_hoodie_void @@ -69,7 +68,7 @@ /obj/item/clothing/head/hooded/cult_hoodie/void/Initialize(mapload) . = ..() - ADD_TRAIT(src, TRAIT_NO_STRIP, REF(src)) + add_traits(list(TRAIT_NO_STRIP, TRAIT_EXAMINE_SKIP), INNATE_TRAIT) /obj/item/clothing/suit/hooded/cultrobes/void name = "void cloak" @@ -112,17 +111,15 @@ /obj/item/clothing/suit/hooded/cultrobes/void/proc/hide_item(datum/source, obj/item/item, slot) SIGNAL_HANDLER if(slot & ITEM_SLOT_SUITSTORE) - ADD_TRAIT(item, TRAIT_NO_STRIP, REF(src)) // i'd use examine hide but its a flag and yeah + item.add_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON), REF(src)) // i'd use examine hide but its a flag and yeah /obj/item/clothing/suit/hooded/cultrobes/void/proc/show_item(datum/source, obj/item/item, slot) SIGNAL_HANDLER - REMOVE_TRAIT(item, TRAIT_NO_STRIP, REF(src)) + item.remove_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON), REF(src)) /obj/item/clothing/suit/hooded/cultrobes/void/examine(mob/user) . = ..() - if(!IS_HERETIC(user)) - return - if(!hood_up) + if(!IS_HERETIC(user) || !hood_up) return // Let examiners know this works as a focus only if the hood is down @@ -148,8 +145,7 @@ /// Makes our cloak "invisible". Not the wearer, the cloak itself. /obj/item/clothing/suit/hooded/cultrobes/void/proc/make_invisible() - item_flags |= EXAMINE_SKIP - ADD_TRAIT(src, TRAIT_NO_STRIP, REF(src)) + add_traits(list(TRAIT_NO_STRIP, TRAIT_EXAMINE_SKIP), REF(src)) RemoveElement(/datum/element/heretic_focus) if(isliving(loc)) @@ -159,8 +155,7 @@ /// Makes our cloak "visible" again. /obj/item/clothing/suit/hooded/cultrobes/void/proc/make_visible() - item_flags &= ~EXAMINE_SKIP - REMOVE_TRAIT(src, TRAIT_NO_STRIP, REF(src)) + remove_traits(list(TRAIT_NO_STRIP, TRAIT_EXAMINE_SKIP), REF(src)) AddElement(/datum/element/heretic_focus) if(isliving(loc)) diff --git a/code/modules/antagonists/traitor/objectives/steal.dm b/code/modules/antagonists/traitor/objectives/steal.dm index 4c697d66d57fc..77e7d17510b86 100644 --- a/code/modules/antagonists/traitor/objectives/steal.dm +++ b/code/modules/antagonists/traitor/objectives/steal.dm @@ -255,7 +255,7 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /obj/item/traitor_bug name = "suspicious device" desc = "It looks dangerous." - item_flags = EXAMINE_SKIP|NOBLUDGEON + item_flags = NOBLUDGEON icon = 'icons/obj/antags/syndicate_tools.dmi' icon_state = "bug" @@ -267,6 +267,10 @@ GLOBAL_DATUM_INIT(steal_item_handler, /datum/objective_item_handler, new()) /// The time it takes to place this bug. var/deploy_time = 10 SECONDS +/obj/item/traitor_bug/Initialize(mapload) + . = ..() + ADD_TRAIT(src, TRAIT_EXAMINE_SKIP, INNATE_TRAIT) + /obj/item/traitor_bug/examine(mob/user) . = ..() if(planted_on) diff --git a/code/modules/clothing/head/wig.dm b/code/modules/clothing/head/wig.dm index 8dc4ae6eb43b6..b324073a0e2a0 100644 --- a/code/modules/clothing/head/wig.dm +++ b/code/modules/clothing/head/wig.dm @@ -19,11 +19,11 @@ /obj/item/clothing/head/wig/equipped(mob/user, slot) . = ..() if(ishuman(user) && (slot & ITEM_SLOT_HEAD)) - item_flags |= EXAMINE_SKIP + ADD_TRAIT(src, TRAIT_EXAMINE_SKIP, CLOTHING_TRAIT) /obj/item/clothing/head/wig/dropped(mob/user) . = ..() - item_flags &= ~EXAMINE_SKIP + REMOVE_TRAIT(src, TRAIT_EXAMINE_SKIP, CLOTHING_TRAIT) /obj/item/clothing/head/wig/update_icon_state() var/datum/sprite_accessory/hair/hair_style = SSaccessories.hairstyles_list[hairstyle] diff --git a/code/modules/hallucination/inhand_fake_item.dm b/code/modules/hallucination/inhand_fake_item.dm index de3b6b99411e9..665c88113394c 100644 --- a/code/modules/hallucination/inhand_fake_item.dm +++ b/code/modules/hallucination/inhand_fake_item.dm @@ -118,7 +118,7 @@ name = "mirage" plane = ABOVE_HUD_PLANE interaction_flags_item = NONE - item_flags = ABSTRACT | DROPDEL | EXAMINE_SKIP | HAND_ITEM | NOBLUDGEON // Most of these flags don't matter, but better safe than sorry + item_flags = ABSTRACT | DROPDEL | HAND_ITEM | NOBLUDGEON // Most of these flags don't matter, but better safe than sorry resistance_flags = INDESTRUCTIBLE | LAVA_PROOF | FIRE_PROOF | UNACIDABLE | ACID_PROOF /// The hallucination that created us. var/datum/hallucination/parent @@ -132,7 +132,7 @@ RegisterSignal(parent, COMSIG_QDELETING, PROC_REF(parent_deleting)) src.parent = parent - ADD_TRAIT(src, TRAIT_NODROP, INNATE_TRAIT) + add_traits(list(TRAIT_NODROP, TRAIT_EXAMINE_SKIP), INNATE_TRAIT) /obj/item/hallucinated/Destroy(force) UnregisterSignal(parent, COMSIG_QDELETING) diff --git a/code/modules/mob/living/basic/drone/_drone.dm b/code/modules/mob/living/basic/drone/_drone.dm index ba315dade6418..7490a463977e9 100644 --- a/code/modules/mob/living/basic/drone/_drone.dm +++ b/code/modules/mob/living/basic/drone/_drone.dm @@ -277,7 +277,7 @@ //Hands for(var/obj/item/held_thing in held_items) - if(held_thing.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) + if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP)) continue . += "It has [held_thing.examine_title(user)] in its [get_held_index_name(get_held_index_of_item(held_thing))]." diff --git a/code/modules/mob/living/carbon/examine.dm b/code/modules/mob/living/carbon/examine.dm index d494a5a1fba0d..c5b2adeb0d215 100644 --- a/code/modules/mob/living/carbon/examine.dm +++ b/code/modules/mob/living/carbon/examine.dm @@ -370,18 +370,18 @@ var/t_has = p_have() var/t_is = p_are() //head - if(head && !(obscured & ITEM_SLOT_HEAD) && !(head.item_flags & EXAMINE_SKIP)) + if(head && !(obscured & ITEM_SLOT_HEAD) && !HAS_TRAIT(head, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [head.examine_title(user)] on [t_his] head." //back - if(back && !(back.item_flags & EXAMINE_SKIP)) + if(back && !HAS_TRAIT(back, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [back.examine_title(user)] on [t_his] back." //Hands for(var/obj/item/held_thing in held_items) - if(held_thing.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) + if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP)) continue . += "[t_He] [t_is] holding [held_thing.examine_title(user)] in [t_his] [get_held_index_name(get_held_index_of_item(held_thing))]." //gloves - if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !(gloves.item_flags & EXAMINE_SKIP)) + if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !HAS_TRAIT(gloves, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [gloves.examine_title(user)] on [t_his] hands." else if(GET_ATOM_BLOOD_DNA_LENGTH(src)) if(num_hands) @@ -391,23 +391,23 @@ var/cables_or_cuffs = istype(handcuffed, /obj/item/restraints/handcuffs/cable) ? "restrained with cable" : "handcuffed" . += span_warning("[t_He] [t_is] [icon2html(handcuffed, user)] [cables_or_cuffs]!") //shoes - if(shoes && !(obscured & ITEM_SLOT_FEET) && !(shoes.item_flags & EXAMINE_SKIP)) + if(shoes && !(obscured & ITEM_SLOT_FEET) && !HAS_TRAIT(shoes, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [shoes.examine_title(user)] on [t_his] feet." //mask - if(wear_mask && !(obscured & ITEM_SLOT_MASK) && !(wear_mask.item_flags & EXAMINE_SKIP)) + if(wear_mask && !(obscured & ITEM_SLOT_MASK) && !HAS_TRAIT(wear_mask, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [wear_mask.examine_title(user)] on [t_his] face." - if(wear_neck && !(obscured & ITEM_SLOT_NECK) && !(wear_neck.item_flags & EXAMINE_SKIP)) + if(wear_neck && !(obscured & ITEM_SLOT_NECK) && !HAS_TRAIT(wear_neck, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [wear_neck.examine_title(user)] around [t_his] neck." //eyes if(!(obscured & ITEM_SLOT_EYES) ) - if(glasses && !(glasses.item_flags & EXAMINE_SKIP)) + if(glasses && !HAS_TRAIT(glasses, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [glasses.examine_title(user)] covering [t_his] eyes." else if(HAS_TRAIT(src, TRAIT_UNNATURAL_RED_GLOWY_EYES)) . += span_warning("[t_His] eyes are glowing with an unnatural red aura!") else if(HAS_TRAIT(src, TRAIT_BLOODSHOT_EYES)) . += span_warning("[t_His] eyes are bloodshot!") //ears - if(ears && !(obscured & ITEM_SLOT_EARS) && !(ears.item_flags & EXAMINE_SKIP)) + if(ears && !(obscured & ITEM_SLOT_EARS) && !HAS_TRAIT(ears, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [ears.examine_title(user)] on [t_his] ears." // Yes there's a lot of copypasta here, we can improve this later when carbons are less dumb in general @@ -421,7 +421,7 @@ var/t_is = p_are() //uniform - if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING) && !(w_uniform.item_flags & EXAMINE_SKIP)) + if(w_uniform && !(obscured & ITEM_SLOT_ICLOTHING) && !HAS_TRAIT(w_uniform, TRAIT_EXAMINE_SKIP)) //accessory var/accessory_message = "" if(istype(w_uniform, /obj/item/clothing/under)) @@ -432,36 +432,36 @@ . += "[t_He] [t_is] wearing [w_uniform.examine_title(user)][accessory_message]." //head - if(head && !(obscured & ITEM_SLOT_HEAD) && !(head.item_flags & EXAMINE_SKIP)) + if(head && !(obscured & ITEM_SLOT_HEAD) && !HAS_TRAIT(head, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [head.examine_title(user)] on [t_his] head." //mask - if(wear_mask && !(obscured & ITEM_SLOT_MASK) && !(wear_mask.item_flags & EXAMINE_SKIP)) + if(wear_mask && !(obscured & ITEM_SLOT_MASK) && !HAS_TRAIT(wear_mask, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [wear_mask.examine_title(user)] on [t_his] face." //neck - if(wear_neck && !(obscured & ITEM_SLOT_NECK) && !(wear_neck.item_flags & EXAMINE_SKIP)) + if(wear_neck && !(obscured & ITEM_SLOT_NECK) && !HAS_TRAIT(wear_neck, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [wear_neck.examine_title(user)] around [t_his] neck." //eyes if(!(obscured & ITEM_SLOT_EYES) ) - if(glasses && !(glasses.item_flags & EXAMINE_SKIP)) + if(glasses && !HAS_TRAIT(glasses, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [glasses.examine_title(user)] covering [t_his] eyes." else if(HAS_TRAIT(src, TRAIT_UNNATURAL_RED_GLOWY_EYES)) . += span_warning("[t_His] eyes are glowing with an unnatural red aura!") else if(HAS_TRAIT(src, TRAIT_BLOODSHOT_EYES)) . += span_warning("[t_His] eyes are bloodshot!") //ears - if(ears && !(obscured & ITEM_SLOT_EARS) && !(ears.item_flags & EXAMINE_SKIP)) + if(ears && !(obscured & ITEM_SLOT_EARS) && !HAS_TRAIT(ears, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [ears.examine_title(user)] on [t_his] ears." //suit/armor - if(wear_suit && !(wear_suit.item_flags & EXAMINE_SKIP)) + if(wear_suit && !HAS_TRAIT(wear_suit, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [wear_suit.examine_title(user)]." //suit/armor storage - if(s_store && !(obscured & ITEM_SLOT_SUITSTORE) && !(s_store.item_flags & EXAMINE_SKIP)) + if(s_store && !(obscured & ITEM_SLOT_SUITSTORE) && !HAS_TRAIT(s_store, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] carrying [s_store.examine_title(user)] on [t_his] [wear_suit.name]." //back - if(back && !(back.item_flags & EXAMINE_SKIP)) + if(back && !HAS_TRAIT(back, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [back.examine_title(user)] on [t_his] back." //ID - if(wear_id && !(wear_id.item_flags & EXAMINE_SKIP)) + if(wear_id && !HAS_TRAIT(wear_id, TRAIT_EXAMINE_SKIP)) var/obj/item/card/id/id = wear_id.GetID() if(id && get_dist(user, src) <= ID_EXAMINE_DISTANCE) var/id_href = "[wear_id.examine_title(user)]" @@ -471,11 +471,11 @@ . += "[t_He] [t_is] wearing [wear_id.examine_title(user)]." //Hands for(var/obj/item/held_thing in held_items) - if(held_thing.item_flags & (ABSTRACT|EXAMINE_SKIP|HAND_ITEM)) + if((held_thing.item_flags & (ABSTRACT|HAND_ITEM)) || HAS_TRAIT(held_thing, TRAIT_EXAMINE_SKIP)) continue . += "[t_He] [t_is] holding [held_thing.examine_title(user)] in [t_his] [get_held_index_name(get_held_index_of_item(held_thing))]." //gloves - if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !(gloves.item_flags & EXAMINE_SKIP)) + if(gloves && !(obscured & ITEM_SLOT_GLOVES) && !HAS_TRAIT(gloves, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [gloves.examine_title(user)] on [t_his] hands." else if(GET_ATOM_BLOOD_DNA_LENGTH(src) || blood_in_hands) if(num_hands) @@ -485,10 +485,10 @@ var/cables_or_cuffs = istype(handcuffed, /obj/item/restraints/handcuffs/cable) ? "restrained with cable" : "handcuffed" . += span_warning("[t_He] [t_is] [icon2html(handcuffed, user)] [cables_or_cuffs]!") //belt - if(belt && !(obscured & ITEM_SLOT_BELT) && !(belt.item_flags & EXAMINE_SKIP)) + if(belt && !(obscured & ITEM_SLOT_BELT) && !HAS_TRAIT(belt, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_has] [belt.examine_title(user)] about [t_his] waist." //shoes - if(shoes && !(obscured & ITEM_SLOT_FEET) && !(shoes.item_flags & EXAMINE_SKIP)) + if(shoes && !(obscured & ITEM_SLOT_FEET) && !HAS_TRAIT(shoes, TRAIT_EXAMINE_SKIP)) . += "[t_He] [t_is] wearing [shoes.examine_title(user)] on [t_his] feet." /// Collects info displayed about any HUDs the user has when examining src diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index e76301343b2f5..27c78ee932c37 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -91,7 +91,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(uniform.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_ICLOTHING) + if(HAS_TRAIT(uniform, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_ICLOTHING)) return var/target_overlay = uniform.icon_state @@ -152,6 +152,9 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON)) + return + var/icon_file = 'icons/mob/clothing/id.dmi' id_overlay = wear_id.build_worn_icon(default_layer = ID_LAYER, default_icon_file = icon_file) @@ -194,7 +197,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_GLOVES) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_GLOVES)) return var/icon_file = 'icons/mob/clothing/hands.dmi' @@ -245,7 +248,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EYES) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EYES)) return var/icon_file = 'icons/mob/clothing/eyes.dmi' @@ -274,7 +277,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EARS) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_EARS)) return var/icon_file = 'icons/mob/clothing/ears.dmi' @@ -298,7 +301,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_NECK) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_NECK)) return var/icon_file = 'icons/mob/clothing/neck.dmi' @@ -327,7 +330,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_FEET) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_FEET)) return var/icon_file = DEFAULT_SHOES_FILE @@ -365,7 +368,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_SUITSTORE) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_SUITSTORE)) return var/mutable_appearance/s_store_overlay = worn_item.build_worn_icon(default_layer = SUIT_STORE_LAYER, default_icon_file = 'icons/mob/clothing/belt_mirror.dmi') @@ -387,7 +390,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_HEAD) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_HEAD)) return var/icon_file = 'icons/mob/clothing/head/default.dmi' @@ -414,7 +417,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_BELT) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_BELT)) return var/icon_file = 'icons/mob/clothing/belt.dmi' @@ -440,6 +443,9 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON)) + return + var/icon_file = DEFAULT_SUIT_FILE var/mutable_appearance/suit_overlay = wear_suit.build_worn_icon(default_layer = SUIT_LAYER, default_icon_file = icon_file) @@ -489,7 +495,7 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) - if(check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_MASK) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON) || (check_obscured_slots(transparent_protection = TRUE) & ITEM_SLOT_MASK)) return var/icon_file = 'icons/mob/clothing/mask.dmi' @@ -516,6 +522,9 @@ There are several things that need to be remembered: if(update_obscured) update_obscured_slots(worn_item.flags_inv) + if(HAS_TRAIT(worn_item, TRAIT_NO_WORN_ICON)) + return + var/icon_file = 'icons/mob/clothing/back.dmi' back_overlay = back.build_worn_icon(default_layer = BACK_LAYER, default_icon_file = icon_file) diff --git a/code/modules/mod/modules/modules_antag.dm b/code/modules/mod/modules/modules_antag.dm index ba5e1711fcb29..be3f7730b14af 100644 --- a/code/modules/mod/modules/modules_antag.dm +++ b/code/modules/mod/modules/modules_antag.dm @@ -526,10 +526,10 @@ var/list/traits_to_add = list(TRAIT_SILENT_FOOTSTEPS, TRAIT_UNKNOWN, TRAIT_HEAD_INJURY_BLOCKED) /obj/item/mod/module/infiltrator/on_install() - mod.item_flags |= EXAMINE_SKIP + ADD_TRAIT(mod, TRAIT_EXAMINE_SKIP, REF(src)) /obj/item/mod/module/infiltrator/on_uninstall(deleting = FALSE) - mod.item_flags &= ~EXAMINE_SKIP + REMOVE_TRAIT(mod, TRAIT_EXAMINE_SKIP, REF(src)) /obj/item/mod/module/infiltrator/on_part_activation() mod.wearer.add_traits(traits_to_add, REF(src)) From d1bbd6b19a0368d7b7a30d758253134a384e0534 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:52:28 +0000 Subject: [PATCH 029/104] Automatic changelog for PR #89343 [ci skip] --- html/changelogs/AutoChangeLog-pr-89343.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89343.yml diff --git a/html/changelogs/AutoChangeLog-pr-89343.yml b/html/changelogs/AutoChangeLog-pr-89343.yml new file mode 100644 index 0000000000000..94510daa53cd7 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89343.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Void Cloaks now properly hide blades and such in the suit storage from the wearer's sprite." \ No newline at end of file From 5a1b9f27c7cf949e183e04a50a311f269794b988 Mon Sep 17 00:00:00 2001 From: TiviPlus <57223640+TiviPlus@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:56:53 +0100 Subject: [PATCH 030/104] Fix more 516 admin byond hrefs (#89350) ## About The Pull Request Randomly spotted this while lookign at something else ## Changelog :cl: fix: fixed some admin links not working on 516 /:cl: Co-authored-by: TiviPlus <572233640+TiviPlus@users.noreply.com> --- code/__DEFINES/vv.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 1ce2d5d46cb9c..7fa8f49cb7938 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -39,8 +39,8 @@ #define IS_VALID_ASSOC_KEY(V) (!isnum(V)) //hhmmm.. //General helpers -#define VV_HREF_TARGET_INTERNAL(target, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[REF(target)]" -#define VV_HREF_TARGETREF_INTERNAL(targetref, href_key) "?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[targetref]" +#define VV_HREF_TARGET_INTERNAL(target, href_key) "byond://?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[REF(target)]" +#define VV_HREF_TARGETREF_INTERNAL(targetref, href_key) "byond://?_src_=vars;[HrefToken()];[href_key]=TRUE;[VV_HK_TARGET]=[targetref]" #define VV_HREF_TARGET(target, href_key, text) "[text]" #define VV_HREF_TARGETREF(targetref, href_key, text) "[text]" #define VV_HREF_TARGET_1V(target, href_key, text, varname) "[text]" //for stuff like basic varedits, one variable From dfd11e5ebb649042b05f4f0761f1c5651e2971e1 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:57:23 +0000 Subject: [PATCH 031/104] Automatic changelog for PR #89350 [ci skip] --- html/changelogs/AutoChangeLog-pr-89350.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89350.yml diff --git a/html/changelogs/AutoChangeLog-pr-89350.yml b/html/changelogs/AutoChangeLog-pr-89350.yml new file mode 100644 index 0000000000000..41931e722aefd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89350.yml @@ -0,0 +1,4 @@ +author: "TiviPlus" +delete-after: True +changes: + - bugfix: "fixed some admin links not working on 516" \ No newline at end of file From 04025b8f7750a92c8d4e9d16b3b2533409554930 Mon Sep 17 00:00:00 2001 From: Holoo <38228316+Holoo-1@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:58:00 +0200 Subject: [PATCH 032/104] Fixes state laws on 516 (#89347) ## About The Pull Request Title. Fixes: ![image](https://github.com/user-attachments/assets/2ffa9c78-68e1-4451-b50e-b66369c7c0d5) ## Why It's Good For The Game Because it is good to have functioning UI ## Changelog :cl: fix: fixed state laws window on 516 /:cl: --- code/modules/mob/living/silicon/silicon.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 188d104a562f9..3a494d2595c2b 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -309,7 +309,7 @@ ///Gives you a link-driven interface for deciding what laws the statelaws() proc will share with the crew. /mob/living/silicon/proc/checklaws() laws_sanity_check() - var/list = "Which laws do you want to include when stating them for the crew?

" + var/list = "Which laws do you want to include when stating them for the crew?

" var/law_display = "Yes" if (laws.zeroth) From 606460605ce19223d1dcead4ba0c2949c8b4c935 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 17:58:24 +0000 Subject: [PATCH 033/104] Automatic changelog for PR #89347 [ci skip] --- html/changelogs/AutoChangeLog-pr-89347.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89347.yml diff --git a/html/changelogs/AutoChangeLog-pr-89347.yml b/html/changelogs/AutoChangeLog-pr-89347.yml new file mode 100644 index 0000000000000..e16e678b24586 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89347.yml @@ -0,0 +1,4 @@ +author: "Holoo-1" +delete-after: True +changes: + - bugfix: "fixed state laws window on 516" \ No newline at end of file From 08ad79e2da4f47ef05ec105cd0eb04b9415ea4c0 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Wed, 5 Feb 2025 18:00:12 +0000 Subject: [PATCH 034/104] AI mobs won't suicide every time they ventcrawl (#89328) ## About The Pull Request Some kind of refactor to how AI behaviours work kind of messed this one up, all of its return values that ended the proc and stopped the suicide timer were relying on a return value... from a proc called in a timer that could never possibly get sent as the return value for the relevant proc. I fixed it to just call `finish_behaviour` instead. ## Changelog :cl: fix: AI-controlled ventcrawling mobs (botanical spiderlings and legioned monkeys) can once more do so without killing themselves shortly afterwards. /:cl: --- .../ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm index aca89d832814a..06fcfa1472623 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/ventcrawling.dm @@ -82,7 +82,8 @@ if(!HAS_TRAIT(living_pawn, TRAIT_MOVE_VENTCRAWLING) && isturf(get_turf(living_pawn))) // we're out of the vents, so no need to do an exit // assume that we got yeeted out somehow and return this so we can halt the suicide pill timer. - return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED + finish_action(controller, TRUE, target_key) + return living_pawn.forceMove(exit_vent) if(!living_pawn.can_enter_vent(exit_vent, provide_feedback = FALSE)) @@ -90,7 +91,8 @@ emergency_vent = calculate_exit_vent(controller) if(isnull(emergency_vent)) // it's joever. we cooked too hard. - return suicide_pill(controller) | AI_BEHAVIOR_DELAY + suicide_pill(controller) + return controller.set_blackboard_key(BB_EXIT_VENT_TARGET, emergency_vent) // assign and go again addtimer(CALLBACK(src, PROC_REF(exit_the_vents), controller), (rand(controller.blackboard[BB_LOWER_VENT_TIME_LIMIT], controller.blackboard[BB_UPPER_VENT_TIME_LIMIT]) / 2)) // we're in danger mode, so scurry out at half the time it would normally take. @@ -99,9 +101,11 @@ living_pawn.handle_ventcrawl(exit_vent) if(HAS_TRAIT(living_pawn, TRAIT_MOVE_VENTCRAWLING)) // how'd we fail? what the fuck stack_trace("We failed to exit the vents, even though we should have been fine? This is very weird.") - return suicide_pill(controller) | AI_BEHAVIOR_DELAY // all of the prior checks say we should have definitely made it through, but we didn't. dammit. + suicide_pill(controller) + return - return AI_BEHAVIOR_DELAY | AI_BEHAVIOR_SUCCEEDED // we did it! we went into the vents and out of the vents. poggers. + finish_action(controller, TRUE, target_key) + return /// Incredibly stripped down version of the overarching `can_enter_vent` proc on `/mob, just meant for rapid rechecking of a vent. Will be TRUE if not blocked, FALSE otherwise. /datum/ai_behavior/crawl_through_vents/proc/is_vent_valid(obj/machinery/atmospherics/components/unary/vent_pump/checkable) From 653be6d95fe0fdcaa3865e5d87e1f565201886d8 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:00:29 +0100 Subject: [PATCH 035/104] Fixes incorrect power consumption on reagent grinders (#89336) ## About The Pull Request Only place where I found this. SECONDS is *10, so this instead multiplied the value by 10 rather than divided it ## Changelog :cl: fix: Fixed incorrect power consumption on reagent grinders /:cl: --- code/modules/reagents/chemistry/machinery/reagentgrinder.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm index a6938f5dcf5ca..6b8b50807fcfe 100644 --- a/code/modules/reagents/chemistry/machinery/reagentgrinder.dm +++ b/code/modules/reagents/chemistry/machinery/reagentgrinder.dm @@ -453,7 +453,7 @@ total_weight += item_weight //use power according to the total weight of items grinded - use_energy((active_power_usage * (duration / 1 SECONDS)) * (total_weight / maximum_weight)) + use_energy((active_power_usage * (duration / (1 SECONDS))) * (total_weight / maximum_weight)) addtimer(CALLBACK(src, PROC_REF(stop_operating)), duration) @@ -513,6 +513,6 @@ beaker.reagents.convert_reagent(/datum/reagent/consumable/cream, /datum/reagent/consumable/whipped_cream) //power consumed based on the ratio of total reagents mixed - use_energy((active_power_usage * (duration / 1 SECONDS)) * (beaker.reagents.total_volume / beaker.reagents.maximum_volume)) + use_energy((active_power_usage * (duration / (1 SECONDS))) * (beaker.reagents.total_volume / beaker.reagents.maximum_volume)) operating = FALSE From 9e0299207b690893b9bd746109ebdd83cc1a749a Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:00:39 +0000 Subject: [PATCH 036/104] Automatic changelog for PR #89328 [ci skip] --- html/changelogs/AutoChangeLog-pr-89328.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89328.yml diff --git a/html/changelogs/AutoChangeLog-pr-89328.yml b/html/changelogs/AutoChangeLog-pr-89328.yml new file mode 100644 index 0000000000000..1f69ece66f018 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89328.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - bugfix: "AI-controlled ventcrawling mobs (botanical spiderlings and legioned monkeys) can once more do so without killing themselves shortly afterwards." \ No newline at end of file From 5d33e80f1fc7056c578f88d7321679ca21645d0a Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:00:51 +0000 Subject: [PATCH 037/104] Automatic changelog for PR #89336 [ci skip] --- html/changelogs/AutoChangeLog-pr-89336.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89336.yml diff --git a/html/changelogs/AutoChangeLog-pr-89336.yml b/html/changelogs/AutoChangeLog-pr-89336.yml new file mode 100644 index 0000000000000..080af93ca5b0d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89336.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed incorrect power consumption on reagent grinders" \ No newline at end of file From c94e44a834c6cf29eec2a7ed9a95710f4fd65beb Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:01:42 +0100 Subject: [PATCH 038/104] Implements the missing bezerk medbot skin (#89351) ## About The Pull Request ![image](https://github.com/user-attachments/assets/2dd6f05c-8d45-46d7-90a9-b9c87ce3342f) #89341 resprited medbots but didn't resprite the bezerk bot, despite tactical medkits still applying said skin. Also removed an unused trait Closes #89341 ## Why It's Good For The Game Missing sprites are bad ## Changelog :cl: fix: Tactical medkits should no longer create invisible medbots image: Implemented the missing bezerk medbot skin /:cl: --- code/__DEFINES/traits/declarations.dm | 2 -- code/_globalvars/traits/_traits.dm | 1 - code/_globalvars/traits/admin_tooling.dm | 1 - .../mob/living/basic/bots/medbot/medbot.dm | 3 +++ icons/mob/silicon/aibots.dmi | Bin 86778 -> 82393 bytes 5 files changed, 3 insertions(+), 4 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 7006b1041c9f6..5cfca56548424 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -379,8 +379,6 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// for something granting you a diagnostic hud #define TRAIT_DIAGNOSTIC_HUD "diag_hud" #define TRAIT_BOT_PATH_HUD "bot_path_hud" -/// Is a medbot healing you -#define TRAIT_MEDIBOTCOMINGTHROUGH "medbot" #define TRAIT_PASSTABLE "passtable" /// Lets you fly through windows #define TRAIT_PASSWINDOW "passwindow" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index b2747ebfa64d6..b69de9ab16418 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -335,7 +335,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_MAGICALLY_PHASED" = TRAIT_MAGICALLY_PHASED, "TRAIT_MARTIAL_ARTS_IMMUNE" = TRAIT_MARTIAL_ARTS_IMMUNE, "TRAIT_MANSUS_TOUCHED" = TRAIT_MANSUS_TOUCHED, - "TRAIT_MEDIBOTCOMINGTHROUGH" = TRAIT_MEDIBOTCOMINGTHROUGH, "TRAIT_MEDICAL_HUD" = TRAIT_MEDICAL_HUD, "TRAIT_MESON_VISION" = TRAIT_MESON_VISION, "TRAIT_MIME_FAN" = TRAIT_MIME_FAN, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 1a7fa55e21e66..9824c6eb71405 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -298,7 +298,6 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_TOO_TALL" = TRAIT_TOO_TALL, "TRAIT_TOXIMMUNE" = TRAIT_TOXIMMUNE, "TRAIT_TOXINLOVER" = TRAIT_TOXINLOVER, - "TRAIT_MEDIBOTCOMINGTHROUGH" = TRAIT_MEDIBOTCOMINGTHROUGH, "TRAIT_TUMOR_SUPPRESSION" = TRAIT_TUMOR_SUPPRESSED, "TRAIT_UI_BLOCKED" = TRAIT_UI_BLOCKED, "TRAIT_UNCONVERTABLE" = TRAIT_UNCONVERTABLE, diff --git a/code/modules/mob/living/basic/bots/medbot/medbot.dm b/code/modules/mob/living/basic/bots/medbot/medbot.dm index 780fd1a07d7fc..bac615ecfb5fc 100644 --- a/code/modules/mob/living/basic/bots/medbot/medbot.dm +++ b/code/modules/mob/living/basic/bots/medbot/medbot.dm @@ -369,12 +369,14 @@ /mob/living/basic/bot/medbot/mysterious name = "\improper Mysterious Medibot" desc = "International Medibot of mystery." + skin = "bezerk" damage_type_healer = HEAL_ALL_DAMAGE heal_amount = 10 /mob/living/basic/bot/medbot/derelict name = "\improper Old Medibot" desc = "Looks like it hasn't been modified since the late 2080s." + skin = "bezerk" damage_type_healer = HEAL_ALL_DAMAGE medical_mode_flags = MEDBOT_SPEAK_MODE heal_threshold = 0 @@ -385,6 +387,7 @@ desc = "A medibot stolen from a Nanotrasen station and upgraded by the Syndicate. Despite their best efforts at reprogramming, it still appears visibly upset near nuclear explosives." health = 40 maxHealth = 40 + skin = "bezerk" req_one_access = list(ACCESS_SYNDICATE) bot_mode_flags = parent_type::bot_mode_flags & ~BOT_MODE_REMOTE_ENABLED radio_key = /obj/item/encryptionkey/syndicate diff --git a/icons/mob/silicon/aibots.dmi b/icons/mob/silicon/aibots.dmi index 7a4d3ca9c9cf4f5c216ba40e93631c58b6a29397..b0bc6261f6de5b08965164f63ac6b4c525be47f1 100644 GIT binary patch literal 82393 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 z z<_-P|+zw*oqOZ4O23;?IzN))jkLE_`e{s~d;2;x2vUE>583CjX4^e5OVw^~ANRf`B z>%=|lEA`AgDs{*%#A0W6(UXdL zeCJ5*!zZoV1f{yL>p*5T5NkE5tE&s&*c)BHaQi}rgl26rb0Hn4TvgVpk_ye<{=Oyh z>CGW%+^1S?FtG3j(T;5N2CX=AQoK_zF^!dkaPR!G@v$e#MI=X%%O({X{QA>5LDjGi zjr}$DiH#Tn(eH#B*@WQ5?2qs zhxMB!AvsGgyY?6>UBeRPZsOl4N49SciSl6+T+|4EqWT=*UE_-UT%Srfqi-VTXoX&R7uob%!TWnG__=h%5ucB9=?s}#A%vA9 zz2P#X>#RE*TJXbfv< zu~j8vugq$#-8t{Fgf zZ-E%7J01ddPv)|HA}lhuQ%D?G$lZ#4Txb@2mz-`lxzMtQnf_e0C8V8hKu%mZ7x~xr zzbLC~++?vAF^>*QiU81yyFM(l*YWXw+^NAL)G;8So~&ABPXAmcAyq^cZ#zp0+Log_ z+Ahx_tJjImGB2GaYdM`dIF|kg4qFd9RG%e1cO8C@`KGXJRe7YVXz@3<*wN5 z%)&D;?4G+nyu^-2$ZV>R+}sjDB<^(YZ!qKmY=jj^h;lAeXS(T-k;IdbQ*)~GH$f(U zbQXG2>;LGr-Atk5#PZ&e*zxZ({7T5TlY}iM#&063k4|W^pzq9pc@!40n8(#W9HSj! zE9)Ukc4kit89R|gIbxqbr;RRqETDl7ZMnEx@rM$&x1ZgkxI?eNw4Za4o27vKPGqu; zrR2&2RRS+bJp1atE)ZRfkM!1#GVH2qVgUqL2j9@O#HdQ5{yHnfnghRlAz*;Bq*zfw za{`#+?8HWtX`~UYfvoH>{jZ44ZJha z*F|jx%%Zi+^B0U}HEQ3jK-&w6YpXte0yHI|9a8T-R`%GX;MJ06`S@eSW16Hd_ET8V zLz6F6pb~%J?T1GSDeu$FlHeB!>B{>=kEQs(V^eYK%(~p&Zz|s0>j3Jysb`w03|oeR znRrR0Qx*DlkI0SoZ^NU^B zXqH4yeyKg4&QP+A(uVNF)(g33pMP0UDu5fH62wCOszsbW@LRk6F!QLFZz17tC5MMv zo18h>>-ZZyld_}_fo^!KHe4C3)0q|TXLzj8G*D~%mG)KD+XbrlGJr%&w6>~@?iia6 zHqk$n7u&n&$2hG}8nV9? z**FELeR5sk{}w%Lu)*jnSd54z-A?d9_C*O^Bre_|N1wyfx zW+fDTjxMnOj_TTufZEGkiGEPgw!AgGUD41U-=SDn53G(hT#zv}Mb;=s+-~OfjcrEB zq+-Z*t+c)!6i%A^@Wv-~kk=m^W`qKt-z>)S)Vy7NnVbVt^Ul zVIblcSRqwH`t-Ddh6L$h1NTGS=b-RaTr3&>ueeb?CJd1Ide=Ywx#woM!Z2K@OEHWl zm9Ir0z)Z$35h{Ol{k_MYReD&Y#QuRIimg`}<2wFUDJeDfbrx(djSow8(f&~O89;iF zFLpefchdX$9ryWB7)s5VrR=J-&v-1!+YrgYI@ni;fPfVLorl;ygETHa^1nrnF zr!^L~CM~J>=c`yTde-WG>8`^45sq8oq9|{yd`8W=V1?k-rFJ3@kF8^EKa(REai8RM z7PRo(SQ?NJHFCAb2X6~0sb4MrDAdhG!3k?i5n}y-Kd45#E68ec-o-#=yW)D#hKw@ zx|a`fs8B0L@An71aLG;vaWb~W9hpSSl)F;YYX1|65Pb80lAag!tT(3MtF3j}G=P4t zY?;Z5mUHsH!CTt-Sq?m@rpVs{yZNT;d3pYWp>-=|d{>kjzBB#c3QF=vyOx8LN%o|# za%&dh!InMY(4kKuWZH=7B-u$Va^}LE<2eWSZ=P)vl?aOPD($mYgLLCq~f^vFO{2^|3iuk zX9Ar-26djY-wf%pN^F}C`%UrOFVqGs9j$1x7^!+#% z#B2236kMhGfFu_w?%}9Du6&ZN8vG=ory{Qd=BwG)a2Q64Qt`)fZ%!A0%_=muvaZ_D z!lJVs9mwy%E;?@Ev){^$o2Cdiu=b8-8{VC|uA76EI#@@ghiw0Bx_A8aq9UzN^OjNu z|1tK8PwRdmmapiK;b9uqM#UB0s$Lzio19Juk89SKjHyI-(rAG<9wm;gy?#k#H#4phvNAp-aLp{M;TLnLXUT@iY6TGkCm~On1A|q50m0@FiCj4Yqpk8A{*Q!>rz&_Kct5D`@5CTIWN3N4j8# z+GzL9z#^3&J@?@c?yhabCOj&-j+zaf;HXhT_F3T3bHN_Zm=DyoWIx|twPC>~LRWZ4 z2H5yu=#qn=v;m3TR&famndd*54o}+_7Vi9h@`Z}LXRY|Zc>$bV0Jb$Tf|*&@8i#Ja z#waf{IgD(TJQw5lK^<q|S!rHQS-AZapsQ}r!E8avw^OgZr2hZPok~2D zlxzI*be;mg$3tt{G}4WSv16(<{C+Mg{=9->fg+~j=-?@2oZ3z)5I)%BPFaRJi1iMw z`+Y{!pykw=Dk2H0$ZVj)~qtQ7}fO@!+f!GI8m~v{5_pD$-Wgsm*0`)CV zf?Sr?blx>Hf!7++UBxMfsn@Tj?yC+)0##;PmKgt#*)`np6pI3qXkj`1bO?&3igR6D zp&?O$Uk5h)>Om%u_UIyoJO$Ld=WtVQgq>R7R#zj0#y)I#4|oyRfxEXjuGNaK*lqzD zMZN(Z!;Y`RT1s^AgSO%#)&({vpzx8}U^m_oi1J~hnKWqslURB{O#-q{RtA1(fLmK0 zJ5ZRTqBSL_)o;(svVz)3#2D@pKl}qO=dRH z_u4Z;?j|;8&yvcLjyZ(5iXa_yYKJd0BTr8YRm~s%_hJ{>Wv(RsC7Z%7s$N4`QewrfSVH_(4)2xPwiPT4#v0IU6#r| z#Hmn!p{PbNcL4kD>RAq;hsNv(c=Iz!g4DbyaK?-V6P`+e-jP_e#x2CE=}BZRgfc#T`EnoP$`R|8RSH(w@vUjEU9B266!vn zO6S5#i*ctXbDyt*6rj+>e*Z@as~vM*ItG8zW>>BMEIqA4xySL%pLzB(wr&1st-Zsi zy@-uV+Pjm!eV3|88C|g4#q!!Vh-+q|3&sb#4X9s0JKQY#Qhz9jUrF+R@_qSheMF31-J&cs923f z@Y_=TIo`Ik5Z4$5!RNC{k06oC!Et+AD{##FVE(1v9=C&0^Dp)`5Sa9C{GF%-;2FCJ z1An6~TQc0ecJO%KPj*SR+?JG}NAL|}8VUkc?ul$SojK7A-!w6)*n=cC15GWkA$7!N zTavx>nPMxcsiVr^G%#~+Y|oIW*g(8ccLv-r&AKmhQYecr1rqr3uk>_*^_E?P)a^eL znRyRp|0@E$myM0XWF_ld>(Xq}zW!<(h(t>laclUurJVWjuG-as7LWe$InYL<=$gx6 z4bO&egX}t3z+P35Y2BJaEh&da?#G)dUBf3La!;&KEwye=-vp4MDQEb&{ubN`@!o5? zvz0!c`5na-r>~cLzXMYmSJjRn7DgS&UA^%k6t7kgJ^)Y*6^s}*qHo)NK^&pcXUjN& z;BW<57e6<(m*!VTY`RVI)B|QHFmHVNBj%rZ)}GJPY70yfbC+XsGm6uAz~XfUWkGza z6Tz?KZ)wr}BSDfM%e388l7!`~RTq?k#bx+btxFHainX2ec`(U778HE0-+&jSyk#Z2 zXPgSlSyAsCitIOr%R7Fq_?{s{wS47P)dK>U{#sXZL~0y-@&igFfvF*a)S<|Oot)Qu zu*)XEMb&(~J@y(b3(?YjPjKA2YUd*$r(dG9{ZAF?t_t7Jl}Vsppq zv}DihFzpZQkf@}AIYFon#`8favhmy$NjKSZoj)k_dyAu%R_a@Ls}`J4HHbFIJ!A7W8T=|DjH)qojn(70jeR6mKn=y{ZP$)_)oJ>0 z89tf>n*>!IZU&mMp%V!I7+8|Uxq;okiXIF@%|*?t?VI?CBUo0!{JaiAve`?H{n>iL zR{KkPo4VWJ>tBW={v1Z+=Te0Z(V1DXGpIG>>2oj(k4M@JMiBb9LYXcTQxU)j_2lMXHdoQNPM5+j1X%qf= zNpaEG>ndeIf}$7o%rW2Zcni{16XH6)hU~YVDj?;wmwesms%WSH&poMQakMttlhU|r z#|F{b|F2ccJ5pHE+&UwX*3QU?+RLH9*1IrH?)_m@;}>;*AMv?ym7ptJxneTUW8Wis zAFc%PE=-cFk8^)vZn@K(@S8HcXvoSB(+a+l%bpITb-HC*$yZag}?u3rO|&RVlggBov-%jYt&F%PYVOx ze42vWo|vLlA?9ByqjKSrDOR6YE=C*3CG|G1pK@qJ{fv#{F_xWa z1u%6-AdF}O((-7UZi%`%0Ubb}_(qHndFbXhs#=^=JHM^duv z6kI0xmE=Ge^gmy=`#{s8NquMMXK@0`7~Mn)+5|ya(lX%4fhLCZ(iy#&SFyE&8`N^- z(G;9?g_6DtKzZOlvai5*&p|Ut4!i-RNt`T^4H-9epZTl^MNwN&M+9w9<~8_K+{QCo zgO2%BKqWn?i!kcIHxTCkeR$vb;cU(_`cf#lZ{HYS=4HMdq$^s=ehQTG{%6)eFG;Xz zwH+w0-n|d~F+lSyMQ?@jaa^p*L?$h;`~J^lsxE8Mz+-MEa`VQC)Tj>?82+!n?f3u} zj@&YyCOehW*=-oO^Z(YKT?i2a4x^F{AAOhYPw3BIDc?qWA0P<i- zek#^jOSH>UHakWF?GE?)bVM+UOhBJhbMR}%bnMNgxkSDqoRBK+H#mtFzZ7xaq=hEQJy^io=JP&SFOK~YF8;@7QYCt^fs49_5KPg z{Y~FKAb=dzzrQgEr7d!e&WHt0RCi$%Y(X#E-dMzZ>F>{8X0(V5ULOJ9D)is98(^8A zuMRx+$u@X5OPsw8dQWy~m1Z4ug)#?jZ%)nr6f~if4hnt+8DSG_H!5OGbVkwiP>dnZ zPb3JokEJbAlPGEwZ4X-=!>&3t=Z=6s_XpR>QRb|pH)L<0Hc0IN-blJ1UGiwoVrHy| z1zs|7W-Ep|oBkLJJqg;`#`K?${D(vG0*5VB(qCH~4`Iolv0lv{z?R(MEOXny zJJI5#CoqYwiO?o1g>`gzatB( zBnz@M_pqcKoy}{$C}`rSL0(uFcFvLl_J2rW6ubzC<2<>m9lD z{t8U1AUuT*`>*ATIeqn0TA)Qed3D**-hDzt_C3SzzfGyE^PEvPKx)X;vap?0`69zV z(%x%N{#1<_Ip2%~)l;|$pk7`ftGf+C6NVyK!_Ak3*(p}P%y+(&pWaF4Qo96nLW4Cv zAUh@sn-hC_yW6*0BYugZ>cmli;pXHv@iCMXe1w{Qxkz(T)=FiJKGD#w6QZ14HaD*sd%V9P1hRcCpl*INHm+m%1NZ|w#DYQ>wa|ZGH!-!56i!1So@5ip++eKz zR}%AziU_K1p|HXI{W4^-0DOfK7&UhKfHg;QO|cmCmK(lPh7700=8{-*%GN^OY&MlJ zs^oGefknag4BU@V^W@^1{thzQVj3hBt+yU;498h}B@EU-F=+)EgFFY*9O3?azEUXL zdkD7`u+koLVj0KCkE4kX^C3#7<9PKkf=wA!WtLdUFqtV6W@v)PWM;z&X;lgi9CsYw zekFQ~%MB@J<#<+D&UP>#4S_7HQ=LvV0O-^c8s4j2>CsrF6<STi$nIS$Rx01o4Dn3X%!0a?{rS(r=g?I%`a>PG*a)T9N4>1s@HKy0W z;Adi~m~;aI7~hZr8X-$>JK}oBa6aI@ zx$m=CVQEE2fQWD*U}?GT(qIz=BG{LQa%sHn8kQmKLi+A$KEL4m;}w=&Vi1beHZm&s z=%hc9&Kr3DH3-sl|FX88$}KlR7G&?LPAj4}VJBN=Oc+4I00fxP$al2Sm@9qes2+Vo zwV>VdO)nYk?w|)lKZ^jndl#^~qg+?XjgNXScY^@Ut^<(iQ3C~FWo^taqyF);!RLOK zi;13w%D++)Vr_=7JNFY$DK0`Tp8y_YYL0Ui+!#C~kPSGQh$2-=?s+4rirSSho_|f6 zf+70Z=@rV!$)ko(4X(2y?@p^)k4jmv(-dRQtl6naMsCCVN{BG*x5jOZ1*0INo%++! zOrbNNLsGBJgsGb$HNFP^BN;13@g3+k)hgdnsgSwL3=9RF#0_Z@VYjRiGkrGgdG22v z1i}9gY407@)Y3j`C-mN%(m@3U1T26Q11N%mfFivFLG4nLG=Low2 ziSG9*zh0XHzo3q>e$Y~k1%Nw(Zft;-rF=u4t6iH0j&XUr(GW`B$&jdTe!9UjqY!51`}aAlH#OFHV&LWXm5h zYk`zNQH=lrD#Tq4XfS{7pwA!!d?|(=c;W%W`ti?VLQ?$yzVy=Jo@KBVV-eRu5#_D` z*)(9prn#S32xH#cs!tW?Bl1+3ABCmlI=Wvb zc*rh3Wzt_GjF`)(ey;l|j&O+rb1h&}FXXg-w)0mGVmA8@hJ7UYzrk#u^ryGh{5Gvc z0Q}!!V-znX$QszPc;J=8v_A&HQ9)Tz;P2-cdjXr?I8PxjD;lqA{#XEeonZtTzFsoehsKQ!(EZ*7Nr(yytKHJm^Z9AX zYTSGJ*LcoH9^GLGwtfoq?n3X$@Abh_p-K42G!F6@W~4ujp7Axea*JWJmX$livxMHa zjYH%z-a>$vC!Al&8=0FKFR}D{Xd4icO(6sPl@rjFt)OG2rw&=wImtS)Sl{~=SCW5? zO92IZT7;_5qq{UnqopXqWhsiV`^d8tAp*!}ykxKU;R~5sfq}IT)>2|(7+wO$LxX>P z3+e>#p>Vq$M5~kkxD_r+Ypu5g{(XmnIM5C2wx)k8-^CO~3IVnUFuE;1jea_E)PUs78Q3ZXm}LedBf-l}_|yr|nB_k5huT`pJHU<~Z;>W*dd@ zG$EwQvoSLgFnc-u_RX6VH`D)}wY^P~BJA4BcsJ}JAx=nKoTjC^%5!n*_uzf9W267s z34%fG4NaFAAeJ6S*UIhyiXghGMcdAVv)|$%#CE0U$MW{djR{&?DE!1-@3oMGLsuNhA`q3J zHvrddzEe?fd^}6a)u7Kf6R@$O>J_x88}&aItRV1nHB`L;V$SPd7e%3^`pMnakQ3yg zRvf#Zb0Rc6k=gLWv)z3i!E37{fPs8dw`A#={5F$5pG2?MAo(e5p3IYArLN!y86C|@?*pHjU}<80B%y2rQkM@r*Zm7 z0J35^K+%Jb!|5)_nXes_!<88yNW-Dj=^}}zCQZb*MaAQ;1Vo=bP|-T6Ze3zG<{pKUE}lFwAGAc;m^+dQ!Nh=#%p>&sEpY8 zkKitVd~|iQEcdU6T-D#-zXGldsA(^iK~8@)o+qA7K}m z^#av8boqB{-kZ+@!tpg+oOTpgu86P8Dkr z{2`q2AmLvTGml#6*Gr5coch$i_D3DZ1eh{B#N8SNoM}0wwY(OkhX+cwK?{#Cyb|iC0;x`r zzQ#0E>Mv>*`cJ0dIAwq_gbz~F4H9-f8p^=Fl8F~GZ>~5AZU%|kEB7Whww=PlJ2hQ9 zDE{ltQdk#(?;i~%&YnKq8rJptwTLbe%?zP1FqKWfCWLa#8!TWWk!}ubY)nuziIswq zGFX8-x%X7sf8HAi@U8p??{uES@mrek|NGDeC-<516Vu639(|?LpAK~e8RIOaK>uVo zj^i~y;2GuPWG4s2drL?9`ex(;aX-dU((@1O9M2(DdSH$qV{C;u=zj`w$55H$=koz# z7`sMi4XzcRYG`@NE)0QW!^{tkHUdwaI7wGnR84ifHxl5|EZS09ur_?&Bz-gbsrXqw z16HTYPP7p$2v3;ME_q<_qJtBzIn8veOO%D1QhpD?BvPr;A33!G!mww(|J-a1Yv_mE zy0Q6zJX@xPF%URXU-C~FOUGRAK(WQ ze~AR%j0Q9ziJ)sy&${#)l292hL?Bcco(uLp{F(;c*yYX42K<^p2t=aUwwXpa;ZhVx ziT&ZIzuqcVL4PzAYJuSxg*MNOwYC~QR-^ama#BbK3oM}=kd_NR733_#rGa$i`xN4c z!-0Qa^0>ZT7mLGC%Yyc6(7D}YYTWHduu~TSeXqo*EX4b@>y+{dR zM>+BEu;~pY$pG=-X744?E&P7S^yHr^`1AJzwxeS%!w1Ps&YxL$#Aoy2b7AHjopLX% z6;!n8bO%(hWvihY8M1M#vV?iUk3BKJe&0*NSyJYlajh_Z)nchP)21z!-+Ha4bGwQ` z+oNK*gz~>03_vToIvMuuY0}n-TT@2n!}>32|D!$X;mx+4*k1qIvS{l5jc<4XWnO8hZakzZc1B)9W<*`V*y+1cT6V0`xby%7G|?M{hrO;6}?8-+fa z7NhPCshZb?ww$_v#NzKVHB#vZ-mahHOxYfgK#If!2$?fgdmz&_fDiTk^C6}%>bqC* zy}{}+v@&5e$8Wa%c~kva(*TI=JZ3LGwz0~f%jKc;gSS}qDs2!OdjD?`tgn>+-p|u6 z6IIVwIE4dqgMwb=#xYAuoSkW_GN7R+8jGl%>n>gX9m~gW8yMZF*T-H+wTHGjwPPMuorf!U0)OSo<8DQikXgnVsE6@m_wr?dY(nuY2d| z>_DI-`>We>u<-1d7R=2r=z%M64RGz!6S(2ISW&%~Np0JEKB4?<$bZ@xu)+ZY=16vM zJwNNZEDXPZbwJ{|t5>Z)dF$M`5#9l)WK{84bKC+y4vOMr9UC!*{`wwY$aVkfH?kH` z)B$)iAVnGkj{*2S!_5yw;67-I2+run+N^Ag&SYWgm8uGn4g3t)VB{kynD8#pTL!o<(vmZ8=4D+q0UQ_Cu2~H0WU!6X>(d(Nb9U6CYlaLU1 zDgRe;eZvp#^jE|=ew+>%&{J!1Qoi5Fwec0%n8n6Ivx*l0B1@-A^4z)ECnSU*oaWu9 z`{G+?sn53Ob#AeOXZlZ_;;V;~L}}>g$lTAL&%7ylT)9BadNychRdJP1Gb{J^eMnaQ z)#L5pr@j$Q$!S$*52`@*?kzNqN4=Rc`wPj!cEjhjOsijP09yFPu8@$BsHmfU9xas= zDswIZ*iz9egfg1TQRLUp{r!uR$hr;T#*{)^0ZD?gcAXr{Z9sxIjMS^N5!Ufi%t<6h z3uyM|$rR3=p&BZN_MvQpE2#=(BI|>W)OC%L-ti+d&~`hE$Q2JE%qvk%<);7Y1`f8& z>8y>hK)Xkyw#PXeX63ma6@b{qbi?rYz;^)|P#wGJ&aw%*?P|3-=9@333 z+;5&S#%5NajQ~C_#ujgNmskj<)GsfV_T2rTNZxvWk+pljpGA3VSO9KFZ7Uob6B9Nu zVZoBvz=l2ZV|BC)2XiklqQtzwOlh;M|Cu1vq@q8OPyMTRq5++TYpwya$ltRlOwaK{ z>l_N1k1uL6JgSKXI^LRR*+0>xD?ryZhEQ62t^yC)FWGmrwvQDiO6YSm(CTsj z2~9$zqAH~Fc^aF-&AB}G*2`n)`rcPm$m8MJ-dr1#g6o6IGx#3TUbVrshU3^$Opc~| zKO@Fc%P&VSWhCU3sCN%^+5Ku|kqvW8F+0MJJR`k|qkLMBu<$TX5%gD|cpw9OX#x1s ziF*#Tzj`UU0?o->V?t25rZU1-g$l^Skyyp-}M@JhZr)SN7cRMUJMzV6^ zIzO!vU{}lx~mvlV%=$RiieyFsS}N8-+2cU;*s89>o{Ge~e^%P2#aJGR&X-nrNS~wAw|GsX!Cb)BPaZwX4s0^IHSCoD@tL+R z!)i222w}LYJ*pqUBY2+~Tls02Rk;b1>h{(nC6t(?cCFZ9hr)O$H}ryx_A0Uhm!(YV-OjH9^6fXCmYUd6FFsvnrM~m% zYm8KKS6^=U0=mduI&0CE?1tYRIIr;EBNY`aZP*wc$J0dV_?hU3iwg;16vzH*!B8us z>S04b&UHbL?@7n<@?Ws1q#ZqYz{&1RLMG0?J4KUo|vThdjT{cEnD^dGZr!ql{ZZWQNMIW8m<=Y~7Yo`dM5D48Zf?_9NT znCuNynF->`vZRP|E-l(MFA$x#nm(l7Zz54XNx>P)bJY3oy^wRAaPU9P_NHkf%H?Z) z{iZ>lu2CGO(k1=fGnT*Z%8nMmPa)L`54HAVaTgb)4P5G}XMH5lVYBx@tv`}xqm`+Q zY3}T@#SdBKaJ1iR$K#v0cYvuA&1Qcz}q`$w0(Ks_|B;_9|i@5*lN zj|r9Egy0vY-F9xvTBQ?lXuC%HKFs0^nuj6JNvd0CF|k&Yk?jsO+zOfLQnf9MJ9om2 ztjapQ1MuSTt^XadZg$@Ut=sE8&cE{XL38FN9M?{<|!|*kgmWfyP|K zqw>s}j(@XP7URgjLM-)2~WG=%zn=t%L+}MFK}Z7BSp_<6UKkb9 z`uuE%ZSJDS5g_Hdhl#FulH?eJ@v|Q`Ch*)P$lL618%4VT?4Qq6CR<_MPSm1T&0B4= z_%4905P>w#+T*q#p8;E;*BaUJxBRA`?vBq6T_A|V1^s3*_yavi?_$W12Ne|w>8~HS zd_U1;wn}N8uXz}Po955EF0-ABr$3}c*vNRn>m)o28alX#!d z`0&7LSlgMZhwWNFAZ{|<#C7`j9Q{T(U^3}97wVf<{eEtg<$K?12XAXO&g2YPy7LqR z#Bl;NHotLd4)cK=-8c}J8Rw_85(aD|$}9$XH{F<%_a_=0o+Yg7pykyfv+XeiZoWXo z#9LceSi#LBXsiU@K`AYr;UVDk*PAb~nd3oYd;H6Z;P5WrPedPmlMFt)FwbKc6h zTK`6{2z8yzKX3A=$Wv#;_QStIj39+xWTc;hBl!EblR7kyCF zodW0@75%AR*e*VA*WmEkJh*-%*lD`^n+1*FNyjO%AvDpWaB)_f_|0(YNnkvNoXl?l z-Kr8ch~ED8T%vhv=vR%)x1!|oOh-Ul=3l_5onKWyL{UPcQ6krxk^*ECOKK=eRF|@X z^7+xW1Bsg~C_sTiM)t+pW^SPQ!8c{9=zq7o5P>N@4k%QzFw*b#?Vd0aKoA}z^IRXZ zTilt#55LrXDlvo#LUugh7S`7QKvZ*?*^lBwOF+)?BB}fpaHddXkE`A?5rP;NU!FlXufHZ}J zD$NZiB#~<#zz*lc93S$3$9KAEC>*EZPI5s_F3N!=siS7N(F885beYCNS#+*IEoVIe zFPgI1Z!2>U4b68uI~iKH6N!Gf*>z3mJU74%9daxFbPnuqND|f`hBWXCvoO(H=Uo%3 zEd>LIYJcz27!DPr++^2NepN*ZWd>BQAc1`>hspNL0~GyqtfhZL(OP;Tos83g^@j3n z@d>;KI3v-WjA?EBX}Te8f0B!mnogi?GNsHHJ|OU?4UqW)&P89H3xH(g&n6J=9DACu zyqN;AuLc78vp&)gy8hV7fNKxUKH@1A49V`*(r_oIP}Ed913F)Nco@Jsvxx&Hp??QV zIzUn^e|KZ5?v>X!%w|qskefs;4Z6u`Qv)~bCbaixq{N1NB4DGg;ugq!=hUrwl(yYB zMI<+gd~=L<+UY0tyHDA-_j?DTF#Jn{Z*~JhFzFN}HOE7RKRrP{z}dL<{x)!U?*30} zZ^cuZVhX2TXQ;$s>q4QCdiVla;P|(Msw@Q=BzyHe%{~XZ`NT!1A<45IO%(Zz{o5xl zTCa|jx)%PEP4frL0hK;FF02hn18yHOZ>x4&#V6d`Dh;EKn0nW7$+~6Z3b12_u0d?G zx9p+mB+7QxB+mEGL?IgsB$`gO+umel)N!9kj~w5?4^t1ulC}oKx{v7J>eRd7L*p82 zr7h!vPs97R>A`9KSP&p2d3-&P&W-gX-$|;QQf5k0$jP3K1W@e$-jmp?R}CvS?(5Bu z3Y;YSdvnggCG>No`p+b4*C)M}0h@ctXRdZV;qd1Xgzs>t)W9hx+~$N#s;2dL1`iam zt2jD6(JXndLvwrv|F~SuDbQ0W1TITmQuY`(6t=_v`F%(J2%Sn*uT}F)JfJNx zj&tYwdyeYA$;;{?dz$;Mc+*M7fd18B<%;>}bMEhMEwQ3~cB1=3>+6bVSF!^)brT7_ zG$Wc>Sb1m>W;1S5pQbUcZHBMq3Cc8pu#$|wvn~;;0wZJ1(oIxum6RDOYD`aD&b)ORxzbnL1MHqv%JbN#&I8Vb zRUB{IIvy7T!($l^z(-tn*;MxN8-WIx3h#2p%V;J7$0Olm^J!#%~G1$FHqiID&?sfc_NS zN5QBamvk2hnTlY~<=LykALY?(?*KIR8pJ)YTKnKaP zm})AYdc~NBs9PI0TPvi(C)W61|6hT$A0m*J5kA-AxcIFvnkW4iP5a_Zl@ z%N8#jh2qlqN53U6s1N8$*#JkK;$OTVqjVZ-@MeyANK-5krQ;-WuYQt$%H#@g3|HE4 z9I`V0!F3^7RKYpkv$-E)Gp&jQlY^LC!LFoLGUS&=kk|;@8st7tL&#eYGiGCi5V+5& zCC@}@Qch7tXgx-4uVqj0TMwQ?CQ5+0&ht}H`XOEj9VZP#9w~fx^juLH z2Q=uX$gW9MoxqH_w0Au@mcfoFi~KHoBOu)Blc?1ob+Yb zB+~^Z!H{UX)B4sQ$=iNXtDnWnP&N>4$FXh55z@{piZ6QpTyh0wbihG7x5ax*fQ;wX zPHzc$a%Ic`QFaGE-cILEpx^fO3R{6l7l!)xCnp->c!0yf zt)C*|*iR?VOj61AUtD7G+!z}CNYG@cJF$PUQStt&!U)Png%6TMmmO53O98?6U;l7( z;FQC7jkILiW%eED1t?{GCMkjPfZyTr zgO}Ye>ZcGkL%jjDEvYv`x{+vUkk3ExZccl1qb=|A6G2w4D>_k6*QgxZrJ!vFhk4A)w82u4=R4?CDq==b{QOTs^MY%$_&-d75p7cv zv)q)$$UyTYZ-dN5WA)}6*LwCh;Dg0(ZWu&P&a@DA$i@Rz9tJJJ&ia)RG-IY{HfpI1 zSNpO~7;b%9YCpG6I*9IOSI$cwB@*|@{O$+-#HyJ(o~57`yXG-2Z`}n!rL7_Mzu#qR zJg#~DFwxAgYVx4%CnR%h3|G#RVv5M?iE(; zHy(?5g)Exq6i%aA*rYCFjy1rhMa6 zi&)c9F=WYkOhF&8aH9aBfZLCL;q|W?r6ck(CWmKA8O#5WwJ8tYtwroD(d*nAHtd3w z*o2jDuR2CN>*^)<&Uyr|*oS0Hup1?0%%RItK%*_44gcxkc0VGeX1;n#pw?)6d?dfc zjN~^xA(OAc?K`h?a`!=HoDCVnAHetNqg<`)ee2IfK|SflzMgj^+y=4}VWib%JErmMOzKtTLHwgN%t{(xyG}qR>C4U5I6ezn7bOx+ z1oH%aY4^3j*%5zN(vBbE(S1@wiP{A5FM{^?zX;lXv-?#o+}3kr;>oLe$Nkt`gR9ur zfN8hog+%R{RM)!cnZk5yk%Y#6^YsubC&5X+~sQwM8MP# zgg|WW>^*t$?E*^~BlO{Y$A%$vVwK-P)yMHcebn9W))C9b5tg|H4CgtxuL0T$x4C-$ zKum5Qnu*s)I`mABxmufUrp+7%(fG{|(g2{c`#$f5p-`@2#?(wt7$vy#f70CfP0I$0 z|E6V|n6dl^EE~Y@q+QM(^ZIHa$^FWMm?1FSn9^(iH@D>*pE&A zmmk~K>Pql`(X!>c4*t?(R};j}Tzc}sy=Nx5Ah#rCEkItJ&P;HsGmf-7p!cezgaud( zq2rZz4Yg9KNn0Z^n~MvD)3t_sf<{(ouND8$kEVwpx9 z-|8rlBLjkM@Fb>+C0wuzaUjPYtDg z3p>ReR235FJ$1UWMGd~IRNtdG1EeGR#TA+GsR~kO&(2)is&eL;qUlVr{xUPtDIKhE z3iZAXS`y3Rze; z5gy-$XNtb5uhaITz;g%Y7a7JkYj-8l%9>WCV`vrg)ZHa6YHlC%5B6FGz+Sr|xKcd-&utc&l&UvzkGGV1GbyBf0wV2eJ?@jm7GVUHO)xmjX*nGot41Fyu~`*A~41RqlK6stfEyE8mL8B)>4> zmhSqnOQ!wfCV&xpdl*-ylF?&H=Gb<7g6K4aynO_D-4K9R(8AtNe*suGs9i~aL$1T_ z659HsZxvrT&g|+t0n*4f<$Vu4NNqj4^QhJ}2J~3yTY;eBQ0$l6!lVh)Db}HU!FC_M zt0mN%tyO^AE-WIHSM4Z7Szx1$PtFanc7Lce%wt5(TDPMldS zzI=2okL6aEN~6uDY2(=+NJ%6t4N&ay@a3(^~=;>EZJZwUiDnw$3D|iYTwz(?OPcAu>2nU>p6Z94h z+shD0Ptg}xAF;2j;QCP>7pGc10@NbAaqhk)@rpxRcpl_jX9O=5Ls$T5N4eWZgli2! zdjHjMmDD1!)H_kO^d)&RgOC$H`C5>9+E5o0p-{@-Zi~mAb zdl+gE(00fVQG}(U7t_Rm#&-ntA(b`9acTWlmCH#DV9grByFu@yxQulU%Rdik(iM7~G<16nq(qq5P5NbH|Rsk6loSi2i8W_Oy#qv+kPtVbR zEv02)VF6j9T;`6bWP}4Rve&TQDRom^0syiOj4;8gE%Q<`D7c?}DDa--%1NT_X%WZ3Xc}$Ba~YSKmLm`sR+h`#GWO zB40o#I>&aD3Ok#vya5JKN_8dR%ao~1BF(`Zjn;LKjppr#WnsoE;D<|BTA&@dDLw$n z+NhNDN7y}%c3QtVGF~i*;U4%z8Q9rUR5D`-aH|M)2X04*chg{EgdY-ZH|y6Yk70-grl-716Z=|b7b*^ zO0*OLY{b(?=5q&oD`yiEEm$ibsWkj8RPU~7AK|SgtPDDJ4r|}Km=oz|RZ5)8OiKHm&KFO;+z@%v-_|xd8m2A8U#RB2S)iJ0dzI)-{|VuKj`X)6$ql+ zb`L_M^3`h=S0BwCw`I59K^f&(l6(Uej`BptAfgzF9qZFR#?&ST-!^XV7vCm(|85@Q zF+N-2Eoe4HzCHe_rotnK6L{rQjf9+xVE-FG3EBu2@}Gkdxn~1_Ch&NYhPG9*9v?2i z^VCb7hdPiL$a=|IL^i}PbW1VR$2kJltd8|&Saf1xqngvp4Daw>B+p{w676x|06)R` zDf`OE$k3dbUufR$wZz7+I4_;{a)E2$i_hEgtjf^G& z@^~ye7We$7Tm74q?BRd;!hsm^KcczgC&vXA_c-_U9!|Bp$uVR#gbi2M4#YQx&p|4M zrvrxRFN`AqAa_C_8+!~N7w`+}KDQB}75RO)-iKne?zUe4$olL@47W_My))MD!3yu!mFri-qc4&ng@<24TbFnL=&6<7dwS5*XdwoK2u?cJU?W{3--?`f$36*hsV6B2Q?`P2+A ziB=U9Ds4X!3!CgW{@a>9L~BN)_CHwD*EMMRi|Xr*FVqz1Z23C1jc$MZI8$tnI^S*| z+<>(Q^Boq7(Wf?;ID=y*Tbpvj(NO(JPil7Qf62}(2$+VrtT5y5c$q7E@wnRLl=oSk z6f!$}xyD1nN6`RR+8W?(>jJ!OKSJ+(6M!TCP)X|l;k%q0zO}jZRvG*B>3c5?+{blF zV3~!19tN9A@_86HyEPPhO}eCPUlYs+r1Q5;g}#po+WOFM_XVGfv(Nlo_vXjQI!pF0 z8{dc*_xw1iBy5x@{#k?2*I6|?8TW^6ZM)m4_yFO~R6|wbl+qXdG~1zw#KlbZUtnwI zUtsIYH$eHzAYki@lE~GoS;aNE7+i2xyNz3*)Nc9EMWoAkT=kas3mdzPSZ^U_O@|ZS6Ax0XB&p?yaEOx#W|Ab8>|AZAs^p zl)N{jCOwW!B4cRE&W3!Y4;&teLVf3!vLcIK>ejD)$7{Xr8xbeKEE>){heo9A)xAD2 zj>Jq1_{nT6nU*+p0RUm{JjgYjF6DO0LW^mUUTVr~)_2s77lUrPcLZAML@YX}yB}V> zM4YHpneIt&*;H#Z<>4_BzQi11)KXtr=LX&%Ebc>~6pV#wj29Q0*c%yVa7LCk-|Kty z&*rRcGe3<9Im&vM3}TcjeUa|*bVbZP%T?0-K(-i|zU(yUA4>^2OyLItc$dE#Pf(E?g>xcmD2K9HQcoFvG+jd5%vzWqVqoaJ6a+w{1JE2BQ$@JG0KAxFT# zP6+!J+|E)@X2}qlNhD@^dipFspq6m%KnEPGpDoytrN8b&W9`JBqot(OD;e_L8yWis z8VOAz8JH0DDm|Eif6_IMzYFMI*i{qpE-8%NA|nQ5?br5)Pm`otQ7^EG80skN!s}IL zTM|o}!XI0&#hYz8b*!~t)34wc4}qOjp?WPUS`cNO!R4|#IXB(4Jdl&Y2!Z_Vhi^y~ zi}inF`_ySdr>P1Puz_H?O4_wOMr$+cWKfjVXPdf=T@;3wJ=SZ6J${(ag{EOWlAtJJ zsVw_B7&@e(F&GPJI5#;G&7DtU$I&jrHS*Q-9IbVRyYL$uUyWd8A1(X0OL`~-(O3m-1&KwuvOV8ENgh|_K!uTJew$b8_ z9%+X4DB`+>^q|dNzD7FChSV!NLHq}(oyvlCAR&e(^=(_FiIv0PP9+;DCDrPK;WTXG z4n1qZ6Yi1cO#0_T%6G}k{1Jsuq0s@;A|?{jCGsQCLePt7Ydv})`ElsRq5SI$(m1(! zOpT8;9>3EU7}Olj7&uzv1KUxNNe>>{*Bm$A-as{DsO)RLeIq&?g){PgycOW;dOkxX zfGgwJuHGoBIY}#f=h??d>s|b;`H-*5s&mi^cFQq>X#?|QK-90?)~5Duv>ZRKTnB)3 zTd-KiDAvC{uiU7Pf4Gnlf>|Q|h{tLGr`sNGQ<{e zM2qxNi3n0dJf!06mzGr)9{=g{V9ACs%Zj;FlglJ;Bao;*#lg=Sd$JpZa6xD`@Oq}Kyju!& zGzNaORx8S)y~AM9mKR%Md$ef z>46kwyuf}kJ)o*Shn*BbdX}T7_KMR$Tx1qBs@LK0s|QGbb@Q}@CK1h*ky<|zGHGk>11DITXXzhf{T{fIt_cf&9zma$*mXd31^oQq z0mO?zQToRK@d4qZ+<)NVhQN=uwtuLi$~uvI04sqVV9)K505RY1>%!ShNL?z*Wg*O8 zZp=0F0ATMI!=y_7hYgF2@`GAiU5t*oV*tfBGuk_Ha!uYtxZg3~EW zEM1K$WJJUts3sm}zr@ujLvu1F>0Ez-y!V-1E+vd(mO3@16<*KYF#15!z~w($4Qv=v zoCfwksnZ1fNbqSIIZ>5QUe3|5kDWY=9DFl5NoLZjQe_AV7$YW;nNXs~DN1zrhiizY zoDH|gScX-Ek%=wRMK$K2@mnf%931R77vEHYLg~ro$q`3RWct93WG8v_r=# zFfBs@5*T;s%7TUsMoa$TfCE7BAR(4@rBZ5W`@kS^GU%rkRNj>t(dgH1d*BzK&Pxoj zYAawE`LbTdDM2pyA!ECn%>x`LvL~IPsO?1@{xD8|Qf$xN6qIXUHe6AyOF#WAUsS^v z*^GC;eZ%+z3H#bq_Y1<0z#QjC^)2>lShniWAdyit;^xzys}UDXVLOL{oFqPknw}L2 z$aT2m1gM$$M6USvZYOqK3Lv-aV`8Bcn#*3LAaO`hlqe~w!gPUACt8j^CoP^NKM^Qz z0Vy#~RA%vA$0g68VfAJ%O53DT4^hbslFIjcaH*=bQOvqUcF&9PZEo%U^rzCijC_i0 zLxp(q*K=&RJa=y51#)!5TWztFk@B~m%`S7eJXqPqfgDW3ip|0|46e&GIa+$F@3nwR zmELW|LNdxteW+l&U0#coUtI%|sU;s;X>Vk!-H zH;{*hs}QNzvVqkHu=nFtCt`}&$=L7uG%kK(142Oau->8E2hr}cJrP}Eu}$P_Md3H| z^zN0Cj``!2Xc~lSJ8+vs(l+-@24iUajwl~z1KIg78?7_hML_RX)TQUq

Z^R~o1g{<2-!1o4@W8(B5=l{1J@7^*kRBjly`-Yd8g0D`v5&8CN{^V=P&-XT z_P_tKd9?=RqExx*-2WUZzy6rJ(-i$-f_kL3lsJqzRfwCDcbI%75%-~4I%tOej8Du7 z`ZD{Tu*E_p)#$~Z>GZyEYuTek*Fg?)k?EBE3^~|?mlar5X zK|`UC(oz1qV_&ly&{iAg_Rs;vS4x&Q%!N;tGhTAS(K(MQbk2$Jw89Ro9?$%EWh_LR zfdBB@D_*^N+`L=4<*iSqehG{DS6xat$M-dTE8ml4%g7b^k=}GvyENMzAX1;cTPsVA(t#FH8 zJf21CbVK z|Ceqw6TsMaAZKRjB|j%H@S3$xl%;4k1xsQrH_09|L`5#{BPc_rQLCX7L@e#km7kjK zN6h23owm}=GhHxke}?IOsJn0k;sx&-0)U;@pha9s5Iy@EPighQC}vAw|Bh6z{2&Kh zn}Q13wT7u~;~S|dyU#RD#b~CU>CfzT1Uo$9imPLYkVfy-`U{{C%dOI{N`Osdh#K88 z>$b(O6T~HYBPVz1MJDT&Sj(Zc@8V3oS)Jupx=KEt0o2#|b1tCLnEJT{q!QnpcBxS- z!_ruO)7zJ?B(SryzkU6>tCm02t>Ey>CTjMv~c4Lh>aQvS?kZvCt9quIy;$R$EKU~zLW#CDd z6ctaVUA~Eo*r=W?%$x?c_et`rWW{FB&Syh4Hl+RE>PL#Y)~)Gc(Kp#G>Zyf+^stv4 z#p_BM>z3FSrf(B5L7eE^`_%-^3*)(MYn4?G8j|0d@wsh?J!D3$pPuQujea07FVKN8 zJ)wH!(|e`kATA0t+5NDT|{6`MYCb zjuxQh=kQ~*VV_W`@-!|^*rY8^u&r1|T}=%PbshCe$z$GNU4trL<;UBfYA9chu>RJP zq)b7N+u8oKWp;kYTqLf-g~lDSZTIrbZHq;2py~4RbLd8>nvnZLN$9#A(973a7~f}X zry`M<aB*k%zEy$mEFQIc2GJB0a?X&rxyEM%n95KNUH1k0COHIwXgUf`LZF-R3FV zDXm_$RT8`+@U{!APiHA@lbB_nowb&=j`}E3NAU8}t2kM)Aa&;?g@)CG-4=tscu2U~ zgy&A-Y^d-?wBQ%&Be(9+CCmF0-TCxgfLw~y7R@EEIOr%6F4;+{+wj&L<_KcONOWa) zODB?s5xl_~uSSvI#s%MJ)yQNo;>6f*dA*#Xni&MGe2b&jfJQHAgbeOOOFJd*kAKme z-#_U^{d6IEgU!hp&gy_O{^1f3BF6&$v8(Tr~@Ja(uvu?`;_g|9eEcJ zNOAZ~(^Zl)QlBVJ%ISk>OkeTPadfL8sjZQ<-P8>FcGZ{FeRIO-)4;j%$*1*8;A=#h zRt)tIn@cC&z8QakChpeZPs<(JRfdbnv)gqUvp{sPW5YR~-Ye11q|)Ugab@q)+pg|) zKVDcfigGS8NlWJrQ&iU9(f%^%TF1-2vc&ViVr{5Kwp5Kzlobb2cULX%iIyaJcxspu zbB7BO&@DI6-QHHCxf(nC<1H@{xB!LqEfI}pAKrFFZkfxawbj4zxNJ(ybFs+gHYG{) zQSb}A$DN*YKux(&46n#~t|+MyX*8^kAhVHd505aP+%tX`SM*k8{2F5IBkAy4{=Geq zQR2aB+I@kV)vqqy`)K<<*HL0~3L*w9zC*1lkMl{VI&Kzm^_#8}p^CAtK`XK;DG_Ux z6c-#WUER}}%RZP8^Wc)=BoVNdIREl*cCl>yiWb6G@z#+khnXm`mh^1I2lu(#nJtm5 z&`AFA%Ff|TOZa5rYqd$USqK5j^%%hjuRp67RQ2&z5RT*`vB*8L-qK*!v!OJ&P}A62 zGD!bI_sR4J=1X?3jGo?|9r403kMv)nX?hxLx1&8E80pn!#H#JH!4Wtil-t-ssVV5h zP+(%fhdqLQb==Z%zccl9*r-5KK=G%-R^tmy3;WT&@3$4hRhqeXV|kHFl|U%y?`Nyk^C)N-MUAj*XaFNS8dBf5T;& zzlB%6J85OXlRWuQS$h8momhttYXmFfnOg#*oeCdD?LXm@C95nsB+M@9<(G;Z5VLA) z$ShmaIGa_L4U49}D%9_*mbw^_YCZcnkM=jXD^}1_U5NeN{MMp1_JKpq^GJyp?eq25 zV~GBjf@1wfvd%iH;&SnKi0i2F*_wE9b#3Vk^jr}lN_eAAlxR_7<~&;a6rOoILFsdd z0@_Pri&z7T&OY<(@msHlU2t_#jIH<#K1BWS1e7I(@=55u2I{OPhXJ(inuG_2tuq(t{)EB;(=O z;;+im7iul=c4%~?%kygH0^F7^Eu}S zIPRGrg>+jwC5K(^c$F#R*7ZV`kGO^R(v8od7fJ#re9xrx6d$UDJd;uTI-R4lnOoZY z09V`$~$Z$-HH8}{>z?nrIdm}Gn(OT5(ne1}l$yn2`woJXiZolG1f2n1r`xdi<8fy!g79W z)o4lT@Nefh?k07gFv4cFHry=GVR%cJ-hJPr~Y0%n6QANoNZJZ>nPoV z)=_uWu;xNY*Wnv4B#JLX%{EY}Fq8?meYnjx-jA43l*wb65 zT4Y}D@WEo}y?GbjS!41>_S0nyLSk<%Hd~Ukd*v26lj`>zHZl;X{ZRpx`!bCEda7+4 zw;E5s%L<&kLf27>?S%d}NSzlbytW4Pol&L>bjk33-9W+Te#GiGwC|S?s05DORh@R#khqVke_(+9P)eW$5r#p zmHgJ%p(l^g&mYIvOn4Z-dcWKaUFx)ZX~5gn=Y3fF46XV8>x9}yo$!)Sc0X3#4}Y%{ z0#Z~x4ODFWpb6u9udxt8^3H*?Kp|K7M!5qfxPNfOP-nqSPo;(Ck0bwmqm!^$$rG9o z-2L3;ec`J2JIqKXeOfT^N4)%*(P6}ZBBL8Tl#0-gU;ba5eP>jYP1kM$7(gi^Doq4M ziiO^5KoJzFQi4(fiqebH5t2|8lqP~8H8knHN)3wAk>0_eNS7J{B&3`hpXYtocg|Yp z$2tFQNbZ?EdnPm2zIGXBIqv>ze7re=WQ^01m=V6~-HFy)>kLi!=9pNGUN2RS7abX5 z0~$N4xUWB+M*n_i2%TYj;bK3m@we%y01g&EuH{b+IE zr7tnleH-$DzV*bZ^EHtN>42vz_8mRTGyX8Jj$tNO8gdRFi{}utoRs+CtFQ1gj9|M` zy$^WIz7Bu9HzU~dVv;a12S~s@2YGwB^xU;&1D?r>r;hWUcJaJ?5QSQT`=$;o?yz^= zH1f$CH7*;%&!M5b)sKS4UcS#NF<-44>>iErJlt3?xn0(iIr=XvwEWpcyHOBDyhc5EiD8=vK6w3n!dqmIR}PcM#v(;i!h(=>9#05e zuX@ruZRNlCK4)}`41~`CS(Rhg2y^`O8l0JbWYvA}<&GnHz#N6n?{CaRORS--rhNZQ zK5I2a4rHj_M-p}ynL~?ceV(|x`WEd|$VX2op(V791DJDCP@uq)U$D1<8o|y^tFNfs zSlQ`VTw{1XSnouYDz%V_%P@aQzH619F4bK=O!CAdT&F-T;iI5YS3~5f!5hl>PBc}EhUcd#-7H6{k$2$xS?|drsu)AXt1o3EH@Sm%x7d~ zFMNUktCU8K%S4=hoezk64G`DhM9}Gr#VK$bljL1JhmrgOK8v|uH;ufDTEGT%R`wJx zgW&Bm!7Md@9Jn<{Ms}%=WXlZ3IV&4wu6YcS_v#z@Pxn*cmrv8W$U=Ae#M^}w?y&#< zii+P%Q}mqPm~9x5v9;yO1i}?xtB?tDL}pyy8^@4#3H5W=&CV`oyeM=1foru-nU`QT zOjyP~r2gqkN`c7PYK%dJmnMn~v}7V8`GF^W<*rEnxn=B0uFM9{*MJS?XKzU20@X5@QT-u*5y|>Dj^^CWU3ROd*pWmnp@2E!1O* zY$*D8Vf0}Z_h3${_&LE03vOH$Fwpz9EEQ!8HH!3yc|V3{&%5JOPK(!^&prwZ6lg9F zJH0M+QW9BnS{lJNEV3+0n@p3%g7Ob-u+&}>9^%*35*d)`^48!yoe!~;1xC!TjB_4J z5>jBIwX;W*`U|sP$O8{Qql^(dr(f%~VUg4z$G7;{UbyJd6(TcGq~!M7#qz|Us^)Sy z#u^yY13D{;(s#@`S(+|K{yMk0Yft+=ur-2nPN8yQl!{P{d0v{O10G7*Z`9XYL4$>? zQan-xw#je|ccVbXG+&5-@yzy_OEIqR-4SC{MyWQwJ?|$7#sP@J5dYak@DfljFJ(48|8{QTWP1+(GkGPVfaM;GRb;#~=Uic0^j`e!$Gmt=AG9IcC>1(QdSC1_=k z{^z?Mh>5(CKt;*c(ovRfa91SgUi-bLFxf9Mf*})nej?D5H#9%7*`z~``=|r^WMU;; zXcI)XjJPrjzC)QLm?R#jLo)Z3jruiem*Dk?vm;QGp!E|T2}7_sB7ZgEDDr8CElfA| z<8) zv_89;Bi%P3;{gS{z#G7?&z9Rm7;;AzvxiK8bfx(6LPY+Y;!nrN_F#?#$V*LQ$e+m> z%%LLGn2A}jStppvlEcn^CQQ?Cv3#8*oE=Ee>B!S_uI1uev9DJH8O8N`qD*rcTR)m2 zMi1tj5Z$1A0%;tVe4Imgx#stI-Og~Jkxzp)KKSQqi|_P}7@U1*Ks!HyC125sIpi;; zx8dX`FT;JwBOm#~d`>Tx<4Ck1^}6^Cpi#eTVX%?ncOIS7!ZNZwi7L9YN%CE;4-T3v z?d2IBW_^wodGTlG*JAVMXB~a;cTV4cdms$Wcrx?!^rgMVF{r&-NB1dwy?K?#t9(-a z%_Djc%7xw&g}ZBqxT<8i!_H<&_h|N@zd!{F7yoi-H0ZEA!gR8lbojoapN3*`zmk+6DR>L1q3rS=L@dvdU zmQwDGoQ7AH?m|yYLyvLO2iglPjOqr|ATb+{C{VjbH5 zY%fP|5l)^%z7d?*-^oSOZ14eaDZ@mfO$pzAdG%~WKe8+llBqv8y|?}}TQ^zi(M+A| zi9}6;O3u?KJK2KIL9;cEuJ=WiZBSJ|KwSRI{BFQ`F@8B2sw428`Xd$g=GPXCo$4}V_+MkfHN)>0XHfDeDL#^K6%{vaOVx``R~p7>-K%FG7=V*Zp*OIg3f1*Oor!q z_?^j~O&BaO=^D{`+M1IvF-QS}_}6V|1D<~*sgIP@rk+7S9cWYROQM@ayuk5#CfBTP zicM@zy7C0)b$MSKp!Z3Y5a@30u4|%!h^#Xk8php%bAY(jRUYO1&=`LoPN z66gFh2>yIW@X_8x&ca5ji}JSqwX_!iSHQQ(3IbiKa+%TR(w+R|8B3zB+}FN?YkIuZ zdK3H6b$siLY;VHJTvj1=>qb9G3)gcokm6U0V|pGs+9-{l^y4PrzQ?jHJg9JN(ulK` ztMjRl6gq6OGb13OLLag*HMy(IOsSUZ0m>r0g>E5|cK`qg0_B2KHa>p`d3q(?v5R7q z%5(|2n*FDP2{%eFyLN9WDW_@o(0^&%DP}|WnNU9%a{LO2zcl#Yrw1pPB>w)Z>zWPf zZ+q%yU|OcX|EfC4Y4i8tt!WzwSPdW$s)Po@37U_{hx>J}43R0Eds(bOE4QFcd(v!a zx*+xY1vuVGBub&YA24J-(>@*yR|CF5{xdjWGW<((lj}tz>2B+%Gd{oLJxS%|v+ z*~iL8MxgC(*kdgot1VK#dF7)Ae`XVxd9VgVF$mB$A92utIp|?Ih0l(=J5b!RLL_U4 z#Td(Ijpq%znhcJ%*9?`)>@fbww6o$+iEKZ}c6jM|O7vR~`qb8*2DWX_dzlaPUP{=? zWwI12ceLKNo;pn!rj8Dc7Fm?5+jBk*NLxeScS8n~5i^!&iN^vW72>+a2?aN&fiD`+~Yx3$eN3R z8m2yiJY8+Wt6GcxfVaY`>q+<`W(iVGXD|2dDU9WR?kuC-Q)bWr^bwA@wq8vrez>U6 z;5xPj?ejX6&2sDWzaKt~yCmw< zw-Co;DAk?-NzMQ<7i^O9Y4K}g(mAMxh6YI~Y>2k2ZARW(7{yi(M`F_6Gw@a}}b_$GAh@*RdWOFKqBlOXL-4me+N$Af{d6mih z={t#?6-ug*G53F}LxDd3eFrzmQ#>viV_mCY5}%}w{j`+g{IxGx`gXBd>DN5H)UV5E zq?r8gWOX(ZI++=K>5{y4I8QEP-gh@b)yJ1g8b7oi+U9i@BC=Ud|1-Z<=u1`|#fauE zfa-nf)g709bI2ZuqOY+NxDeL5px9=?L3zS$@aEGy#*)d6MUr^bhUnMZLAadiOS<4Y zPt~Wqc1xCSdr^ZOmA{hMml=*8wdUUG?DYYC=li&$8N`%FFg)hmvXNus;0 zdfl|>YyqL~Y0ypCHe2scW^SvqW0{XTUaVaH18$3Mo%mO@5mV?g&O);(^85A7?ml>< zj?AZBRT%O07C1iC3?O5d+E1P7`G=8To{ID#u-DY(1$6ijzkBm1IEi{q`eQ7 zzZ7p>n9+$~WbMXlKtV$J8ZxS)RP^`&(%x@J9dgS^6nUoOO?GGoqqW6jO1=Tw zt?z^6ty!S#>QZC#%!btThxm8_9oV5+8IN?fpNNn`GUa!7{Ki_`&pgD5ER1WaL{EYw z{_+Itb!yZYNLs_^li3;XHly6m*9dc7iNAY7ej}yKzvWw@mChSD{l*#0GRb;{(|V8n zc1F&i!TDe_JS-5=R4|xXH2Jn#=g(Ps%XMY_1V{Dmz_L^kY?bt<-s{#b zY0OPYOx$`TgSD`E)--U5!})_q&ui&doZR^ymBExPA!ZqU61IFM7+KochM9{`c$sxx=zT{h`1`qBCq^)4c1zE8`Iy5|N80ZxxfUh)=^^q zJM?5wu^iibHRcerjRO1znH(K#iKo57+M(B)GjAV)UY%J87 zeJ9owqlYhg^s`Yl5Bzs44qBlv-WmnjhqN{^cw`XbwG1Rfq%PkxraMGk(nOjD#gKH^ zb@L8wM&IZ2ZhO5n)b;yH(59PwK$p0r!LBjzQvVx+N3y?wU5;?;nu*@`hM<71Pc&HO zFF;;6R-QO3c3zKChXS)mtNy$5ui%eooICbi@_gnVub>0D_KU(&q8Y){ddh2wYY@8p z=j?M;TgmLpHg??lH{SCRp5S^{jbysh?l)dToJqSnluY$X4n0No*xTS%h41KFD_i)0 zRF!Ju($BS=59dC5_5M^4^%0w|`UOJii|;3XMf!I1e3yT-r+&Oms_o@W7@YNId7+|| zzv-y8k=Xy$lotngP+v8datye%0Z7EbkgP8Ce#wh2=F<|nT+7-&ql^JO5^+%`Gq-p3 z{s?DcT^VUXl*#XuCVove+Dc0@OU|!$h#i(@J(3oh`sdOsyY#`W7xG;L<6XB*RpM7U;_r$}eYe@ypeM$mc( z`ox7-jNF1WYsdCx9-qQ|M7A~M*DB#z21^HD8^a@i-eXPL0vsdvwrMAMoq0uUzJw0@ zl22P!%^caL8p)n3|Qp59q@0nL+iqk zD&Zdo{9B6$W_Dp%lhHeSEnE6gCknS5Grb=$%Mm7!59J-~-U!<~ z`oFr!;wx>9@A5P!=3rOtE5wp*&LNHl&(&L95o;*Tx27$*{^jl!sSKl!_v|SeK9A+M zx&wMUxAwxlbXfld7o0))amx~W4^nmIQ<2v1cD$8Xr%DmiT#9m;650HznH@jy8E((@ zM++(!Trs$|7T=WeGR7IYb^ZS|pm5wk1%7PVVDj)`4n||OU7hAF#4r>Jz?7wthH*%` z%Zt2^|4NJYC$4!htT$sb@gq(rHLsz%qz6wxGf$UG3eRLXt_B|i8bI0DVzsCXf5FlJ z18_S2zTG*Aw!iQ37o+|kFxZvfs~px+0bUrs46q$jLEmu`5vP)|!DRXf+_dG5A3Q3j zTfug8!KS}GEi&8-s7UB)(;Xhhf28FjCg&L}dHxK!%@}R}fe4T0a`ggkIDPc(%@fJt zO69sufKcS1Da+IY3>XWO;n zrKH-D)xjVNc>7Jx$&{6o3D=Qh*E+kYuu@993xko&e_w4Mo{*(9NTLCDkMK0eG(NVt znpEDjsl???Ib4XX<#b)i#~_AzOJSLG@@>aZE$zM=#$kqX|JnT<;?r-!1?}dIA}~^2 zL&2onkuzL4LWxGLOoAN_*cH(XcpXc;p>3ejdNrR^v=5|ffN;A#-jAV@0dk2rj7a2St@8*pe zZ;`hU@2a4@_2R`$Eq-%hp1p<(4xptOC!-9i$snxvrXKBH^)0wPd1Q*>y^m?^z-Y$7 zoVfv?Z@t&1)8Ni8)xGoHN5+Mg4OP#6$GGm|_J^N*O_6neZfmssxIedOE-ERCm^ zZ8FhZ#7fO*2_xFv8F67W)}rK)$k&(4&B#``fJoz}gtHiy zX`qS>LA3&Ba7C)kXr(hW8yOBO6{~ZZx=aoLrv%f#FCk_9v zY6>MNf>IefJW^-*?62^Ox=2jxur$u z0^!{%VP)&eA3w>cYj(f+XkUP(x^^qUmrfCrOZjjkpo90tSLmVA9q<1LyZ*4dl(8`a)~d8w&uA62PY=W-;|@7vQaXP$BkxOlqzfU zZEvReE)!JG7NI+m)cK4J+@l#Jyoy3BtpVK?4pO`isQSaF^AOox&L)KVl>Z#rW_=I5 z)R{7*6wluV?*1?gwwTd&`Js@083h}g5v1}ZTHMzHh056u4g`{KDyJDA$mIC+KK)e` zvw>sHm|#fMO|dQj7e&7<2ML#_i}Gm3>bu%4e4NNNT*Ov9x1EK*-I)eIscL24&>izt z0@)X-E$qul>`C8(o?An2Qnc-d5581kT|86vLh zmpiJROL4i6nPCwz#+ULMHtP$-3~Iq_nv^JZ@~ZQy$VpsqCsc=M=`Qr z1>ut44`C|y(;pwnKb@voA1Vws3!e1Bk?Mg`h|oK^*vwx)vu%H1Yu!be1$jyPw8K$S z)IL*tQ`sdq#VSL}sx&70k}f&37n&zWx$f34>OQc^8NA#v z5IxY0o2Xdl8w^A^ffu% zzP!m^B2GC}q@L;oie~t_SnA4%wP=*Nk#_6UN4^ND2yey8T&3!G@#PG7F_x&*GOnB(*z zDh@b3Vy>$wtt@ZCmPjAenfh#&n{dx#<2r2Lk|J3Li~(^UDs((t3jct%Q0uio{SV~sdR%pP0XXaskBZg~cEATjZ}9b(L@fXze4*^mRY(}Vn-BAe|v(rirCeloDgS8W#H<~IxS zyPKX5AFud=1%5jkOo6pwMw&Wl-2N%A6&Lu5fFShTkEm z9>RYI*q*K3XtlGp>@Hr}MQ7mQzDE;t)b)$hQAz#>zh(P~TdxZC#u!Tcd$CLB6+SP; zGkie}rCE&GNxAGZ$bF1*Vj+KjT`P@A^OaTgiJRyD4n`mO#lgqT@-NZ3hP2=opXQCve4h^Vai(J3++cZ%W_m1O_T%S#P#Wt^yr3@%R5vlu zmutv;4v=j+G9LoSTFas&sbRaS+`^zvkuIj>>l{st{S}kAHA;e%9!puuW-g`X;^T0V zPJ_)Rr2Yg~upq7Oy>TIv9PP6oI08MCwYA8cHp6*WIZAT0vQ|GiO*4$qvD<}p*9552 zduS&qnV|ziTb6b;6q4@DFfQEx8bKI!Rbu_^tevfHV#UJM%7IwR8pUwJ?J|O zewDTL6vS`~+kZlRkmx233K>5LI3=@!+Zv|>aQotA5MdySSl&eLET&f?BJ$?#(blx15!C^~XVrLs9)cqp()u@HhWu+)^j#h2r^*PIT#$M5jf* z?#ResW#E9b{kaFMt66Jco&A{OL{)rm0>(d1_-Fk3$KwZAJmLt}+b8p1uIM(@v*uJv zh<&lyppDqXVlb9UV}|{T+IcNYL%q)?KNPJV@PJv0Nkf&v2?7@4pa>TXL)Sh)`jhGT z-+S;FF<+)hJ*gBJD9-IN*pdRrbne9Oi}dpGUI$&hBL}DB2bgBi7f8C&U!?v2jnJ?1 zPN#`utCaz-fMgRjXX(B0Md|Mf)yV|v0922Ix`t24sre5x8dfn?Vo@GbV7Q>U$|rvV z{rE{9V%> z(r&Nr4rTD?iG6f(HNQk`emlrG>>z8?H#Oy&S=SLu?m6V{u;{bD=a z+UVq^BtvEi(J4Cki}tY)D(0v)BRJVcE+=g6EW@t`4(n51VijXv#cx~FHI`}=Bo}~2 za=~N8FtmOz;6#-PMeMKAf~roXOmCy9%{G*+aS%I|WPi|>rv(g1p;(XJf0nN^T0)@0 zmUI5DG2$KCqE2DN5~y>9?pbBs$Z_J%&k1iF&%1v3@Qc-Nxz`B5Zd1yOZ^ds zJv$yWJOzqhdbfy)oN;T`D$q*uHgQ$HDcxpr_&?D9ZEMCX_i}@!dm^DSd(zsNhqX@b zJzA;uApoiLLuQTWE8$MJC%d9ti2O?o-$FAs0_gtGmrwSR$w%NT| zMV3Pja|67Yq%xRpTbT+t$+pQXqA)p|3(Fd^F(Bi;B=5W7ae`H=Z!f zwHhN@DP8w3`yPG2bDe+h)Y{fnUzxEOF?#uMH&7N|ODp#YwMV#)JfjJy?8%d4hdsx& z+l1^F{ZynyRavqXITZ19t+QR9YC}Hz<#|30akX%O%|@wh6d=Fe)!WY4zzu&-J`CGWJBY%Mvkdu-8SG{a&z~%G@y`5S z-T#h{|c{!7kEjt|$-5ug?AVx-6B z4ig2v#vwYfp;U4efZ5QCa^%~Z4_g`hiEM5^H=G%Jt2kwznE=ya9!); zq>EyY*38;Rmqsn3XSWDFQ{iqY-GW*ioEE^*W(Q46yR z=CvW&HlZ%97yWMc`2=MHm4;pw!2_{EQ+Ks(DVgX1qN1W=9823^tUmU+ttkD}{f|1{ z!3dw@nN;@Oyzq4?jiHGz1aU|tooD#sgfe~HtCid*p2ckgbq}tPZaW+FL_kL<-iEek zCPc2y?z!S_-?q{hrx-=i;AY51!gQxTjEb#Agx|1}LbX`@#&WM6+XJY7?STUewkj(u zOCvE?D}POU3JkC!Y8n79T5W*tH_rg4ekZo5J?J#{SP?xZorz8+%ADUhyruGNqw*;^ zXGi#tBj;eO8L-lltwVH6|H_8ValHUGJ2=$~vS4fn2?wxBqF|wCOhjeJ>wJNIe;mvr?dU7aCY&KHmHSo%}Mja;lu)={t)iJ zD>)K%^!o5&r5c^Ry^QIv{;}vDQ2bBP3fHNvM+X%0XAC4-8MJ;DRlp3`p3Aad39oE_ z4=$gvkh21l{|wg`BhypmIj+OX&QjB*wQHJwog4`p^8F(7$cOk9d;5(#Jd`qd?s^|F zUw^7c`tfC5S_bkqevF@KqEM5lv3w37-%KA>W_Mi0JExBDlpH$?-A^Slv`_NgQ7S3d zFxJb%YbbcP%(0sJ>Cq-{`@OOd{NWXT=5{3aYu$>4u%PGKqK_#=TB% zsf}!nZ|%3+n=#JVhuk_(=JUnxj_4yNV~cN=hQZQJ$38SIcHJc857??Q>qbiq1on5i z(^YE7P;dMounJI%5E+E^Gv0(^B9e@UB^C6-$Dq|kLxO9&u%F*2iZCzM%^X88z(Jrv zzkWA!NW6Z7npKJHXTWU;@AOdfO)Cv|w`#~7-SVHa088Cnu#dt@##HadR*`c^)y1T4 z5d7J*>y=&v9iw8cS{h@1zc~)L0n;3?+)il@LOu-7?=@L_UD%K~XqA#;`;Sp!0_K)? z5&6moT}J-=B>i=kfO~S{&*Y~M4weD85HAD$Ei&H+^VsVD;B(X`{G=z)gh`Gef(_O3WYRu3dDUoPnwfZW(}!s)xAyeLj+2<`D{o`sRuqb zVMHlGt`~-T4;fLeb@x!0$HI41YTNoarZG+Xe2E0#`xM(6WCEsXcVdcSL`k-wTmY+; z6CUhRIp{Ihy)Ui=7VAzN7D6Ex!Djts-fuKiN{$XC+iVv^Y)y6?{%c3@s9V2W4|+;@ zu}!3ybXdwiA%J(DH=TJN^!A*FYghtH*`Wz|wK@QQmsw(^Lz|e}&-`|`cRG!w$Coo2 z%{1xBan8|cjI!`ab~njk8dhexa)FLFSTM+H(SVqv?B-ZhOnLx^5j=TDO(_o4fSF^* zaqRBE=B{uTi0=W(!>H*g^9;lGyC=Qh_FL#_q}!&{huLq#(!5MN-|M&h%7V1PUapZdTchB5CF3Q)|N1ysRVLf$j2Eh2mCc1 zGDKB2V|$hwGkGrk?O6M7XtfAZbEq0%G~=q$#46oRinNsq=Q*f|0N$|KmO1=kyS~oS|W~dJB!bJ7IE`W}$}8|3u90 zf7(9wY#R_lw>|7oj#sa9^dEKK5_PBr7t9cPx(sOfT^kp_D6N@_@WS*`YuQeZo-P;; zXgT?@7_RoJFR9;^^?S~=kq5oz@=G^Hf+GF+bq}S^*(vX}(Ys>dOk9_fnnk;=d;Imk z$Nt;nP!g1Zqm#|1buIf#E?lE3mCgY3>dN(v&&8LZFjUEPp8d}!_0A1$awLtu$}}^a z7XP89|CXTQ$5b0E=rjx9>ZAkQi;E?&u{AzP18D)8#Fg`Wp zLg(+%erGR8oLRl4_Lf3n*P6SRXU_HrsQE(V{=$G$=TE#!MIGLJ9OtqTNJ<3%A1VhL z^2{oDd7GySyY$>7pxw<5d2ef>4f+Hp;9;@)PvCuVQBuc zxAP$TGxMnP;=zjxP{)H88SP>m3CK^5{}mcoWMQXH{^R@qzY@^7S55WR`ps3>lg#VZ zXhA60;4?5to%`kzu2Y;U{JrrHHH?M5$O4E-A))k7fk4AdQfM-S=^c8Y-1_SCe?JLf zxvtmn>({B@&StHL#2L9G5-ub>Lx$>Zx-of2uK1NzJ&UXMGO`%yjb*N1 zKRS<2q$I-7e;mzaBY4~zwZsN61vv#))k;wkpi8$PHFwFWx05?MUuW0q^myCdeBrZx zCK)_l2t;XU%okK&4m}vpgq(;rqu~Nnq8P?@<qvcp ztUO~q0T4fD7ix31Lchjg=dDcE%o62Np02-sLXn4y9mG6e4aCpgwf8-vUL9fm$tLcY zyAOmGR^&U66}>mg*H7=#-3AhpqJdb}d#c$+Ia(P}9>ct&4H%~c1KCeIOcikH!(Z&G z(W%P3Qr3Jd1Wg6W%%TTKWLN&LVC&DE8gFEvqhvRnr8%?0&xt*Y%I__L#@%llYPbR8 zSo5@JuxU^+gvSzbI>tueLV_A-{`6XL=VVwFA?nwAyGA@1G}Ok1J%F%ArO!xF#hTIy zPqL*xyC68kt#90k-F6C#N9=Sy6NvJgnVcV%VR+Lg6`x1C0$|RxcP^7@JB2UhLXr0UfO4Y+B7G=uc|GU;6=?EOTcG zG@@Xu2XJ3v!Dd*b?#PWvx|z>Qupslkt)_Qlifuky;23*UXyEM>?>DqL+&0yHEZnwV z3c*W`U?Y8vdBH4WJ|VC|sq&7s>iKWiyMa|kZUZgz*j$cd9Dk3L!e~xH4s&AFbU0sT zNZ5u%jsAGn$y+z${^=(~+cD=V>l&@AOl?S%>sw+BJT#BnAVg10qho-0`a(JGNJk>z z9JeU)$Q1|&E73AjynoN}au*2wyr+A&8V$>w;<6c@mwC%2bodKZ5BwfBe$eU~=E_@p z$#qR+ev6c{fFnBwU!c;tZ62>f(CEXa|-3 zHS?X_N#6y;a%-g9IfJEF0Pw$sew+q$3`N7bCRT|(R7rW(DSD}mC*H)rg> zr#)yx$vF;xoi(d-dC(B;;S|CZ^QWqiSqJKP`A^=(3WDH>qpX_l=`FC?Pr|1n!taLK zHMtnjQL=CGl4=~d?#wH2%)vz)%GE~!lTp|<8*T#rcEGfFY9JWJ_tLQ6 zubDyO1<&bWOFLM}^f@Apz&-30jzul-0_X$aHghHuSTp3V{u z?fOy&L@X6~RC;$9^!`DB$xyKBC{+cTXg`MKcyjac`u-_gH-mgN(FBqPc;yN1? zh9Iub*rtaVW@|Ef&TP&##cyssIT@xiQD(&~g+VYWB+m!a(kn%RW;8kmSA9cea_N%Y zrBc^ofr!OZA$~yAyaoR;2_Y39BwSFhx^jm{`%JqWy69r6q4&u!v7mB@`EnENSZ&OM zX#>}ryv}a5PQhmbmQ{b@G}?LlH})FQGYfhdO!>a;NzJzql?}*s zsgJOl7IVZVZp~SW9JJYD!Cfid5y?mpTOuQOW=?v}k zZqLP~;uMB-q6Tno6~PQv$LaZbYy>=a3-co%VDvp*QFEKi`wBJWcQ20K43+QK$=VDW zxCbeV(A+a-IMk5-6-E&U8^JtzcuG1|7-HbC#fdyqfQs zjg6LW`9KkP&QwD=^gqXG*Nw8~C9Rod2B1P)dsNY_bKF)cKitT#{Nd;%2dI?vsfn_) z!X`yaJzxFiSOM-bEFEn2dK$zItOLk3&@f#SEH;i&5Xbd*HxKO#W!k>0caqZc`%kj8 z)OQd}@#qcPi~3C^9V-~A;GG4Gx_vv`@95B)zj$VJ|)cR=2^K|63Kk*Ziwq*jXAK|u00McbSa4om7* zIG-dlCqVRKbw={^qDKs%R+N+!j;=ucR5?8$1X3XJB#|={bcgnTXzH#Umkp(a+g2Vj z86CINh#pyZ%c#8cPV6b&?!Zv!$v)|qh^H$v8bYH36zhI>&cE-o_m~yB0bsB03I2_F zGd?+wRf-kCu$fYfLne|&1}I6Dte*?1%E>fwYok!y#gT{`hlNNcfUiR{&gX*PYE?|t zr1bf%OY8C3o!2u^p8Hg?;C*5|NRjkdav{l)>wvq)^Se`xsg=AdrK(1*ZP^N6VuaD) zt>m|_y~NKY@O?jdEPoLXfK#TkD6D1 zdBX9OcSlWB(E{12&*Aapc3gJEq@| zg4Ol|a>Rozab>GxlOW40Y;<+tf43l3n{Fxr7pqDEE@1XU{!9z_0fC z^j+R7$U!PW7a@7u%VRwt=`IyX34t!_sa(M&%H94#<&a-oF^{jnG(!?|rrJ7*B7yO^${tUJU%AK<@@YXX3qq(4qol;UwkHFp46awmV@; zRV2Q6dbDl{c)P!YiF`qL@pCh1EAHW1Dq}y0-PVkzDJtID9ER>b30EZ;nb4#YVv9(M zv0nGO9Xrq1(U0zJQaYk0Hsd-KaX$~D(HSiddO^PvGxxmFKw2np4GmhBcLn+7D)Re6 zarMEQqDZaRBI{J|P=wqy`6A(cawS{~Wv|aEEVS1QA+r+sHZ}%QV!SqyDm*r4S{7oI zUFr=!NNAYF`2B^uaN%VD2TP5YJb3)na?I9MiLun8o<$FxD4gM!J^y7{rWrqO@l>$D zvf;Vb60~SHf9Bd+;I*PzlWqd3Q$Qprg(88ACcP>_#OOdDkOdHgPU9uwh&A%YE{-p+ zHJ+G%3p-8GPi|;MsU3ig_Mr)o;fW!tW;(T?2dhNyJMaOfX@W;HZ4WIv>EM(Xn##ZB zT2Fi{S>($@Tqg1!u^MB%Vgr_lyavlXi@Wx`q;}$YY!jZpZ{Zq+sQJlgX?fgMlzfB3gAoT#rC%(vO%Xv`~oa zFY5-<6sy%~U50aCHf2 z=g+Q;UUdgNE{vw=n#c=AI;2|r{E8GT5S{WKx^B?)^KG{RIfpT8)zhv$fRZyD3!{3i z6mM)LmMXs7%h^OKFdMC{_aRLd%fEk~+usbm+(X3fzK)GP^X*>5^TlhC&~Y(Y=8CfY zfeL~n&gOQdzh+s%zL|mNOph}0HT-;%s13-V*s~z^#za;I=RqLl+dB*PuVmKLo&x+B zshY4>NmURf*8G+!cr3AA43W4&&fBUL|BcKZWxYl%WB+Vmd&Z>eRyd1jMLM^j?9C8v zK3S!v4TO@q(&oxg&LZPr;Xu8{sEi#T`VC}8=#1Zj9nOb+85=NLvFn~rJY9=u-d$e! zjyy8*v}m89^1f*eurLZoWD_TFB<{F1iy5?j(D5Lr-U3q$PY>-~lJ6lJKn_3Y)P7y+ zcmBHB(sYW`CVeB8i6Qx<6uaiwdees)GiKf^dRLQA-y~mbpPA$2ucZ!Up$jO53-GhV zG^!%6zNidEyVM;IUHyQBy`CproPZ-+{C2yAzX4>)BBKKkBCzmS1qhnly*6q90rrCNLBP=_;Zd$2Wz zvl}1+uHJLXxrmR~V-xYQ?w^q}_V){jP81Bs$NoZk-2`F+)l4-tm241q`S!3BH3M*a zwEzjx-Pd)CKr{93zJXE4r?l7lxSov5t5~w0NMHpf9$l=XZTSR{Xe8+t{ z>f%3z0`~tT#}Q&1NgGS^&nXr)4nG(7USBoNQy8Z@eSvj+EESJ_0MxrN{G}IshYlN( zi(ASknFg(k4vOrJ;kJB0KAsfs35=DpWHyY;MSSn zWPVExdCSmxLNBf%GLHpc0=4ZVmOtF82 zDZFg&Tjmfn@}P=RO4>2#>~t{9&ae-XrP`?#k{gCt?xS}Nyn@!oZ;}V*l6(zPNliL* znDyh^AkH6Pk(i{t$Rz84yFNE*=~?!?Xc~PsoPLuT@p55F`jfG0tZGcGH%BFnmT$ff z{%&MWY}_?iq^>04zS?3mjVV5!9#^R{hli4xG7SEz)NzZqf;tHj^&3B0lvgPl2Epb~ z9A>HRjh+~*6*hp5f2T)qR7qHofbx#oKUXE?pIjOrT65_zJMk2BG>PNUoG-M$B zSN13@RLJiOJ+vp1W(~P=;pIm@JBpQXNCql5Khm4)bnD5;gD_925Kd4jtsw?MKB;L{ z5cS-l<8)qteEx57{$_r5es)QEomVfUS z#PRqLl+#0byvYW&S5Lb!XJW6OE&>b9a(h4_A2KQ7Kio3gQNbV!(f8<0z0!{u=i<#oHwdkNj=P#^y$qM!$QZh8Jb zVMJ7S%tmFqjrP|!4)~4j76f}_?~?(u7pF?{J+nyvWxuu_&!H1xPBjM#N%N_SXOMXL*!henxusmHvvDcY>Te5-+)R#p1TCwD?mut zqc3yM3AfiLc1MypRP!t*t(i}2XA(4o>mg|e_@mQ_Wef_n7^>CbE627-wW+DuI_l16 z#slUrsA`}(f!`=ZWrg%Ys;yDLW)>VEiPFH*_!RT~7Og1285o~wL>oWQG(BD^#@(nY zxg6jipw$iKyA{gM?5DE*Ajx)xeafk=g|p2oBP3gzsv>+)5`>L#k;`nH!HfZ{@slpP zVu02Z=Ydl$gn^etsyJvbj^6TXygXk7K6nHQ%?LSD3uaXUw&koDRPOKvU0#T#FU3}! zeHrat3Z#)sW$r|Qnfxlqu`w3&O3a_iNVqi1fTLS-Jce@{Sb!>I77q#^-x)3kkGr-R z3(}NbrzxF50UQMuqTob(X3@Fg*J}Qk3no^CaIk0zJTq9UgwH)QvIoRIW!L823i)0} z9g+pIA%SLRtE92)Q!eV>^~f>M86UPmza?0n;APsBLdYzU`_n06jZFP*Jh#*wM5T*F ze-X?w1Cnu_9?evAxwiLJT9vU>YPCM_@$_!Om%N0f!G6GG5Is%=Yexx<*XIfRIR$D8 z7Q04!+5kF4^pfXyI(m$oSS+RgmZ_YPgzlyr4rqG9Nj4aTSlUy%>EtbOEnQD(i<-#F zl5IslO`*Lq5C`>z)%+ANY-AaR@!8RW^k)f9lJKh|+7vc3_Aac^#K?sof-jaoemvG^ zFsIE7`?+`E3T}10H`I=1>hOV4bS4@slB~v_2p&tPnnQ#>vh9p${Aj*$$27}Ee9*n%-B%0B7b;M>4 z6b|w^}h>}3XAycmv;a;QzMB$>XCTb(12h}lBdnOSat3++=x9jsCC7&O9E< z|NZwfMq`PPR!g)I5y?`vF(E{jC@Ml_Ye5ZCGBZ&k6(!lSXOF2YV;|a(eVv3TjAiU* zEMsQw^PZN^_k6$S`#8UIX8xP|_IA&E?&W%3uj_ifd8=wj7e=xWnHi#@?mQ&@Lswb; zNL6{3@*<&vnTj(WY}U7I6RL);YpvTkzBJo|Kb9)x$F_p#6NT`dqQ<4SgbKP)EBh~C z1ufO7ogJEjcyE<;cL#s04~#&@il@%qC4c4t?E<6}Hsee}6MeJAf!|#-AWzJ<^LUqz zPxe6gOW*MG%|f)ryI5~VHOE*6y!6Wdr-oS0UjGv}IjFccZA(8MEl+{+YzgWp;3QU3Eu<>1;jO3!3H{+KKe1C=!K0i_q5tNd97|JT?qml_qGX|*8oDOc_H3(kOL?wDTJPeP`quSZ6*ih~9ep?}8)$2s z1x!4SC2IO|5xC3gAjXEB6rrKo#{s~=UhNvk1+`l=ZU|nFoB#PKNae&mE0OV$a6-~n z>glT@v)7uTMBj=isndIh_9y*is@=eBgmXB1rWk`+W5M^aU0CLb=2^Ox?EJ~REjmiv!Nuk*fnCEfM$ z#nG|kYR7#iywkXN%QyCSl;xrCw?fu?Lr((Qv-rf|IT>s=jjLzwz|Eifx%_hU=L%Bo zW7>US9Y&{qoY@;?*pgQKi{~~;i!+6aq2Y7qWwtTJCtgF+p?ZPY&(Pc?m2v%-*B>cU4zl+cURZsGN~l~Y&GsH_Kbk^I~P z=jRg4mMvsj%nDVje`Rho7f^m`&Wgz5zVV|kaXdv!I`?bQt1pSK=Yo4=5qG{%+lCiF zant^De8Uo@a?HQzW!@rmvoihI<7d?O+n7-q&i$p=gIY|wgmz8T<7AdmAXA3IN<3im zuq?h5p(<2UAigZ7Z#S-+sjlFtaB(fUO+fj_GPmUqf`kv@W$>E*r_A>zneUZr8mklb zWa;%Uk>bwE$yQF=XYo95FtlnyR8fuov>Qhuv_ z&9x52ewaNh3y`%wan~O+XT+I!cQ0Iz&#(V27t#78PVvOJ$>_zWt5V%e^R=JX$aN-J z?7BjD=JA_obA79FBOMIuNfu`G#;vu$cW>M)Bz4GDGsa{9O!Xz{mohnEgu(NlOU}}J zbZ7QlC(I~ADgwJzUF#KY;_(9-iJ|NWtynM6!)M-*A=mQVf#suVEpBNohDlH;Evko9 zIZSQKVoF_aFLtd9SRIYo+6MXIJdOx=t+0q~AUTCos^0BCm#P}6d!T7(&AA7wu(9RkvkVz zR5#wd&deo&XaB?I-8b~fwt|PZJE@bb#`}_>;9$qKzW9f96!yRd(w*3{=^7kiBWkQm zK^d0R?i5#6_4ADF!>6-N_2ipJco$A>7Rt4v=B>Id(!ZKuipD#ib+&nx z!Lo>N7c$p>&HyKjD`-otnXyxGFgOJfNST4DytFn8qt8AixI!VV!z=W%*U>B9y~^`b zVaaiQJCZQPcG_#PTnMMcD7Gqb&~8z_eXKETp|B4fxhA#4CcVdYv6XVg?LpaDnn#0& zWuMe<1WdK9w#kOVPCB}=)8%ng344_qXEIJ@IV^3t{2S^6g-9+o{3wedh9!-u9wgEe zw5>;46wlPa$X6;G`?1%CRepw9u%9LOa)SpF>b`MgeOs!2^R>K?4bL(o&7{$k2(x5< zubY?kJot|ip(f=I&?UX@;nP*srtYAvAwDSe7%shwcoZQmcv&@8#L%Le+z(vx^KMwa zLPuJX>gN135Gl7!(Hx3gW>5)6xvi_or>Y)Iar;g#UOQ~AuRemBS|EnQ2+;igr}A`1 zqOKrbHM`yEn7v(ALfLe}C&WmKaj77P zUywSrnn$rsWDC2ph~KZ9L@yDJB4f=I9lYO-eiH70? zuBW`;$r13(aUr7{Q=WHa00$m|bsl8UnsHnuHiefdC5fH3G6N)wSw<4QjO}3O^0W(8 zZs>3Z$~~Pg7FHb(d7UOlODbP6%C}hc`d(JGI@I7rV!fDOB_6AnHg#AmJhOX2NxfxezCU#lqUoC~C%=97e8niCEQwZzh}ZOg zRey$PRW$COIfd_O`8HI^mJBHRLy`!;-#|Rh{HjQiHc&##&Q!2#A2s6A%F3cbTKUaT zy??$YJa%pZK%rTL|>Iv%Hz+{Ny9 z=gF~HmED0Yx{}Jy>J+@`c8OiaBue$!wKTdQBz#t7fyZ4T8@TwO2(#f}PHypkykc9d zMjX(&YW6T@eSOs)&?cPkJ{fYEnzZ4u zsVJHHaNRN7l-BHKciefi6sbUUl0d?c5-C<%i9Z`k#cX;}T>#F|DEJI&z8ajKe}6ZU zFTX)W;Q=+`W5#^mtF^UwE_9?^;*r@`!up#fR~8EehBJ2*M{Eaod@5s(0=7F zKc5H|;#koYG80>B{|vGzbf<%bGSOG8RC$73ovA1MZFdR}eHDF(h5s>TZ1V(xE^Y99h01cc9bg4Sg(YEwxzefG1%UgeT4Jf+*YXt zPe<5m(om^Li`;Gr&_kZ_8U-*X~rVoSjw?5^<0wt>Vomi(D|>ZPE>=aZJDM%RKC!P!DQ(|&)a}U8FyOg9LL+Qo}# zvf87B@U|5CG4Tk%|8M?I`+%Qp!pT1;wQyQ~&I!Ibl`J?{TCF(x?!;`6lIz?xyswd- zuefE_s+$gDL;kSKCK0C{-nS|=c^Q&0U!j_ujc~H$-7XhS{)0l9Nh&@ut^oODL(U~Q z4H4-bJ`(|z-)CXj0WkAu-qHeIANg&T1DH177dXvsNckHnidQ+#QN4Q7ZI?IV-(lZn0_)VQXf?Pb;?&Kp66d6sIG%TVatwH?2;e7&vam88fiS zhQax)q1c6D!FYYsH>=itj@qKegQM3}A1t??Fzx67Ck)3PB!dCKyJ=~*8;03)*b-s( z@ep1fEmq^xCi~hN71RN`WEWHNHdGsw3)Pg<^O2ES=Yw>k+6&`PGEn;v;|9sZ9D^Jw zS9W0)d%_bk=W(j2jS2k%Ydb>rsQJ)A6w|x1W-aKXjhU>2-R`#SOwmVWGu;AModfK| zZBFksd14=X??E0GvD)7Dt0VXG?p*j`Yx*gK@mE8qTZxyEAAsX$b_9c93z9GUc32sv zsGM?C!{1A62>(s&>XYegYWK~{_~9RYF!F)#^+S%B-Tjq3vC@k%g<7@>y;`lEeD!{T z>e8yb8$G`VAD<(HuBz$vzP2!>s>0qkY~sc~P@-8u9ahPLyn;dZ5|&doGXER6caeO$ z2sQ;_*A0p@gUpnFP-2F7RY(D+TZFG@w9;Jhd@6UDWd;NK5588_dl!*x7kOBBzTOiy z%#}C`kuSTg1xPY~c~~T$;JrR|eQy(;%Kkd-jw1w1{qjYK;-j=~&YjXAd)Ya3wX?5c z`5ZZ>s^BF(@c(1Z0Q(PvEY1kO@&T_zE`EM=FxTb?jmnc}E5)D(1F`h8ih~p^MW_fD zX|j_0rfZw!Ji26~FAMs=s-^GpA-J@=wrvksu1*{*XdDxr=kSLy#Y<+z2D zG*|CYpiJ#PkRLz0X|^&3m)Gt&=Nz=-o*l$7@ER-89t=JETWSq^2W{63h_a(Ca$o=W zdGv+@h{|9=?|t{45+D2+Cfdvboiz$P#-5?h8nEL$&8VNN#B@bs0yDIHcaSVw1g7=G%@;mvd4Cy#ai8emKQ6gmF$ZJPvl6-wDLr#%$|p?>*1h;aauy_6M#{6rQU5@=?RU)u zDHqP&U+G1TdsA6?`o%@@V`BZWz(k}S+Ji!I(3m@)5I-0)8tyTTgYkyn+x%Q>Yk9_S z(aEeYFoSz>$ciU1w6to*XsyvSGkx1VAC3w+rd@Du?QN_|acr9v6i{;Ky}KPLb(A4 zmqk2OQ{Fc?Uq?Pf57=?0-+s_50DJa8<(z#E>1wZ3$r{8CC>UP!B172>r7nUemb4bM z`R?RD{OmbU9y>jo{3(1>8{y32;a+z2DrF6T`;i+XW3CY9L&)QIOpe?MM<5NK;W|!J z9lx&HHln5&P-jT&5gy`5=HB;bp$~1O`Oo5y`yD`=256`dZvs29dM!izRR)y z0ItjGqC`J&uy>zNH%_INB}12Y!ul4Yb}(lu7ndsGw_lfLjW|pXiJ(Y#JcLvJ8Y5%ea%I=ebp?{Wd?0}iIXW^DvXV`;3U+DlgEsQWO zhtjKBBdzu+A(UG+_FFIR%fZ!7tR`A^=bqZ#Zo5dj)_b}aUg*~aGAtEZ-5OHbtJB0m z6RxPpY7Yv2!-fJu^Y=rx_ntbSd;+lhMUNe(gnEcn zy6B4O+w4`H>;tXMLNRWE1-P{($w)?wBR1zXPU8O5TR(k{U>UwytJ0ENmBWy`Beb2C zP)1eDSdK)Bquf2d0BsDH2|39QqYRy;LY>j_?s7PXX(_z)bqBsy>RQ@cAO9yS)O*a; zME&w4Cr_%Xw{r(8T;b);%f45oKLgCc@X)?RuDj6sWqX=KUFJK)S>-Ev!xts2@^k)^ z?bu%hf3uxu6}$aW69_*Eht4aHjTG3O)1WO7#heo9$w1@$Z#-2snT%<<1z791{>hb5 z-!{@PtV10e83{d^@uW#fDh4svlGtY$j1<(Kz(9*lhm;;VRFs5M38d3KBp}Ob=^kr% zW^@~*Uo0q5-;%|rrRj3eM^Ou!To>ds<$vlJ1&xqXJq7C>f$RG(G=gwa-*R0WC%b=`@87zRoR3;*vcbqtbO8c%HHj;zfdIo8;XqJD}w7iz0f?) zHTlSufmG;#FnzD6nd{*lSYSq(Oc|-ZW968Sv~gn*&F^{#z=cOP@roJe6P=EzY>toy zd4=n|M8uoH2i^b#iQ?lb(qOeI!S#M#sm2Dsbjk-pQm3USO=V)6ytSF*=N6^t>x^SZ zXMH##H3;qz!h3*-ZkV!y7AGQ$Z9e_=4hZ$y&HAKEH}_iTof6LIp;IR<^}C)<{elk9R1tRz3QS+h{PIEu2p+-Q;L z^-w%qsXu%@zmPwc_sOG2G4QWm+{bTno2dcbNpVEDR;?p+;wS5Wlgl4qvcuUAzPQnw zx%`T2jprKPqh=T#4axd@XQJa`RC$pcaQcW)_Q*}%UI9Ox{b0`LSWPcJ0BD{T=yqp4 zUkYmTm*2h})}Z|M6E%Np0A@eGB$!Sm4{I@>xFH|)p(F~7DgltF=Hy~7Tv2EhE{apwAVBHj)nF*hhBQ&m%l1`{{PmsUh3r|GB zAt=XP59IzOr=?!)0D9^mZ>18#?64%hm-kf#JO{+nXpB3bIxdhwdy3;u(EIM{#_zFV z_FMCzP7a{p%Ej80CrKLuLAr9F#77G6D<1i5uc`P|ik)@$*v;B^NA_6Pn|_Zd0noPF z2JuDc%Uk$pE0&{!x>dltIX(|*id<$N6M{V+*Uall+=ug84_=1#u87d$1f=q9AE$7H zM7%lembgd}N2a_=z?IVn1n`v(4#_i!H=dxKf6v9b$o7kf?3NQQHkk2lSb4V_BG(i( z{s&{=ywBPMyg?->%y}XY83|lZi^VLvd66zaJ~aZAI)dt>CVK`F5h>A};|JN{NaH0_ zCkeO>-xs`VI<|z28u)X2?uE5Wn*r@`e=X?(g^Zu*%F6H+gZ;R~&qey6@s9$TJWaRA z(iImL#-2~yE!YX`P)RJ+l} z7r;FF#V6(+p-ZyazZ`ju_t*D#sKn*?GISyXQ#gxI{J&Ignru7d`p7Ed_~u0j_%$A=cF%;O3pJ=eAByqF&%*1?$TF z6E#D%!GDjU811$WFX)NHrD4WeKL7j_{s|Dr|GrTVHm(i>&baEJ5EXx}?F@VfAEC>r zH!cc%e~&Lnphog$zjFmEMBFoUT?W*MN>U*wFEK7Y9beX30yTIOJLpYxt)!Od#?k3z z6W010V&7&4F#}XKP3fwiG1MV0G=ZZ#SF`7{MyOi{oC#2~k0WE$)5~dcS$EzX6F7Lp z>x)aB9VQ2rx1`y}(jX-co029^Ax^MnnwR6LjTuv7YW2_TRXe zX<2r))uQqK)};OP7{#>@e$XJU^^+X}W-Qkx2an`dPX@J$TRQ*lgt3GAvertdCvelNBq2k0Tm|E~2cy9f0$m;Sp% zgDh<^!NvD^y}lJazBp>I+MCDcy4Xkkw(Dn9S)V~GW<#_Wso{{}O#icW0^U`hE1IUs z>IZfwt&AxB-Zfw>kr;mP;^&6}$9K4TQb|;=w--L;av@7^({m|HCD)WTdR4EMFa<;f zV4!4pCzuYEluPmrX5Y}6&&~EZFYA1tse|R!B|=N-l#&o4q~#L`ny@Z6G;PdKD*M)7 za*^iNu_=mArfc?KnIo@2E`8A|#B1A&4^6PE zZYL?E*MLJZ#I4bqq3a!wZzLjrU~V zD|Mf=v|tSOV~XY(rJr}X4IJ}g)a_7Yx4RaUzJZQeFtV!7*4ok0zVqac{3KdFZd07_&q+;-@4~6b9$seb=;$jbZo^tNdW>SW~Zq3>h2^B@&o?XS%lJ3b9CaqhhjR*lbTd^h1;w;3Ej{_pzgb@V_vQ~FYIh%L zEH7bu-MfDZ9K8Oe^=EhWaz@v-(;3H$xr7=E&R1=`r~s4W7n6mV;Nc|DTb)+2FvP}240jolj7O4&Q-L6Qs)-$)1<;L%ur*F9qZVwmS!){zyTbfRd z9SS4pI2Dzz89o|>t-u6%@q6q9_r;mW+AZ^afq}A6(Anae=rka^4`Jro^R(I}IR%`w zXMS&vit`NueL89Nsc)5Rm5=2~AWsV%6v z4g3PHbh_Er&33D;bI9%6oWOgiOQpuv9;bizTB1d6)&Pu57;GyYkJoAnRW;12!!lmj zy>Y^3Ph1|Xt~xj#ci?CiTxaoF#V0ZWwa>@EN$U2+*ReVQB`d7uL9hTw3|l-SLG0#q zY-;{YtM=r+^oE{%kBPm`_`6<{cdYyE?)*5f=o{ALHGiA>>3jdfT?(S$G6C;LyxuCn zuEDmreA_~;@G34VK{E_>I-eI*!@(8K4f{WxZZ~>T&>KKwfJM)dK>FG4Wb6mfngBa z@n79{B$vi52Qd^gN2Fc1__e zS2t5g3VZ}MgRIhZP-3tE`MEh<_7tZN+nOvxmuA$TY7t+7%~iKgwS#QX0<=X-BcU(z zxqOTd#Ca|PldW3d8FrH2#~8K;`1xIu8K_y~29Do$ou2O3JheDA_#nQGZMxbntCi5V zgwj3yqq@?<5_~fCBSz>DQF3MW6yNe_Ag4LmHCbo=5T@?~rog;ZX;$<(u+8dQd@1vw zrFkUopM7TKZpD`6Lj@$!nZ~smn43`VrqpAqx>e{}c;r1!`WZuM5>XYb4Ton=@NoJk z4o|#_x_}<9P^-bxWo@S}n?3x*eIj`70^Wn6Z~8%a?Dg`}mWN&iTR*qr)J0VV-*f&@ z$W7vqgZ<&Ii#QFvZKK#L((YpSwjva=P%oeDHqh{5xCA^>Ij(eG?$^g=ol<^XIWi^M z11*aZPAYHyj&UjFAkQ{fCU@ipXN!rUxk15Er=b4@Gzt0y literal 86778 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

(tBRGTyC>`^ip*SO+JS;ySbdYhq$;GbiC2jCCvM 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 Date: Wed, 5 Feb 2025 18:02:03 +0000 Subject: [PATCH 039/104] Automatic changelog for PR #89351 [ci skip] --- html/changelogs/AutoChangeLog-pr-89351.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89351.yml diff --git a/html/changelogs/AutoChangeLog-pr-89351.yml b/html/changelogs/AutoChangeLog-pr-89351.yml new file mode 100644 index 0000000000000..c84a5942e410d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89351.yml @@ -0,0 +1,5 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Tactical medkits should no longer create invisible medbots" + - image: "Implemented the missing bezerk medbot skin" \ No newline at end of file From 2d3735a051dde6ae3dd80fe8ee4b935fc9845141 Mon Sep 17 00:00:00 2001 From: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Date: Wed, 5 Feb 2025 13:02:16 -0500 Subject: [PATCH 040/104] Fixes more scrollables for 516 (#89325) ## About The Pull Request I was looking at https://github.com/tgstation/tgstation/pull/89312 (Ghommie merged it while I was looking at it lol, this would've been a comment otherwise) and noticed a few problems: 1. There's other instances of ``style={{ overflow: 'auto' }}`` in the code, I checked them and they don't work, this fixed one instance of the 3 that exists. 2. Autolathes have 2 scrollbars, one for the whole UI and one for the item list (3 actually, one on the left for the sections) This fixes all instances, and uses overflowY instead of scrollable so it isn't there permanently. Also removes the unnecessary scrollbar to Autolathes. ## Why It's Good For The Game Fixes more UIs for 516 and removes unnecessary and annoying scrollbar from autolathes. ## Changelog :cl: fix: Autolathes no longer have a scrollbar that sends you off the screen. fix: Exosuit fabricators' queue list & Techfab/Autolathe's left side (with the sections of printables) now have a scrollbar when the full list doesn't fit on the UI for 516 users. Techfab/Autolathe also now does this for the list of items too, instead of always having one. /:cl: --- tgui/packages/tgui/interfaces/Autolathe.tsx | 2 +- tgui/packages/tgui/interfaces/ExosuitFabricator.tsx | 4 ++-- .../tgui/interfaces/Fabrication/DesignBrowser.tsx | 8 ++++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/tgui/packages/tgui/interfaces/Autolathe.tsx b/tgui/packages/tgui/interfaces/Autolathe.tsx index 26b5254072684..ef52d1132dd8c 100644 --- a/tgui/packages/tgui/interfaces/Autolathe.tsx +++ b/tgui/packages/tgui/interfaces/Autolathe.tsx @@ -53,7 +53,7 @@ export const Autolathe = (props) => { return ( - +

diff --git a/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx b/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx index 3785e6b5987da..253a1ddb6f86a 100644 --- a/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx +++ b/tgui/packages/tgui/interfaces/ExosuitFabricator.tsx @@ -242,8 +242,8 @@ const Queue = (props: QueueProps) => { />
- -
+ +
(
- -
+ +
( />
- -
+ +
{searchText.length > 0 ? ( {sortBy( From 6bf0f1acc66ec088859d91a0c18b92fbd9f98c47 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:02:34 +0100 Subject: [PATCH 041/104] Fixes stunprod's missing inhands sprite (#89339) ## About The Pull Request Closes #89338 ## Changelog :cl: fix: Fixed stunprod's missing inhands sprite /:cl: --- code/game/objects/items/melee/baton.dm | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index 74e5d54e8b128..eae6b5e4289f4 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -530,6 +530,8 @@ var/active_changes_inhand = TRUE ///Whether or not our baton visibly changes the inhand sprite based on inserted cell var/tip_changes_color = TRUE + ///When set, inhand_icon_state defaults to this instead of base_icon_state + var/base_inhand_state = null /datum/armor/baton_security bomb = 50 @@ -594,20 +596,21 @@ update_appearance() /obj/item/melee/baton/security/update_icon_state() + var/base_inhand = base_inhand_state || base_icon_state if(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()]" + inhand_icon_state = "[base_inhand]_active_[get_baton_tip_color()]" else - inhand_icon_state = "[base_icon_state]_active" + inhand_icon_state = "[base_inhand]_active" return ..() if(!cell) icon_state = "[base_icon_state]_nocell" - inhand_icon_state = "[base_icon_state]" + inhand_icon_state = base_inhand return ..() - icon_state = "[base_icon_state]" - inhand_icon_state = "[base_icon_state]" + icon_state = base_icon_state + inhand_icon_state = base_inhand return ..() /obj/item/melee/baton/security/examine(mob/user) @@ -833,6 +836,7 @@ icon_state = "stunprod" base_icon_state = "stunprod" inhand_icon_state = "prod" + base_inhand_state = "prod" worn_icon_state = null icon_angle = -45 lefthand_file = 'icons/mob/inhands/weapons/melee_lefthand.dmi' From b1ca5988895d1a22b73757c4766032c15afb0971 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:02:35 +0000 Subject: [PATCH 042/104] Automatic changelog for PR #89325 [ci skip] --- html/changelogs/AutoChangeLog-pr-89325.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89325.yml diff --git a/html/changelogs/AutoChangeLog-pr-89325.yml b/html/changelogs/AutoChangeLog-pr-89325.yml new file mode 100644 index 0000000000000..78a89a5c0ff06 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89325.yml @@ -0,0 +1,5 @@ +author: "JohnFulpWillard" +delete-after: True +changes: + - bugfix: "Autolathes no longer have a scrollbar that sends you off the screen." + - bugfix: "Exosuit fabricators' queue list & Techfab/Autolathe's left side (with the sections of printables) now have a scrollbar when the full list doesn't fit on the UI for 516 users. Techfab/Autolathe also now does this for the list of items too, instead of always having one." \ No newline at end of file From d58edd0d5aa046f4f7437cfd3e624be6eaa29855 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:02:55 +0000 Subject: [PATCH 043/104] Automatic changelog for PR #89339 [ci skip] --- html/changelogs/AutoChangeLog-pr-89339.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89339.yml diff --git a/html/changelogs/AutoChangeLog-pr-89339.yml b/html/changelogs/AutoChangeLog-pr-89339.yml new file mode 100644 index 0000000000000..ff46e4b138498 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89339.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed stunprod's missing inhands sprite" \ No newline at end of file From 09e8924876d99abdda357ecf1cbcffefd41237a8 Mon Sep 17 00:00:00 2001 From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com> Date: Wed, 5 Feb 2025 20:17:57 +0200 Subject: [PATCH 044/104] [no gbp] fixes virtual pet app changing PDA's colors when open (#89333) ## About The Pull Request PDAs no longer go white when the virtual pet app is opened ## Why It's Good For The Game fixes virtual pet app changing PDA's colors when open ## Changelog :cl: fix: fixes virtual pet app changing PDA's colors when open /:cl: --- .../modular_computers/file_system/programs/virtual_pet.dm | 1 + 1 file changed, 1 insertion(+) diff --git a/code/modules/modular_computers/file_system/programs/virtual_pet.dm b/code/modules/modular_computers/file_system/programs/virtual_pet.dm index a52a0c37aaf93..9047e3014e6d5 100644 --- a/code/modules/modular_computers/file_system/programs/virtual_pet.dm +++ b/code/modules/modular_computers/file_system/programs/virtual_pet.dm @@ -17,6 +17,7 @@ GLOBAL_LIST_EMPTY(virtual_pets_list) filedesc = "Virtual Pet" downloader_category = PROGRAM_CATEGORY_GAMES extended_desc = "Download your very own Orbie today!" + program_open_overlay = "generic" program_flags = PROGRAM_ON_NTNET_STORE size = 3 tgui_id = "NtosVirtualPet" From 465f654548bc123c1f5846f135a0ed4897c5f6f0 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:18:18 +0000 Subject: [PATCH 045/104] Automatic changelog for PR #89333 [ci skip] --- html/changelogs/AutoChangeLog-pr-89333.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89333.yml diff --git a/html/changelogs/AutoChangeLog-pr-89333.yml b/html/changelogs/AutoChangeLog-pr-89333.yml new file mode 100644 index 0000000000000..0ce3e5c3f6941 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89333.yml @@ -0,0 +1,4 @@ +author: "Ben10Omintrix" +delete-after: True +changes: + - bugfix: "fixes virtual pet app changing PDA's colors when open" \ No newline at end of file From 344d3b62664baac5ef48a9d7253aed8240bc7777 Mon Sep 17 00:00:00 2001 From: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com> Date: Wed, 5 Feb 2025 14:00:27 -0500 Subject: [PATCH 046/104] Optimizes `/proc/icon_exists()` (#89357) ## About The Pull Request This PR reimplements https://github.com/tgstation/tgstation/pull/71538 atop `master`. Quoting the original PR: > Every `icon_exists()` call will cache the entire file. Past me didn't realise _why_ file opts were so expensive, but I do now. This is immeasurably slower on a single call, and _significantly_ faster on subsequent calls to the same file. I attempted to handle some of the review comments that were posted there, by splitting screaming functionality into its own proc. * `if(icon_state in icon_states(file))` and `if(!(icon_state in icon_states(file)))` were refactored to use `icon_exists(file, icon_state)`. * Where screaming was seemingly wanted (and where there wasn't a more descriptive error inside the `if` block), I refactored them to use `icon_exists_or_scream(file, icon_state)` * The exception to the above was under `/datum/unit_test/turf_icons/Run()` and `/datum/unit_test/worn_icons/Run()`, where `icon_states()` was being passed a mode flag. Given that this is only used in unit tests (where performance isn't a priority), I opted to leave these be. Additionally, I revised the documentation comment for `/proc/icon_exists()`, as I felt it was a bit vague currently. ## Why It's Good For The Game https://youtu.be/Z9G1Mf6TZRs ## Changelog No player-facing changes (hopefully). --------- Co-authored-by: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> --- code/__HELPERS/icons.dm | 43 +++++++++++-------- code/__HELPERS/lighting.dm | 2 +- code/controllers/subsystem/overlays.dm | 3 +- code/datums/greyscale/layer.dm | 3 +- .../objects/items/devices/chameleonproj.dm | 4 +- code/modules/admin/verbs/debug.dm | 26 +++++------ .../admin/view_variables/view_variables.dm | 2 +- code/modules/asset_cache/asset_list.dm | 2 +- code/modules/asset_cache/assets/crafting.dm | 2 +- .../asset_cache/assets/research_designs.dm | 4 +- .../living/carbon/human/human_update_icons.dm | 2 +- code/modules/surgery/bodyparts/_bodyparts.dm | 2 +- code/modules/unit_tests/suit_storage_icons.dm | 4 +- code/modules/unit_tests/turf_icons.dm | 8 ++-- 14 files changed, 56 insertions(+), 51 deletions(-) diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm index 583db80877305..9d9afc57bcb63 100644 --- a/code/__HELPERS/icons.dm +++ b/code/__HELPERS/icons.dm @@ -1184,28 +1184,37 @@ GLOBAL_LIST_EMPTY(transformation_animation_objects) animate(pixel_x = initialpixelx + rand(-pixelshiftx,pixelshiftx), pixel_y = initialpixely + rand(-pixelshifty,pixelshifty), time = shake_interval) animate(pixel_x = initialpixelx, pixel_y = initialpixely, time = shake_interval) -///Checks if the given iconstate exists in the given file, caching the result. Setting scream to TRUE will print a stack trace ONCE. -/proc/icon_exists(file, state, scream) +/// Checks whether a given icon state exists in a given icon file. If `file` and `state` both exist, +/// this will return `TRUE` - otherwise, it will return `FALSE`. +/// +/// If you want a stack trace to be output when the given state/file doesn't exist, use +/// `/proc/icon_exists_or_scream()`. +/proc/icon_exists(file, state) var/static/list/icon_states_cache = list() - if(icon_states_cache[file]?[state]) - return TRUE - - if(icon_states_cache[file]?[state] == FALSE) - return FALSE - - var/list/states = icon_states(file) + if(isnull(file) || isnull(state)) + return FALSE //This is common enough that it shouldn't panic, imo. - if(!icon_states_cache[file]) + if(isnull(icon_states_cache[file])) icon_states_cache[file] = list() + for(var/istate in icon_states(file)) + icon_states_cache[file][istate] = TRUE + + return !isnull(icon_states_cache[file][state]) - if(state in states) - icon_states_cache[file][state] = TRUE +/// Functions the same as `/proc/icon_exists()`, but with the addition of a stack trace if the +/// specified file or state doesn't exist. +/// +/// Stack traces will only be output once for each file. +/proc/icon_exists_or_scream(file, state) + if(icon_exists(file, state)) return TRUE - else - icon_states_cache[file][state] = FALSE - if(scream) - stack_trace("Icon Lookup for state: [state] in file [file] failed.") - return FALSE + + var/static/list/screams = list() + if(!isnull(screams[file])) + screams[file] = TRUE + stack_trace("State [state] in file [file] does not exist.") + + return FALSE /** * Returns the size of the sprite in tiles. diff --git a/code/__HELPERS/lighting.dm b/code/__HELPERS/lighting.dm index 96087ba173770..a3d3522ebff93 100644 --- a/code/__HELPERS/lighting.dm +++ b/code/__HELPERS/lighting.dm @@ -9,7 +9,7 @@ //Test to make sure emissives with broken or missing icon states are created if(PERFORM_ALL_TESTS(focus_only/invalid_emissives)) - if(icon_state && !icon_exists(icon, icon_state, scream = FALSE)) //Scream set to False so we can have a custom stack_trace + if(icon_state && !icon_exists(icon, icon_state)) //Scream set to False so we can have a custom stack_trace stack_trace("An emissive appearance was added with non-existant icon_state \"[icon_state]\" in [icon]!") return appearance diff --git a/code/controllers/subsystem/overlays.dm b/code/controllers/subsystem/overlays.dm index fda892be7a432..96041edd4237a 100644 --- a/code/controllers/subsystem/overlays.dm +++ b/code/controllers/subsystem/overlays.dm @@ -47,8 +47,7 @@ SUBSYSTEM_DEF(overlays) if (istext(overlay)) // This is too expensive to run normally but running it during CI is a good test if (PERFORM_ALL_TESTS(focus_only/invalid_overlays)) - var/list/icon_states_available = icon_states(icon) - if(!(overlay in icon_states_available)) + if(!icon_exists(icon, overlay)) var/icon_file = "[icon]" || "Unknown Generated Icon" stack_trace("Invalid overlay: Icon object '[icon_file]' [REF(icon)] used in '[src]' [type] is missing icon state [overlay].") continue diff --git a/code/datums/greyscale/layer.dm b/code/datums/greyscale/layer.dm index f12fb1992c9db..6512a6c3d5619 100644 --- a/code/datums/greyscale/layer.dm +++ b/code/datums/greyscale/layer.dm @@ -92,8 +92,7 @@ /datum/greyscale_layer/icon_state/Initialize(icon_file) . = ..() - var/list/icon_states = icon_states(icon_file) - if(!(icon_state in icon_states)) + if(!icon_exists(icon_file, icon_state)) CRASH("Configured icon state \[[icon_state]\] was not found in [icon_file]. Double check your json configuration.") icon = new(icon_file, icon_state) diff --git a/code/game/objects/items/devices/chameleonproj.dm b/code/game/objects/items/devices/chameleonproj.dm index fbdf3bae40a88..5783b3c867f52 100644 --- a/code/game/objects/items/devices/chameleonproj.dm +++ b/code/game/objects/items/devices/chameleonproj.dm @@ -77,9 +77,7 @@ saved_appearance = temp.appearance /obj/item/chameleon/proc/check_sprite(atom/target) - if(target.icon_state in icon_states(target.icon)) - return TRUE - return FALSE + return icon_exists(target.icon, target.icon_state) /obj/item/chameleon/proc/toggle(mob/user) if(!can_use || !saved_appearance) diff --git a/code/modules/admin/verbs/debug.dm b/code/modules/admin/verbs/debug.dm index fc054e9a9cb0b..0ca4072ff77ac 100644 --- a/code/modules/admin/verbs/debug.dm +++ b/code/modules/admin/verbs/debug.dm @@ -814,57 +814,57 @@ ADMIN_VERB(check_missing_sprites, R_DEBUG, "Debug Worn Item Sprites", "We're can continue //Is there an explicit worn_icon to pick against the worn_icon_state? Easy street expected behavior. if(sprite.worn_icon) - if(!(sprite.icon_state in icon_states(sprite.worn_icon))) + if(!icon_exists(sprite.worn_icon, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Slot Flags are [sprite.slot_flags]."), confidential = TRUE) else if(sprite.worn_icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' - if(!(sprite.worn_icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.worn_icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) else if(sprite.icon_state) if(sprite.slot_flags & ITEM_SLOT_MASK) actual_file_name = 'icons/mob/clothing/mask.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Mask slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_NECK) actual_file_name = 'icons/mob/clothing/neck.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Neck slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BACK) actual_file_name = 'icons/mob/clothing/back.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Back slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_HEAD) actual_file_name = 'icons/mob/clothing/head/default.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Head slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_BELT) actual_file_name = 'icons/mob/clothing/belt.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Belt slot."), confidential = TRUE) if(sprite.slot_flags & ITEM_SLOT_SUITSTORE) actual_file_name = 'icons/mob/clothing/belt_mirror.dmi' - if(!(sprite.icon_state in icon_states(actual_file_name))) + if(!icon_exists(actual_file_name, sprite.icon_state)) to_chat(user, span_warning("ERROR sprites for [sprite.type]. Suit Storage slot."), confidential = TRUE) #ifndef OPENDREAM diff --git a/code/modules/admin/view_variables/view_variables.dm b/code/modules/admin/view_variables/view_variables.dm index fbebccd445981..58c98bb114a8e 100644 --- a/code/modules/admin/view_variables/view_variables.dm +++ b/code/modules/admin/view_variables/view_variables.dm @@ -54,7 +54,7 @@ ADMIN_VERB_AND_CONTEXT_MENU(debug_variables, R_NONE, "View Variables", "View the else // it means: icon_state="" if(!dmi_nullstate_checklist[icon_filename_text]) dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_CHECKED - if("" in icon_states(image_object.icon)) + if(icon_exists(image_object.icon, "")) // this dmi has nullstate. We'll allow "icon_state=null" to show image. dmi_nullstate_checklist[icon_filename_text] = ICON_STATE_NULL diff --git a/code/modules/asset_cache/asset_list.dm b/code/modules/asset_cache/asset_list.dm index 39e9cf925da62..48e5e7e39a41e 100644 --- a/code/modules/asset_cache/asset_list.dm +++ b/code/modules/asset_cache/asset_list.dm @@ -392,7 +392,7 @@ GLOBAL_LIST_EMPTY(asset_datums) /datum/asset/spritesheet/proc/queuedInsert(sprite_name, icon/I, icon_state="", dir=SOUTH, frame=1, moving=FALSE) #ifdef UNIT_TESTS - if (I && icon_state && !(icon_state in icon_states(I))) // check the base icon prior to extracting the state we want + if (I && icon_state && !icon_exists(I, icon_state)) // check the base icon prior to extracting the state we want stack_trace("Tried to insert nonexistent icon_state '[icon_state]' from [I] into spritesheet [name] ([type])") return #endif diff --git a/code/modules/asset_cache/assets/crafting.dm b/code/modules/asset_cache/assets/crafting.dm index 99088ed1a70da..1d6b9469d1ff2 100644 --- a/code/modules/asset_cache/assets/crafting.dm +++ b/code/modules/asset_cache/assets/crafting.dm @@ -40,7 +40,7 @@ icon_state ||= initial(preview_item.icon_state_preview) || initial(preview_item.icon_state) if(PERFORM_ALL_TESTS(focus_only/bad_cooking_crafting_icons)) - if(!icon_exists(icon_file, icon_state, scream = TRUE)) + if(!icon_exists_or_scream(icon_file, icon_state)) return Insert("a[id]", icon(icon_file, icon_state, SOUTH)) diff --git a/code/modules/asset_cache/assets/research_designs.dm b/code/modules/asset_cache/assets/research_designs.dm index cf56d33ddbb11..6f9c96e549684 100644 --- a/code/modules/asset_cache/assets/research_designs.dm +++ b/code/modules/asset_cache/assets/research_designs.dm @@ -15,7 +15,7 @@ icon_file = initial(path.research_icon) icon_state = initial(path.research_icon_state) if (PERFORM_ALL_TESTS(focus_only/invalid_research_designs)) - if(!(icon_state in icon_states(icon_file))) + if(!icon_exists(icon_file, icon_state)) stack_trace("design [path] with icon '[icon_file]' missing state '[icon_state]'") continue I = icon(icon_file, icon_state, SOUTH) @@ -48,7 +48,7 @@ icon_state = initial(item.icon_state) if (PERFORM_ALL_TESTS(focus_only/invalid_research_designs)) - if(!(icon_state in icon_states(icon_file))) + if(!icon_exists(icon_file, icon_state)) stack_trace("design [path] with icon '[icon_file]' missing state '[icon_state]'") continue I = icon(icon_file, icon_state, SOUTH) diff --git a/code/modules/mob/living/carbon/human/human_update_icons.dm b/code/modules/mob/living/carbon/human/human_update_icons.dm index 27c78ee932c37..9b743f9590143 100644 --- a/code/modules/mob/living/carbon/human/human_update_icons.dm +++ b/code/modules/mob/living/carbon/human/human_update_icons.dm @@ -104,7 +104,7 @@ There are several things that need to be remembered: //icon_file MUST be set to null by default, or it causes issues. //handled_by_bodyshape MUST be set to FALSE under the if(!icon_exists()) statement, or everything breaks. //"override_file = handled_by_bodyshape ? icon_file : null" MUST be added to the arguments of build_worn_icon() - //Friendly reminder that icon_exists(file, state, scream = TRUE) is your friend when debugging this code. + //Friendly reminder that icon_exists_or_scream(file, state) is your friend when debugging this code. var/handled_by_bodyshape = TRUE var/icon_file var/woman diff --git a/code/modules/surgery/bodyparts/_bodyparts.dm b/code/modules/surgery/bodyparts/_bodyparts.dm index 2d1b3570e3d96..2b6f111b2eb58 100644 --- a/code/modules/surgery/bodyparts/_bodyparts.dm +++ b/code/modules/surgery/bodyparts/_bodyparts.dm @@ -1058,7 +1058,7 @@ else limb.icon_state = "[limb_id]_[body_zone]" - icon_exists(limb.icon, limb.icon_state, TRUE) //Prints a stack trace on the first failure of a given iconstate. + icon_exists_or_scream(limb.icon, limb.icon_state) //Prints a stack trace on the first failure of a given iconstate. . += limb diff --git a/code/modules/unit_tests/suit_storage_icons.dm b/code/modules/unit_tests/suit_storage_icons.dm index 7cc987bb46801..543db168851bd 100644 --- a/code/modules/unit_tests/suit_storage_icons.dm +++ b/code/modules/unit_tests/suit_storage_icons.dm @@ -35,12 +35,12 @@ continue if(worn_icon) //easiest to check since we override everything. - if(!(icon_state in icon_states(worn_icon))) + if(!icon_exists(worn_icon, icon_state)) log_test("\t[count] - [item_path] using invalid [worn_icon_state ? "worn_icon_state" : "icon_state"], \"[icon_state]\" in worn_icon override file, '[worn_icon]'") count++ continue - if(!(icon_state in icon_states('icons/mob/clothing/belt_mirror.dmi'))) + if(!icon_exists('icons/mob/clothing/belt_mirror.dmi', icon_state)) already_warned_icons += icon_state log_test("\t[count] - [item_path] using invalid [worn_icon_state ? "worn_icon_state" : "icon_state"], \"[icon_state]\"") count++ diff --git a/code/modules/unit_tests/turf_icons.dm b/code/modules/unit_tests/turf_icons.dm index 6f37117289880..945130ada0c45 100644 --- a/code/modules/unit_tests/turf_icons.dm +++ b/code/modules/unit_tests/turf_icons.dm @@ -9,7 +9,7 @@ var/icon_file = initial(turf_path.icon) if(isnull(icon_state) || isnull(icon_file)) continue - if(!(icon_state in icon_states(icon_file))) + if(!icon_exists(icon_file, icon_state)) TEST_FAIL("[turf_path] using invalid icon_state - \"[icon_state]\" in icon file, '[icon_file]") for(var/turf/closed/mineral/turf_path as anything in typesof(/turf/closed/mineral)) //minerals use a special (read: snowflake) MAP_SWITCH definition that changes their icon based on if we're just compiling or if we're actually PLAYING the game. @@ -18,7 +18,7 @@ var/icon_file = initial(turf_path.icon) if(isnull(icon_state) || isnull(icon_file)) continue - if(!(icon_state in icon_states(icon_file))) + if(!icon_exists(icon_file, icon_state)) if(modular_mineral_turf_file && (icon_state in icon_states(modular_mineral_turf_file, 1))) continue if(!(icon_state in icon_states('icons/turf/mining.dmi', 1))) @@ -45,13 +45,13 @@ var/list/burnt_states = instanced_turf.burnt_states() for(var/state in burnt_states) - if(!(state in icon_states(damaged_dmi))) + if(!icon_exists(damaged_dmi, state)) TEST_FAIL("[open_turf_path] has an invalid icon in burnt_states - \"[state]\", in '[damaged_dmi]'") var/list/broken_states = instanced_turf.broken_states() for(var/state in broken_states) - if(!(state in icon_states(damaged_dmi))) + if(!icon_exists(damaged_dmi, state)) TEST_FAIL("[open_turf_path] has an invalid icon in broken_states - \"[state]\", in '[damaged_dmi]'") run_loc_floor_bottom_left = run_loc_floor_bottom_left.ChangeTurf(initial_turf_type) //cleanup. From 584d6b2fc7fd0f6b2000a74c215a1c24ddc0ba97 Mon Sep 17 00:00:00 2001 From: Roxy <75404941+TealSeer@users.noreply.github.com> Date: Wed, 5 Feb 2025 13:00:42 -0600 Subject: [PATCH 047/104] Fix silicon state laws window for 516 (#89354) ## About The Pull Request Switch the state laws UI for silicons to use the browser datum cause it's just raw HTML on 516 ## Why It's Good For The Game They gotta state those laws ## Changelog --- code/modules/mob/living/silicon/silicon.dm | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/code/modules/mob/living/silicon/silicon.dm b/code/modules/mob/living/silicon/silicon.dm index 3a494d2595c2b..265c27e587078 100644 --- a/code/modules/mob/living/silicon/silicon.dm +++ b/code/modules/mob/living/silicon/silicon.dm @@ -315,7 +315,7 @@ if (laws.zeroth) if (!(laws.zeroth in lawcheck)) law_display = "No" - list += {"[law_display] 0: [laws.zeroth]
"} + list += {"[law_display] 0: [laws.zeroth]
"} for (var/index in 1 to length(laws.hacked)) law_display = "Yes" @@ -323,7 +323,7 @@ if (length(law) > 0) if (!(law in hackedcheck)) law_display = "No" - list += {"[law_display] [ion_num()]: [law]
"} + list += {"[law_display] [ion_num()]: [law]
"} for (var/index in 1 to length(laws.ion)) law_display = "Yes" @@ -331,7 +331,7 @@ if (length(law) > 0) if(!(law in ioncheck)) law_display = "No" - list += {"[law_display] [ion_num()]: [law]
"} + list += {"[law_display] [ion_num()]: [law]
"} var/number = 1 for (var/index in 1 to length(laws.inherent)) @@ -340,7 +340,7 @@ if (length(law) > 0) if (!(law in lawcheck)) law_display = "No" - list += {"[law_display] [number]: [law]
"} + list += {"[law_display] [number]: [law]
"} number++ for (var/index in 1 to length(laws.supplied)) @@ -349,11 +349,13 @@ if (length(law) > 0) if (!(law in lawcheck)) law_display = "No" - list += {"[law_display] [number]: [law]
"} + list += {"[law_display] [number]: [law]
"} number++ - list += {"

State Laws"} + list += {"

State Laws"} - usr << browse(list, "window=laws") + var/datum/browser/browser = new(usr, "laws") + browser.set_content(list) + browser.open() /mob/living/silicon/proc/ai_roster() if(!client) From 25eb08420a0247bfa7456a6ccd74c1e9e1304abf Mon Sep 17 00:00:00 2001 From: Y0SH1M4S73R Date: Wed, 5 Feb 2025 14:01:42 -0500 Subject: [PATCH 048/104] Temporary bodies return players to minds without bodies (#89323) ## About The Pull Request There are a couple of cases where ghost roles that give the temporary body component prevent you from returning to the round when they really shouldn't. The particular cases are: - You entered a temporary body while you had no body, but could be recovered via means such as podcloning - You enter a temporary body, and while in that body, your original body is permanently removed while your mind could be recovered via means such as podcloning - Basketball This PR addresses those cases by allowing the temporary body component to operate with a null `old_body`, and allowing the temporary body component to be given to ghosts whose minds don't have bodies. ## Why It's Good For The Game Erroneous DNRs caused by code oversights are probably very undesirable to the playerbase. ## Changelog :cl: fix: Joining a minigame or taking certain ghost roles, while you have a mind without a body, will no longer DNR you, just in case you can be resurrected by some means. fix: If your old body is permanently destroyed while you are playing a minigame or as certain ghost roles, you will still return to your character's original mind, just in case you can be resurrected by some means. fix: The basketball minigame now gives its players and referee temporary bodies. /:cl: --- code/datums/components/temporary_body.dm | 16 +++++++++------- code/modules/antagonists/cult/runes.dm | 2 +- code/modules/basketball/controller.dm | 6 ++++++ code/modules/bitrunning/server/threats.dm | 2 +- code/modules/bitrunning/spawners.dm | 2 +- code/modules/capture_the_flag/ctf_game.dm | 2 +- code/modules/deathmatch/deathmatch_lobby.dm | 2 +- code/modules/mafia/roles/roles.dm | 2 +- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/code/datums/components/temporary_body.dm b/code/datums/components/temporary_body.dm index 28a7000a4951d..deadf90e6f99d 100644 --- a/code/datums/components/temporary_body.dm +++ b/code/datums/components/temporary_body.dm @@ -14,11 +14,12 @@ var/delete_on_death = FALSE /datum/component/temporary_body/Initialize(datum/mind/old_mind, mob/living/old_body, delete_on_death = FALSE) - if(!isliving(parent) || !isliving(old_body)) + if(!isliving(parent)) return COMPONENT_INCOMPATIBLE - ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) src.old_mind_ref = WEAKREF(old_mind) - src.old_body_ref = WEAKREF(old_body) + if(istype(old_body)) + ADD_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) + src.old_body_ref = WEAKREF(old_body) src.delete_on_death = delete_on_death /datum/component/temporary_body/RegisterWithParent() @@ -38,9 +39,9 @@ /datum/component/temporary_body/proc/on_parent_destroy() SIGNAL_HANDLER var/datum/mind/old_mind = old_mind_ref?.resolve() - var/mob/living/old_body = old_body_ref?.resolve() + var/mob/living/old_body = old_body_ref?.resolve() || old_mind.current - if(!old_mind || !old_body) + if(!old_mind) return var/mob/living/living_parent = parent @@ -50,12 +51,13 @@ if(!ghost) CRASH("[src] belonging to [parent] was completely unable to find a ghost to put back into a body!") ghost.mind = old_mind - if(old_body.stat != DEAD) + if(old_body?.stat != DEAD) old_mind.transfer_to(old_body, force_key_move = TRUE) else old_mind.set_current(old_body) - REMOVE_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) + if(old_body) + REMOVE_TRAIT(old_body, TRAIT_MIND_TEMPORARILY_GONE, REF(src)) old_mind = null old_body = null diff --git a/code/modules/antagonists/cult/runes.dm b/code/modules/antagonists/cult/runes.dm index a01217ea4f969..b779388947ec4 100644 --- a/code/modules/antagonists/cult/runes.dm +++ b/code/modules/antagonists/cult/runes.dm @@ -1027,7 +1027,7 @@ GLOBAL_VAR_INIT(narsie_summon_count, 0) visible_message(span_warning("A cloud of red mist forms above [src], and from within steps... a [new_human.gender == FEMALE ? "wo":""]man.")) to_chat(user, span_cult_italic("Your blood begins flowing into [src]. You must remain in place and conscious to maintain the forms of those summoned. This will hurt you slowly but surely...")) var/obj/structure/emergency_shield/cult/weak/N = new(T) - if(ghost_to_spawn.mind && ghost_to_spawn.mind.current) + if(ghost_to_spawn.mind && ghost_to_spawn.mind) new_human.AddComponent( \ /datum/component/temporary_body, \ old_mind = ghost_to_spawn.mind, \ diff --git a/code/modules/basketball/controller.dm b/code/modules/basketball/controller.dm index 4373c8d784a8d..20b3b0ecdaff2 100644 --- a/code/modules/basketball/controller.dm +++ b/code/modules/basketball/controller.dm @@ -192,6 +192,12 @@ GLOBAL_VAR(basketball_game) var/client/player_client = GLOB.directory[player_key] if(player_client) player_client.prefs.safe_transfer_prefs_to(baller, is_antag = TRUE) + if(player_client.mob.mind) + baller.AddComponent( \ + /datum/component/temporary_body, \ + old_mind = player_client.mob.mind, \ + old_body = player_client.mob.mind.current, \ + ) baller.key = player_key SEND_SOUND(baller, sound('sound/items/whistle/whistle.ogg', volume=30)) diff --git a/code/modules/bitrunning/server/threats.dm b/code/modules/bitrunning/server/threats.dm index 145cdc9ee2bbf..77d1c6b6cda59 100644 --- a/code/modules/bitrunning/server/threats.dm +++ b/code/modules/bitrunning/server/threats.dm @@ -113,7 +113,7 @@ var/datum/mind/ghost_mind = ghost.mind new_mob.key = ghost.key - if(ghost_mind?.current) + if(ghost_mind) new_mob.AddComponent(/datum/component/temporary_body, ghost_mind, ghost_mind.current, TRUE) var/datum/mind/antag_mind = new_mob.mind diff --git a/code/modules/bitrunning/spawners.dm b/code/modules/bitrunning/spawners.dm index 07e97837f522d..3ae116a4d71ce 100644 --- a/code/modules/bitrunning/spawners.dm +++ b/code/modules/bitrunning/spawners.dm @@ -9,7 +9,7 @@ /obj/effect/mob_spawn/ghost_role/human/virtual_domain/special(mob/living/spawned_mob, mob/mob_possessor) var/datum/mind/ghost_mind = mob_possessor.mind - if(ghost_mind?.current) // Preserves any previous bodies before making the switch + if(ghost_mind) // Preserves any previous bodies before making the switch spawned_mob.AddComponent(/datum/component/temporary_body, ghost_mind, ghost_mind.current, TRUE) ..() diff --git a/code/modules/capture_the_flag/ctf_game.dm b/code/modules/capture_the_flag/ctf_game.dm index 968e6e2953e95..17606b10d1504 100644 --- a/code/modules/capture_the_flag/ctf_game.dm +++ b/code/modules/capture_the_flag/ctf_game.dm @@ -153,7 +153,7 @@ player_mob.set_species(/datum/species/human) var/datum/mind/new_member_mind = new_team_member.mob.mind - if(new_member_mind?.current) + if(new_member_mind) player_mob.AddComponent( \ /datum/component/temporary_body, \ old_mind = new_member_mind, \ diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index 9a6773edec565..a99f4fabfe101 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -141,7 +141,7 @@ new_player.dna.update_dna_identity() new_player.updateappearance(icon_update = TRUE, mutcolor_update = TRUE, mutations_overlay_update = TRUE) new_player.add_traits(list(TRAIT_CANNOT_CRYSTALIZE, TRAIT_PERMANENTLY_MORTAL, TRAIT_TEMPORARY_BODY), INNATE_TRAIT) - if(!isnull(observer.mind) && observer.mind?.current) + if(observer.mind) new_player.AddComponent( \ /datum/component/temporary_body, \ old_mind = observer.mind, \ diff --git a/code/modules/mafia/roles/roles.dm b/code/modules/mafia/roles/roles.dm index b035b618ec4e7..77f46cddac74a 100644 --- a/code/modules/mafia/roles/roles.dm +++ b/code/modules/mafia/roles/roles.dm @@ -116,7 +116,7 @@ * Adds the playing_mafia trait so people examining them will know why they're currently lacking a soul. */ /datum/mafia_role/proc/put_player_in_body(client/player) - if(player.mob.mind && player.mob.mind.current) + if(player.mob.mind) body.AddComponent( \ /datum/component/temporary_body, \ old_mind = player.mob.mind, \ From e7efdddf48542fe5d208be4aad6e76cd0105cf35 Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 5 Feb 2025 14:06:11 -0500 Subject: [PATCH 049/104] Fix runtimes with `REMOVE_TRAITS_IN` (#89344) ## About The Pull Request ok so `REMOVE_TRAITS_IN` would sometimes run with like `type mismatch: null -= /list (/list)` credit to @RikuTheKiller for actually figuring this out and fixing it, here's their explaination on what caused the issue: > okay so > its due to linked traits > like knocked out which adds other traits > when knocked out is removed, it sends a removed signal > but sending that signal modifies the list mid for loop > so now when it tries to index it on the next iteration with a trait key thats already gone > it returns null, and tries to remove a list from a null > and it runtimes ## Why It's Good For The Game `REMOVE_TRAITS_IN` is a handy macro, and it'd be nice if it reliably worked ## Changelog no user-facing changes --- code/__DEFINES/traits/_traits.dm | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/code/__DEFINES/traits/_traits.dm b/code/__DEFINES/traits/_traits.dm index 7ebf1ad659046..0b1231c081fa6 100644 --- a/code/__DEFINES/traits/_traits.dm +++ b/code/__DEFINES/traits/_traits.dm @@ -74,7 +74,9 @@ var/list/_S = sources; \ if (_L) { \ for (var/_T in _L) { \ - _L[_T] &= _S;\ + if (_L[_T]) { \ + _L[_T] &= _S; \ + }; \ if (!length(_L[_T])) { \ _L -= _T; \ SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \ @@ -97,7 +99,9 @@ }; \ if (_L) { \ for (var/_T in _L) { \ - _L[_T] -= _S;\ + if (_L[_T]) { \ + _L[_T] -= _S; \ + }; \ if (!length(_L[_T])) { \ _L -= _T; \ SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T)); \ From 45e8c53cbeb14bf22ae62bd769fef26848d7a302 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 19:10:05 +0000 Subject: [PATCH 050/104] Automatic changelog for PR #89323 [ci skip] --- html/changelogs/AutoChangeLog-pr-89323.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89323.yml diff --git a/html/changelogs/AutoChangeLog-pr-89323.yml b/html/changelogs/AutoChangeLog-pr-89323.yml new file mode 100644 index 0000000000000..eaeeba1fdbb1d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89323.yml @@ -0,0 +1,6 @@ +author: "Y0SH1M4S73R" +delete-after: True +changes: + - bugfix: "Joining a minigame or taking certain ghost roles, while you have a mind without a body, will no longer DNR you, just in case you can be resurrected by some means." + - bugfix: "If your old body is permanently destroyed while you are playing a minigame or as certain ghost roles, you will still return to your character's original mind, just in case you can be resurrected by some means." + - bugfix: "The basketball minigame now gives its players and referee temporary bodies." \ No newline at end of file From f16b3279ca928db1e0957275a78ee2264347a66a Mon Sep 17 00:00:00 2001 From: Gaxeer <44334376+Gaxeer@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:53:22 +0200 Subject: [PATCH 051/104] Cleanup supply packs contents (#89342) ## About The Pull Request fix image display in `NT IRN` PDA app
Images present! ![image](https://github.com/user-attachments/assets/b9a5e733-9bc8-498e-bdaa-3531e0b142e5)
## Why It's Good For The Game Bug fixes good ## Changelog :cl: fix: fix image display in `NT IRN` PDA app for preview and contents /:cl: --- code/modules/cargo/goodies.dm | 10 ++++++++-- code/modules/cargo/orderconsole.dm | 18 +----------------- code/modules/cargo/packs/_packs.dm | 14 ++++++++++++++ code/modules/cargo/packs/organic.dm | 9 +++------ .../file_system/programs/budgetordering.dm | 7 ++++++- 5 files changed, 32 insertions(+), 26 deletions(-) diff --git a/code/modules/cargo/goodies.dm b/code/modules/cargo/goodies.dm index b4457f5613859..ee48e48e40303 100644 --- a/code/modules/cargo/goodies.dm +++ b/code/modules/cargo/goodies.dm @@ -78,7 +78,10 @@ desc = "For when the enemy absolutely needs to be replaced with lead. Contains one Aussec-designed Combat Shotgun, and one Shotgun Bandolier." cost = PAYCHECK_COMMAND * 15 access_view = ACCESS_ARMORY - contains = list(/obj/item/gun/ballistic/shotgun/automatic/combat, /obj/item/storage/belt/bandolier) + contains = list( + /obj/item/gun/ballistic/shotgun/automatic/combat, + /obj/item/storage/belt/bandolier + ) /datum/supply_pack/goody/disabler_single name = "Disabler Single-Pack" @@ -214,7 +217,10 @@ name = "Medipen Two-Pak" desc = "Contains one standard epinephrine medipen and one standard emergency medkit medipen. For when you want to prepare for the worst." cost = PAYCHECK_CREW * 2 - contains = list(/obj/item/reagent_containers/hypospray/medipen, /obj/item/reagent_containers/hypospray/medipen/ekit) + contains = list( + /obj/item/reagent_containers/hypospray/medipen, + /obj/item/reagent_containers/hypospray/medipen/ekit + ) /datum/supply_pack/goody/mothic_rations name = "Surplus Mothic Ration Pack" diff --git a/code/modules/cargo/orderconsole.dm b/code/modules/cargo/orderconsole.dm index 409dc197e43f5..e26c0ba739195 100644 --- a/code/modules/cargo/orderconsole.dm +++ b/code/modules/cargo/orderconsole.dm @@ -206,27 +206,11 @@ "goody" = pack.goody, "access" = pack.access, "contraband" = pack.contraband, - "contains" = get_pack_contains(pack), + "contains" = pack.get_contents_ui_data(), )) return packs -/** - * returns a list of the contents of a supply pack - * * pack - the pack to get the contents of - */ -/obj/machinery/computer/cargo/proc/get_pack_contains(datum/supply_pack/pack) - var/list/contains = list() - for(var/obj/item/item as anything in pack.contains) - contains += list(list( - "name" = item.name, - "icon" = item.greyscale_config ? null : item.icon, - "icon_state" = item.greyscale_config ? null : item.icon_state, - "amount" = pack.contains[item] - )) - - return contains - /** * returns the discount multiplier applied to all supply packs, * the discount is calculated as follows: pack_cost * get_discount() diff --git a/code/modules/cargo/packs/_packs.dm b/code/modules/cargo/packs/_packs.dm index bfa95b2a7ed25..94f71245882e5 100644 --- a/code/modules/cargo/packs/_packs.dm +++ b/code/modules/cargo/packs/_packs.dm @@ -45,6 +45,20 @@ /datum/supply_pack/New() id = type +/// Returns data used for cargo purchasing UI +/datum/supply_pack/proc/get_contents_ui_data() + var/list/data = list() + for(var/obj/item/item as anything in contains) + var/list/item_data = list( + "name" = item.name, + "icon" = item.greyscale_config ? null : item.icon, + "icon_state" = item.greyscale_config ? null : item.icon_state, + "amount" = contains[item] + ) + UNTYPED_LIST_ADD(data, item_data) + + return data + /datum/supply_pack/proc/generate(atom/A, datum/bank_account/paying_account) var/obj/structure/closet/crate/C if(paying_account) diff --git a/code/modules/cargo/packs/organic.dm b/code/modules/cargo/packs/organic.dm index a47c92fabc449..294179bf10732 100644 --- a/code/modules/cargo/packs/organic.dm +++ b/code/modules/cargo/packs/organic.dm @@ -10,10 +10,8 @@ desc = "Bee business booming? Better be benevolent and boost botany by \ bestowing bi-Beekeeper-suits! Contains two beekeeper suits and matching headwear." cost = CARGO_CRATE_VALUE * 2 - contains = list(/obj/item/clothing/head/utility/beekeeper_head, - /obj/item/clothing/suit/utility/beekeeper_suit, - /obj/item/clothing/head/utility/beekeeper_head, - /obj/item/clothing/suit/utility/beekeeper_suit, + contains = list(/obj/item/clothing/head/utility/beekeeper_head = 2, + /obj/item/clothing/suit/utility/beekeeper_suit = 2, ) crate_name = "beekeeper suits" crate_type = /obj/structure/closet/crate/hydroponics @@ -363,8 +361,7 @@ desc = "A packaged box containing illegal coffee syrups. Possession of these carries a penalty established in the galactic penal code." cost = CARGO_CRATE_VALUE * 6 contains = list( - /obj/item/reagent_containers/cup/bottle/syrup_bottle/laughsyrup, - /obj/item/reagent_containers/cup/bottle/syrup_bottle/laughsyrup, + /obj/item/reagent_containers/cup/bottle/syrup_bottle/laughsyrup = 2, ) crate_name = "illegal syrups box" crate_type = /obj/structure/closet/crate/cardboard diff --git a/code/modules/modular_computers/file_system/programs/budgetordering.dm b/code/modules/modular_computers/file_system/programs/budgetordering.dm index 511c664c137ab..b05237436a13c 100644 --- a/code/modules/modular_computers/file_system/programs/budgetordering.dm +++ b/code/modules/modular_computers/file_system/programs/budgetordering.dm @@ -94,13 +94,18 @@ ) if((P.hidden && (P.contraband && !contraband) || (P.special && !P.special_enabled) || P.drop_pod_only)) continue + + var/obj/item/first_item = length(P.contains) > 0 ? P.contains[1] : null data["supplies"][P.group]["packs"] += list(list( "name" = P.name, "cost" = P.get_cost(), "id" = pack, "desc" = P.desc || P.name, // If there is a description, use it. Otherwise use the pack's name. + "first_item_icon" = first_item?.icon, + "first_item_icon_state" = first_item?.icon_state, "goody" = P.goody, - "access" = P.access + "access" = P.access, + "contains" = P.get_contents_ui_data(), )) //Data regarding the User's capability to buy things. From dd2197b293ff862d7bd976a2e7027b71f4ad85fe Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:00:38 +0000 Subject: [PATCH 052/104] Automatic changelog for PR #89342 [ci skip] --- html/changelogs/AutoChangeLog-pr-89342.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89342.yml diff --git a/html/changelogs/AutoChangeLog-pr-89342.yml b/html/changelogs/AutoChangeLog-pr-89342.yml new file mode 100644 index 0000000000000..dcaf752d2a984 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89342.yml @@ -0,0 +1,4 @@ +author: "Gaxeer" +delete-after: True +changes: + - bugfix: "fix image display in `NT IRN` PDA app for preview and contents" \ No newline at end of file From 402065c19442ca04e2bbfb0dfd7a0cad03a16c78 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:53:18 +0100 Subject: [PATCH 053/104] Fixed wrong area/wall in Icemoon Underground - Round 3 (#89356) ## About The Pull Request ![StrongDMM_u12oSaxu6Q](https://github.com/user-attachments/assets/72df4f86-f0fb-4254-99c8-85b23701ac91) (No funny screenshot of me malding in-game this time) ## Changelog :cl: fix: Fixed wrong area/wall in Icemoon Underground /:cl: --- _maps/map_files/IceBoxStation/IceBoxStation.dmm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_maps/map_files/IceBoxStation/IceBoxStation.dmm b/_maps/map_files/IceBoxStation/IceBoxStation.dmm index 846042ad52e9e..7e0d66282425c 100644 --- a/_maps/map_files/IceBoxStation/IceBoxStation.dmm +++ b/_maps/map_files/IceBoxStation/IceBoxStation.dmm @@ -104229,7 +104229,7 @@ thA iDt psb rxz -gFX +wDU wDU aNw qmt From 19ac93c72ac781103c9dff6885348882a8ed0816 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Wed, 5 Feb 2025 23:53:38 +0000 Subject: [PATCH 054/104] Automatic changelog for PR #89356 [ci skip] --- html/changelogs/AutoChangeLog-pr-89356.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89356.yml diff --git a/html/changelogs/AutoChangeLog-pr-89356.yml b/html/changelogs/AutoChangeLog-pr-89356.yml new file mode 100644 index 0000000000000..b72975cf2271b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89356.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - bugfix: "Fixed wrong area/wall in Icemoon Underground" \ No newline at end of file From 96a0a39d97229a33415b2ececa05ca5a6811359a Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 00:28:10 +0000 Subject: [PATCH 055/104] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89231.yml | 4 --- html/changelogs/AutoChangeLog-pr-89245.yml | 4 --- html/changelogs/AutoChangeLog-pr-89323.yml | 6 ---- html/changelogs/AutoChangeLog-pr-89325.yml | 5 --- html/changelogs/AutoChangeLog-pr-89328.yml | 4 --- html/changelogs/AutoChangeLog-pr-89333.yml | 4 --- html/changelogs/AutoChangeLog-pr-89336.yml | 4 --- html/changelogs/AutoChangeLog-pr-89337.yml | 4 --- html/changelogs/AutoChangeLog-pr-89339.yml | 4 --- html/changelogs/AutoChangeLog-pr-89342.yml | 4 --- html/changelogs/AutoChangeLog-pr-89343.yml | 4 --- html/changelogs/AutoChangeLog-pr-89347.yml | 4 --- html/changelogs/AutoChangeLog-pr-89350.yml | 4 --- html/changelogs/AutoChangeLog-pr-89351.yml | 5 --- html/changelogs/AutoChangeLog-pr-89352.yml | 4 --- html/changelogs/AutoChangeLog-pr-89356.yml | 4 --- html/changelogs/archive/2025-02.yml | 42 ++++++++++++++++++++++ 17 files changed, 42 insertions(+), 68 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89231.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89245.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89323.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89325.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89328.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89333.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89336.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89337.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89339.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89342.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89343.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89347.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89350.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89351.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89352.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89356.yml diff --git a/html/changelogs/AutoChangeLog-pr-89231.yml b/html/changelogs/AutoChangeLog-pr-89231.yml deleted file mode 100644 index 4bb6f363a93d1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89231.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Exester509" -delete-after: True -changes: - - map: "The Syndicate Lavaland base has been generally improved, with more defenses and comms equipment." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89245.yml b/html/changelogs/AutoChangeLog-pr-89245.yml deleted file mode 100644 index ad15f3b2dcc17..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89245.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - map: "Added cooling loops and cold tiles to all kitchen freezers that were missing them" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89323.yml b/html/changelogs/AutoChangeLog-pr-89323.yml deleted file mode 100644 index eaeeba1fdbb1d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89323.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "Y0SH1M4S73R" -delete-after: True -changes: - - bugfix: "Joining a minigame or taking certain ghost roles, while you have a mind without a body, will no longer DNR you, just in case you can be resurrected by some means." - - bugfix: "If your old body is permanently destroyed while you are playing a minigame or as certain ghost roles, you will still return to your character's original mind, just in case you can be resurrected by some means." - - bugfix: "The basketball minigame now gives its players and referee temporary bodies." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89325.yml b/html/changelogs/AutoChangeLog-pr-89325.yml deleted file mode 100644 index 78a89a5c0ff06..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89325.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "JohnFulpWillard" -delete-after: True -changes: - - bugfix: "Autolathes no longer have a scrollbar that sends you off the screen." - - bugfix: "Exosuit fabricators' queue list & Techfab/Autolathe's left side (with the sections of printables) now have a scrollbar when the full list doesn't fit on the UI for 516 users. Techfab/Autolathe also now does this for the list of items too, instead of always having one." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89328.yml b/html/changelogs/AutoChangeLog-pr-89328.yml deleted file mode 100644 index 1f69ece66f018..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89328.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - bugfix: "AI-controlled ventcrawling mobs (botanical spiderlings and legioned monkeys) can once more do so without killing themselves shortly afterwards." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89333.yml b/html/changelogs/AutoChangeLog-pr-89333.yml deleted file mode 100644 index 0ce3e5c3f6941..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89333.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - bugfix: "fixes virtual pet app changing PDA's colors when open" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89336.yml b/html/changelogs/AutoChangeLog-pr-89336.yml deleted file mode 100644 index 080af93ca5b0d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89336.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed incorrect power consumption on reagent grinders" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89337.yml b/html/changelogs/AutoChangeLog-pr-89337.yml deleted file mode 100644 index dc3cb897530eb..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89337.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed another two missing areas on icebox" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89339.yml b/html/changelogs/AutoChangeLog-pr-89339.yml deleted file mode 100644 index ff46e4b138498..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89339.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed stunprod's missing inhands sprite" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89342.yml b/html/changelogs/AutoChangeLog-pr-89342.yml deleted file mode 100644 index dcaf752d2a984..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89342.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Gaxeer" -delete-after: True -changes: - - bugfix: "fix image display in `NT IRN` PDA app for preview and contents" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89343.yml b/html/changelogs/AutoChangeLog-pr-89343.yml deleted file mode 100644 index 94510daa53cd7..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89343.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "Void Cloaks now properly hide blades and such in the suit storage from the wearer's sprite." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89347.yml b/html/changelogs/AutoChangeLog-pr-89347.yml deleted file mode 100644 index e16e678b24586..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89347.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Holoo-1" -delete-after: True -changes: - - bugfix: "fixed state laws window on 516" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89350.yml b/html/changelogs/AutoChangeLog-pr-89350.yml deleted file mode 100644 index 41931e722aefd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89350.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TiviPlus" -delete-after: True -changes: - - bugfix: "fixed some admin links not working on 516" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89351.yml b/html/changelogs/AutoChangeLog-pr-89351.yml deleted file mode 100644 index c84a5942e410d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89351.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Tactical medkits should no longer create invisible medbots" - - image: "Implemented the missing bezerk medbot skin" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89352.yml b/html/changelogs/AutoChangeLog-pr-89352.yml deleted file mode 100644 index bf0b2036cd2d0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89352.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed plant analyzers not being placeable on tables/in backpacks" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89356.yml b/html/changelogs/AutoChangeLog-pr-89356.yml deleted file mode 100644 index b72975cf2271b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89356.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - bugfix: "Fixed wrong area/wall in Icemoon Underground" \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index 9489c669b8d8f..21a6354c617f2 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -55,3 +55,45 @@ 2025-02-05: Melbert: - qol: Map vote tallies explains how they work if you hover them +2025-02-06: + Absolucy: + - bugfix: Void Cloaks now properly hide blades and such in the suit storage from + the wearer's sprite. + Ben10Omintrix: + - bugfix: fixes virtual pet app changing PDA's colors when open + Exester509: + - map: The Syndicate Lavaland base has been generally improved, with more defenses + and comms equipment. + Gaxeer: + - bugfix: fix image display in `NT IRN` PDA app for preview and contents + Holoo-1: + - bugfix: fixed state laws window on 516 + Jacquerel: + - bugfix: AI-controlled ventcrawling mobs (botanical spiderlings and legioned monkeys) + can once more do so without killing themselves shortly afterwards. + JohnFulpWillard: + - bugfix: Autolathes no longer have a scrollbar that sends you off the screen. + - bugfix: Exosuit fabricators' queue list & Techfab/Autolathe's left side (with + the sections of printables) now have a scrollbar when the full list doesn't + fit on the UI for 516 users. Techfab/Autolathe also now does this for the list + of items too, instead of always having one. + SmArtKar: + - bugfix: Tactical medkits should no longer create invisible medbots + - image: Implemented the missing bezerk medbot skin + - bugfix: Fixed another two missing areas on icebox + - bugfix: Fixed incorrect power consumption on reagent grinders + - bugfix: Fixed wrong area/wall in Icemoon Underground + - map: Added cooling loops and cold tiles to all kitchen freezers that were missing + them + - bugfix: Fixed plant analyzers not being placeable on tables/in backpacks + - bugfix: Fixed stunprod's missing inhands sprite + TiviPlus: + - bugfix: fixed some admin links not working on 516 + Y0SH1M4S73R: + - bugfix: Joining a minigame or taking certain ghost roles, while you have a mind + without a body, will no longer DNR you, just in case you can be resurrected + by some means. + - bugfix: If your old body is permanently destroyed while you are playing a minigame + or as certain ghost roles, you will still return to your character's original + mind, just in case you can be resurrected by some means. + - bugfix: The basketball minigame now gives its players and referee temporary bodies. From 0261ad2997087b8e7364829a665de27a66ac4e93 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Wed, 5 Feb 2025 18:33:55 -0600 Subject: [PATCH 056/104] Small heretic patch (#89369) ## About The Pull Request Reported by https://github.com/ParadiseSS13/Paradise/pull/27873 , shoutout to them We used to check this in the distant past but it was lost across the reworks. Kinda important --- code/modules/antagonists/heretic/heretic_antag.dm | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/code/modules/antagonists/heretic/heretic_antag.dm b/code/modules/antagonists/heretic/heretic_antag.dm index 8466eaf3130f2..839fba2c77f39 100644 --- a/code/modules/antagonists/heretic/heretic_antag.dm +++ b/code/modules/antagonists/heretic/heretic_antag.dm @@ -205,8 +205,13 @@ if("research") var/datum/heretic_knowledge/researched_path = text2path(params["path"]) if(!ispath(researched_path, /datum/heretic_knowledge)) - CRASH("Heretic attempted to learn non-heretic_knowledge path! (Got: [researched_path])") - + CRASH("Heretic attempted to learn non-heretic_knowledge path! (Got: [researched_path || "invalid path"])") + if(!(researched_path in get_researchable_knowledge())) + message_admins("Heretic [key_name(owner)] potentially attempted to href exploit to learn knowledge they can't learn!") + CRASH("Heretic attempted to learn knowledge they can't learn! (Got: [researched_path])") + if(ispath(researched_path, /datum/heretic_knowledge/ultimate) && !can_ascend()) + message_admins("Heretic [key_name(owner)] potentially attempted to href exploit to learn ascension knowledge without completing objectives!") + CRASH("Heretic attempted to learn a final knowledge despite not being able to ascend!") if(initial(researched_path.cost) > knowledge_points) return TRUE if(!gain_knowledge(researched_path)) From 348413a8a66b30ba39a6713bca080030739cdfa1 Mon Sep 17 00:00:00 2001 From: Lucy Date: Wed, 5 Feb 2025 20:27:55 -0500 Subject: [PATCH 057/104] Add a `DISABLE_DREAMLUAU` define, for disabling dreamluau at compile-time (#89359) ## About The Pull Request this adds a new define, `DISABLE_DREAMLUAU` (commented out by default), which does... exactly what it says on the tin. it fully disables any dreamluau-related code (the "Open Lua Editor" admin verb is left in, albeit just giving the user a warning saying Lua is disabled, just so there's no confusion about the verb itself being missing) when compiling with OpenDream outside of CI (so dreamluau code will still be linted), `DISABLE_DREAMLUAU` will be defined by default, tho. ## Why It's Good For The Game makes OpenDream testing easier ## Changelog no user-facing changes. or even code changes for most cases. --- code/__HELPERS/_dreamluau.dm | 2 ++ code/_compile_options.dm | 10 ++++++++++ code/controllers/subsystem/garbage.dm | 2 ++ code/controllers/subsystem/lua.dm | 2 ++ code/datums/datum.dm | 2 ++ code/game/atom/_atom.dm | 2 ++ code/game/atoms_movable.dm | 2 ++ code/game/world.dm | 2 ++ code/modules/admin/topic.dm | 2 ++ code/modules/admin/verbs/lua/_wrappers.dm | 2 ++ code/modules/admin/verbs/lua/helpers.dm | 2 ++ code/modules/admin/verbs/lua/lua_editor.dm | 6 ++++++ code/modules/admin/verbs/lua/lua_state.dm | 2 ++ code/modules/error_handler/error_handler.dm | 4 ++++ 14 files changed, 42 insertions(+) diff --git a/code/__HELPERS/_dreamluau.dm b/code/__HELPERS/_dreamluau.dm index d8bb784c217a2..9436b95c55196 100644 --- a/code/__HELPERS/_dreamluau.dm +++ b/code/__HELPERS/_dreamluau.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU /* This comment bypasses grep checks */ /var/__dreamluau /* This comment also bypasses grep checks */ /var/__dreamluau_exists @@ -299,3 +300,4 @@ */ #define DREAMLUAU_CLEAR_REF_USERDATA(object) DREAMLUAU_CALL(clear_ref_userdata)((object)) +#endif diff --git a/code/_compile_options.dm b/code/_compile_options.dm index 2bd9309406a0a..ee53eb99b8d73 100644 --- a/code/_compile_options.dm +++ b/code/_compile_options.dm @@ -106,6 +106,16 @@ /// If this is uncommented, will profile mapload atom initializations // #define PROFILE_MAPLOAD_INIT_ATOM +/// If uncommented, Dreamluau will be fully disabled. +// #define DISABLE_DREAMLUAU + +// OpenDream currently doesn't support byondapi, so automatically disable it on OD, +// unless CIBUILDING is defined - we still want to lint dreamluau-related code. +// Get rid of this whenever it does have support. +#if defined(OPENDREAM) && !defined(SPACEMAN_DMM) && !defined(CIBUILDING) +#define DISABLE_DREAMLUAU +#endif + /// If this is uncommented, force our verb processing into just the 2% of a tick /// We normally reserve for it /// NEVER run this on live, it's for simulating highpop only diff --git a/code/controllers/subsystem/garbage.dm b/code/controllers/subsystem/garbage.dm index ad1b9e4132fed..b9c8a08ca751e 100644 --- a/code/controllers/subsystem/garbage.dm +++ b/code/controllers/subsystem/garbage.dm @@ -346,7 +346,9 @@ SUBSYSTEM_DEF(garbage) /// Datums passed to this will be given a chance to clean up references to allow the GC to collect them. /proc/qdel(datum/to_delete, force = FALSE) if(!istype(to_delete)) +#ifndef DISABLE_DREAMLUAU DREAMLUAU_CLEAR_REF_USERDATA(to_delete) +#endif del(to_delete) return diff --git a/code/controllers/subsystem/lua.dm b/code/controllers/subsystem/lua.dm index 99df8cf335490..2d199ccd3dcc3 100644 --- a/code/controllers/subsystem/lua.dm +++ b/code/controllers/subsystem/lua.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU SUBSYSTEM_DEF(lua) name = "Lua Scripting" runlevels = RUNLEVEL_LOBBY | RUNLEVELS_DEFAULT @@ -156,3 +157,4 @@ SUBSYSTEM_DEF(lua) continue state.log_result(json_data) return +#endif diff --git a/code/datums/datum.dm b/code/datums/datum.dm index 8337dac113178..c3c800bd85c93 100644 --- a/code/datums/datum.dm +++ b/code/datums/datum.dm @@ -142,9 +142,11 @@ _clear_signal_refs() //END: ECS SHIT +#ifndef DISABLE_DREAMLUAU if(!(datum_flags & DF_STATIC_OBJECT)) DREAMLUAU_CLEAR_REF_USERDATA(vars) // vars ceases existing when src does, so we need to clear any lua refs to it that exist. DREAMLUAU_CLEAR_REF_USERDATA(src) +#endif return QDEL_HINT_QUEUE diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index a7d057aa9fa4d..a00838691670d 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -186,12 +186,14 @@ if(smoothing_flags & SMOOTH_QUEUED) SSicon_smooth.remove_from_queues(src) +#ifndef DISABLE_DREAMLUAU // These lists cease existing when src does, so we need to clear any lua refs to them that exist. if(!(datum_flags & DF_STATIC_OBJECT)) DREAMLUAU_CLEAR_REF_USERDATA(contents) DREAMLUAU_CLEAR_REF_USERDATA(filters) DREAMLUAU_CLEAR_REF_USERDATA(overlays) DREAMLUAU_CLEAR_REF_USERDATA(underlays) +#endif return ..() diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index e6fe68ea4c487..5c61186b585f0 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -237,9 +237,11 @@ LAZYNULL(client_mobs_in_contents) +#ifndef DISABLE_DREAMLUAU // These lists cease existing when src does, so we need to clear any lua refs to them that exist. DREAMLUAU_CLEAR_REF_USERDATA(vis_contents) DREAMLUAU_CLEAR_REF_USERDATA(vis_locs) +#endif . = ..() diff --git a/code/game/world.dm b/code/game/world.dm index ea6c9cb976ff2..79ba0f231e992 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -503,7 +503,9 @@ GLOBAL_PROTECT(tracy_init_reason) /world/proc/on_tickrate_change() SStimer?.reset_buckets() +#ifndef DISABLE_DREAMLUAU DREAMLUAU_SET_EXECUTION_LIMIT_MILLIS(tick_lag * 100) +#endif /world/proc/init_byond_tracy() if(!fexists(TRACY_DLL_PATH)) diff --git a/code/modules/admin/topic.dm b/code/modules/admin/topic.dm index 71374bf2464ff..9dbac57315d23 100644 --- a/code/modules/admin/topic.dm +++ b/code/modules/admin/topic.dm @@ -1699,6 +1699,7 @@ return return usr.client?.mark_datum(datum_to_mark) +#ifndef DISABLE_DREAMLUAU else if(href_list["lua_state"]) if(!check_rights(R_DEBUG)) return @@ -1715,6 +1716,7 @@ editor.force_view_chunk = log_entry["chunk"] editor.force_modal = "viewChunk" editor.ui_interact(usr) +#endif else if(href_list["show_paper"]) if(!check_rights(R_ADMIN)) diff --git a/code/modules/admin/verbs/lua/_wrappers.dm b/code/modules/admin/verbs/lua/_wrappers.dm index d516f064f847f..5fd78244b5603 100644 --- a/code/modules/admin/verbs/lua/_wrappers.dm +++ b/code/modules/admin/verbs/lua/_wrappers.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU /proc/wrap_lua_get_var(datum/thing, var_name) SHOULD_NOT_SLEEP(TRUE) if(thing == world) @@ -46,3 +47,4 @@ var/result = list("status" = "print", "message" = print_message) INVOKE_ASYNC(target_state, TYPE_PROC_REF(/datum/lua_state, log_result), result, TRUE) log_lua("[target_state]: [print_message]") +#endif diff --git a/code/modules/admin/verbs/lua/helpers.dm b/code/modules/admin/verbs/lua/helpers.dm index c3072f15e74cd..fe844c5c55fa2 100644 --- a/code/modules/admin/verbs/lua/helpers.dm +++ b/code/modules/admin/verbs/lua/helpers.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU #define PROMISE_PENDING 0 #define PROMISE_RESOLVED 1 #define PROMISE_REJECTED 2 @@ -34,3 +35,4 @@ #undef PROMISE_PENDING #undef PROMISE_RESOLVED #undef PROMISE_REJECTED +#endif diff --git a/code/modules/admin/verbs/lua/lua_editor.dm b/code/modules/admin/verbs/lua/lua_editor.dm index 93e8e50c1a6a4..280bd52a57d72 100644 --- a/code/modules/admin/verbs/lua/lua_editor.dm +++ b/code/modules/admin/verbs/lua/lua_editor.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU /datum/lua_editor var/datum/lua_state/current_state @@ -279,7 +280,12 @@ /datum/lua_editor/ui_close(mob/user) . = ..() qdel(src) +#endif ADMIN_VERB(lua_editor, R_DEBUG, "Open Lua Editor", "Its codin' time.", ADMIN_CATEGORY_DEBUG) +#ifndef DISABLE_DREAMLUAU var/datum/lua_editor/editor = new editor.ui_interact(user.mob) +#else + to_chat(user, span_warning("Lua support has been disabled at compile-time."), type = MESSAGE_TYPE_ADMINLOG, confidential = TRUE) // doing this instead of just disabling the verb entirely so it's clear WHY it doesn't work. +#endif diff --git a/code/modules/admin/verbs/lua/lua_state.dm b/code/modules/admin/verbs/lua/lua_state.dm index 30bc21c83b2be..53b869e23a1df 100644 --- a/code/modules/admin/verbs/lua/lua_state.dm +++ b/code/modules/admin/verbs/lua/lua_state.dm @@ -1,3 +1,4 @@ +#ifndef DISABLE_DREAMLUAU #define MAX_LOG_REPEAT_LOOKBACK 5 GLOBAL_DATUM(lua_usr, /mob) @@ -232,3 +233,4 @@ GLOBAL_PROTECT(lua_state_stack) SStgui.update_uis(editor) #undef MAX_LOG_REPEAT_LOOKBACK +#endif diff --git a/code/modules/error_handler/error_handler.dm b/code/modules/error_handler/error_handler.dm index 6585f92f9b61c..7cdc43317e73f 100644 --- a/code/modules/error_handler/error_handler.dm +++ b/code/modules/error_handler/error_handler.dm @@ -103,12 +103,14 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) // The proceeding mess will almost definitely break if error messages are ever changed var/list/splitlines = splittext(E.desc, "\n") var/list/desclines = list() +#ifndef DISABLE_DREAMLUAU var/list/state_stack = GLOB.lua_state_stack var/is_lua_call = length(state_stack) var/list/lua_stacks = list() if(is_lua_call) for(var/level in 1 to state_stack.len) lua_stacks += list(splittext(DREAMLUAU_GET_TRACEBACK(level), "\n")) +#endif if(LAZYLEN(splitlines) > ERROR_USEFUL_LEN) // If there aren't at least three lines, there's no info for(var/line in splitlines) if(LAZYLEN(line) < 3 || findtext(line, "source file:") || findtext(line, "usr.loc:")) @@ -124,8 +126,10 @@ GLOBAL_VAR_INIT(total_runtimes_skipped, 0) desclines += line if(usrinfo) //If this info isn't null, it hasn't been added yet desclines.Add(usrinfo) +#ifndef DISABLE_DREAMLUAU if(is_lua_call) SSlua.log_involved_runtime(E, desclines, lua_stacks) +#endif if(silencing) desclines += " (This error will now be silenced for [DisplayTimeText(configured_error_silence_time)])" if(GLOB.error_cache) From d7130a459894b3a28e2059454ffd1677d3db4f70 Mon Sep 17 00:00:00 2001 From: Runi-c <5150427+Runi-c@users.noreply.github.com> Date: Wed, 5 Feb 2025 21:37:22 -0700 Subject: [PATCH 058/104] Make slips eligible for shove stuns (#89313) ## About The Pull Request Adds slips to the list of existing shove stun methods originally set in https://github.com/tgstation/tgstation/pull/84640 (wall shoves, telebaton, mansus grasp), and also reifies this concept as the "dazed" status effect. This makes it so that being knocked down from a slip from any source (e.g. wet floor, clown stuff, lube, foam, oil, butterdog) gives the dazed visual effect and makes you eligible for being shove stunned. The status always lasts for 3 seconds even if e.g. slipping on lube knocks you down for 15, but this can be customized per slip. ## Why It's Good For The Game Further rewards environmental play and provides another feasible means of fighting back against better equipped opponents, both in line with the original PR. Also the visual cue fits well as an immediate signal that you're dazed and can't get up. ## Changelog :cl: balance: slips now make you eligible for being shove stunned /:cl: --------- Co-authored-by: Roryl-c <5150427+Roryl-c@users.noreply.github.com> --- .../signals/signals_mob/signals_mob_living.dm | 2 +- code/__DEFINES/traits/declarations.dm | 2 +- code/_globalvars/traits/_traits.dm | 2 +- code/_globalvars/traits/admin_tooling.dm | 1 + code/datums/components/slippery.dm | 10 +++- .../status_effects/debuffs/staggered.dm | 56 +++++++++++-------- code/game/atom/atom_act.dm | 2 +- code/game/objects/items/melee/baton.dm | 2 +- .../objects/structures/beds_chairs/chair.dm | 14 ++--- code/game/objects/structures/tables_racks.dm | 3 +- code/game/turfs/open/_open.dm | 4 +- .../antagonists/heretic/magic/mansus_grasp.dm | 3 +- code/modules/meteors/meteor_types.dm | 2 +- .../mob/living/carbon/carbon_defense.dm | 2 +- .../mob/living/carbon/carbon_movement.dm | 4 +- .../mob/living/carbon/human/human_defense.dm | 6 +- .../mob/living/carbon/human/human_movement.dm | 2 +- .../mob/living/carbon/human/status_procs.dm | 2 +- code/modules/mob/living/living_defense.dm | 3 +- code/modules/mob/living/status_procs.dm | 8 ++- code/modules/mob/mob_movement.dm | 5 +- .../projectiles/projectile/bullets/special.dm | 2 +- .../reagents/chemistry/recipes/others.dm | 2 +- 23 files changed, 79 insertions(+), 60 deletions(-) diff --git a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm index 3569b9af1e61d..b687ef5ace2a2 100644 --- a/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm +++ b/code/__DEFINES/dcs/signals/signals_mob/signals_mob_living.dm @@ -43,7 +43,7 @@ #define COMSIG_LIVING_REVIVE "living_revive" ///from base of mob/living/set_buckled(): (new_buckled) #define COMSIG_LIVING_SET_BUCKLED "living_set_buckled" -///from base of mob/living/set_body_position() +///from base of mob/living/set_body_position(): (new_position, old_position) #define COMSIG_LIVING_SET_BODY_POSITION "living_set_body_position" /// Sent to a mob being injected with a syringe when the do_after initiates #define COMSIG_LIVING_TRY_SYRINGE_INJECT "living_try_syringe_inject" diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 5cfca56548424..b7069943e9099 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -616,7 +616,7 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai #define TRAIT_DISPLAY_JOB_IN_BINARY "display job in binary" /// Trait that determines vulnerability to being stunned from a shove -#define TRAIT_STUN_ON_NEXT_SHOVE "stun on next shove" +#define TRAIT_DAZED "dazed" /// Trait that determines whether our mob gains more strength from drinking during a fist fight #define TRAIT_DRUNKEN_BRAWLER "drunken brawler" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index b69de9ab16418..6d4e0be910bbd 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -205,6 +205,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION, "TRAIT_CULT_HALO" = TRAIT_CULT_HALO, "TRAIT_CURSED" = TRAIT_CURSED, + "TRAIT_DAZED" = TRAIT_DAZED, "TRAIT_DEAF" = TRAIT_DEAF, "TRAIT_DEATHCOMA" = TRAIT_DEATHCOMA, "TRAIT_DEFIB_BLACKLISTED" = TRAIT_DEFIB_BLACKLISTED, @@ -511,7 +512,6 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_STRONG_STOMACH" = TRAIT_STRONG_STOMACH, "TRAIT_STUBBY_BODY" = TRAIT_STUBBY_BODY, "TRAIT_STUNIMMUNE" = TRAIT_STUNIMMUNE, - "TRAIT_STUN_ON_NEXT_SHOVE" = TRAIT_STUN_ON_NEXT_SHOVE, "TRAIT_STURDY_FRAME" = TRAIT_STURDY_FRAME, "TRAIT_SUCCUMB_OVERRIDE" = TRAIT_SUCCUMB_OVERRIDE, "TRAIT_SUICIDED" = TRAIT_SUICIDED, diff --git a/code/_globalvars/traits/admin_tooling.dm b/code/_globalvars/traits/admin_tooling.dm index 9824c6eb71405..093ed55b5c8c1 100644 --- a/code/_globalvars/traits/admin_tooling.dm +++ b/code/_globalvars/traits/admin_tooling.dm @@ -75,6 +75,7 @@ GLOBAL_LIST_INIT(admin_visible_traits, list( "TRAIT_CORPSELOCKED" = TRAIT_CORPSELOCKED, "TRAIT_CRITICAL_CONDITION" = TRAIT_CRITICAL_CONDITION, "TRAIT_CULT_HALO" = TRAIT_CULT_HALO, + "TRAIT_DAZED" = TRAIT_DAZED, "TRAIT_DEAF" = TRAIT_DEAF, "TRAIT_DEATHCOMA" = TRAIT_DEATHCOMA, "TRAIT_DEFIB_BLACKLISTED" = TRAIT_DEFIB_BLACKLISTED, diff --git a/code/datums/components/slippery.dm b/code/datums/components/slippery.dm index 8d2dbda379eda..370b3406ff9ff 100644 --- a/code/datums/components/slippery.dm +++ b/code/datums/components/slippery.dm @@ -23,6 +23,8 @@ var/knockdown_time = 0 /// How long the slip paralyzes (prevents the crossing mob doing anything) for. var/paralyze_time = 0 + /// How long the slip dazes (makes the crossing mob vulnerable to shove stuns) for. + var/daze_time = 3 SECONDS /// Flags for how slippery the parent is. See [__DEFINES/mobs.dm] var/lube_flags /// Optional callback allowing you to define custom conditions for slipping @@ -53,6 +55,7 @@ * * lube_flags - Controls the slip behaviour, they are listed starting [here][SLIDE] * * datum/callback/on_slip_callback - Callback to define further custom controls on when slipping is applied * * paralyze - length of time to paralyze the crossing mob for (Deciseconds) + * * daze - length of time to daze the crossing mob for (Deciseconds), default 3 seconds * * force_drop - should the crossing mob drop items in its hands or not * * slot_whitelist - flags controlling where on a mob this item can be equipped to make the parent mob slippery full list [here][ITEM_SLOT_OCLOTHING] * * datum/callback/on_slip_callback - Callback to add custom behaviours as the crossing mob is slipped @@ -62,12 +65,14 @@ lube_flags = NONE, datum/callback/on_slip_callback, paralyze, + daze = 3 SECONDS, force_drop = FALSE, slot_whitelist, datum/callback/can_slip_callback, ) src.knockdown_time = max(knockdown, 0) src.paralyze_time = max(paralyze, 0) + src.daze_time = max(daze, 0) src.force_drop_items = force_drop src.lube_flags = lube_flags src.can_slip_callback = can_slip_callback @@ -126,6 +131,7 @@ lube_flags = NONE, datum/callback/on_slip_callback, paralyze, + daze, force_drop = FALSE, slot_whitelist, datum/callback/can_slip_callback, @@ -136,11 +142,13 @@ on_slip_callback = component.on_slip_callback can_slip_callback = component.on_slip_callback paralyze = component.paralyze_time + daze = component.daze_time force_drop = component.force_drop_items slot_whitelist = component.slot_whitelist src.knockdown_time = max(knockdown, 0) src.paralyze_time = max(paralyze, 0) + src.daze_time = max(daze, 0) src.force_drop_items = force_drop src.lube_flags = lube_flags src.on_slip_callback = on_slip_callback @@ -167,7 +175,7 @@ return if(can_slip_callback && !can_slip_callback.Invoke(holder, victim)) return - if(victim.slip(knockdown_time, parent, lube_flags, paralyze_time, force_drop_items)) + if(victim.slip(knockdown_time, parent, lube_flags, paralyze_time, daze_time, force_drop_items)) on_slip_callback?.Invoke(victim) /** diff --git a/code/datums/status_effects/debuffs/staggered.dm b/code/datums/status_effects/debuffs/staggered.dm index dcb5dc5488800..1498cdb791681 100644 --- a/code/datums/status_effects/debuffs/staggered.dm +++ b/code/datums/status_effects/debuffs/staggered.dm @@ -51,62 +51,74 @@ animate(pixel_x = normal_pos, time = 0.2 SECONDS) /// Status effect specifically for instances where someone is vulnerable to being stunned when shoved. -/datum/status_effect/next_shove_stuns - id = "next shove stuns" - duration = 3 SECONDS +/datum/status_effect/dazed + id = "dazed" status_type = STATUS_EFFECT_UNIQUE tick_interval = 0.5 SECONDS alert_type = null remove_on_fullheal = TRUE /// Our visual cue for the vulnerable state this status effect puts us in. - var/mutable_appearance/vulnverability_overlay + var/mutable_appearance/dazed_overlay -/datum/status_effect/next_shove_stuns/on_apply() +/datum/status_effect/dazed/on_creation(mob/living/new_owner, duration = 3 SECONDS) + src.duration = duration + return ..() + +/datum/status_effect/dazed/on_apply() //Let's just clear this if they're dead or we can't stun them on a shove if(owner.stat == DEAD || HAS_TRAIT(owner, TRAIT_NO_SIDE_KICK) || HAS_TRAIT(owner, TRAIT_IMMOBILIZED)) return FALSE - RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_stun_vulnverability_on_death)) + RegisterSignal(owner, COMSIG_LIVING_DEATH, PROC_REF(clear_daze_on_death)) + RegisterSignal(owner, COMSIG_LIVING_SET_BODY_POSITION, PROC_REF(clear_daze_on_stand)) RegisterSignals(owner, list( COMSIG_LIVING_STATUS_PARALYZE, COMSIG_LIVING_STATUS_STUN, - COMSIG_LIVING_STATUS_IMMOBILIZE), PROC_REF(clear_stun_vulnverability) + COMSIG_LIVING_STATUS_IMMOBILIZE), PROC_REF(clear_daze) ) - ADD_TRAIT(owner, TRAIT_STUN_ON_NEXT_SHOVE, TRAIT_STATUS_EFFECT(id)) - vulnverability_overlay = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "dazed") - owner.add_overlay(vulnverability_overlay) + ADD_TRAIT(owner, TRAIT_DAZED, TRAIT_STATUS_EFFECT(id)) + dazed_overlay = mutable_appearance(icon = 'icons/effects/effects.dmi', icon_state = "dazed") + owner.add_overlay(dazed_overlay) return TRUE -/datum/status_effect/next_shove_stuns/on_remove() +/datum/status_effect/dazed/on_remove() UnregisterSignal(owner, list( + COMSIG_LIVING_DEATH, + COMSIG_LIVING_SET_BODY_POSITION, COMSIG_LIVING_STATUS_PARALYZE, COMSIG_LIVING_STATUS_STUN, COMSIG_LIVING_STATUS_IMMOBILIZE, - COMSIG_LIVING_DEATH, )) - REMOVE_TRAIT(owner, TRAIT_STUN_ON_NEXT_SHOVE, TRAIT_STATUS_EFFECT(id)) - if(vulnverability_overlay) - clear_stun_vulnverability_overlay() + REMOVE_TRAIT(owner, TRAIT_DAZED, TRAIT_STATUS_EFFECT(id)) + if(dazed_overlay) + clear_dazed_overlay() /// If our owner is either stunned, paralzyed or immobilized, we remove the status effect. /// This is both an anti-chainstun measure and a sanity check. -/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability(mob/living/source, amount = 0, ignore_canstun = FALSE) +/datum/status_effect/dazed/proc/clear_daze(mob/living/source, amount = 0, ignore_canstun = FALSE) SIGNAL_HANDLER if(amount > 0) // Making absolutely sure we're removing this overlay - clear_stun_vulnverability_overlay() + clear_dazed_overlay() + qdel(src) + +/datum/status_effect/dazed/proc/clear_daze_on_stand(mob/living/source, new_position) + SIGNAL_HANDLER + + if(new_position == STANDING_UP) + clear_dazed_overlay() qdel(src) -/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability_on_death(mob/living/source) +/datum/status_effect/dazed/proc/clear_daze_on_death(mob/living/source) SIGNAL_HANDLER - clear_stun_vulnverability_overlay() + clear_dazed_overlay() qdel(src) /// Clears our overlay where needed. -/datum/status_effect/next_shove_stuns/proc/clear_stun_vulnverability_overlay() - owner.cut_overlay(vulnverability_overlay) - vulnverability_overlay = null +/datum/status_effect/dazed/proc/clear_dazed_overlay() + owner.cut_overlay(dazed_overlay) + dazed_overlay = null /// Status effect to prevent stuns from a shove /// Only applied by shoving someone to paralyze them diff --git a/code/game/atom/atom_act.dm b/code/game/atom/atom_act.dm index 54f023eb86b59..197d6c9e38b49 100644 --- a/code/game/atom/atom_act.dm +++ b/code/game/atom/atom_act.dm @@ -150,7 +150,7 @@ step(harmed_atom, REVERSE_DIR(harmed_atom.dir)) ///Handle the atom being slipped over -/atom/proc/handle_slip(mob/living/carbon/slipped_carbon, knockdown_amount, obj/slipping_object, lube, paralyze, force_drop) +/atom/proc/handle_slip(mob/living/carbon/slipped_carbon, knockdown_amount, obj/slipping_object, lube, paralyze, daze, force_drop) return ///Used for making a sound when a mob involuntarily falls into the ground. diff --git a/code/game/objects/items/melee/baton.dm b/code/game/objects/items/melee/baton.dm index eae6b5e4289f4..946a9e47eaeb9 100644 --- a/code/game/objects/items/melee/baton.dm +++ b/code/game/objects/items/melee/baton.dm @@ -382,7 +382,7 @@ RegisterSignal(src, COMSIG_TRANSFORMING_ON_TRANSFORM, PROC_REF(on_transform)) /obj/item/melee/baton/telescopic/additional_effects_non_cyborg(mob/living/target, mob/living/user) - target.apply_status_effect(/datum/status_effect/next_shove_stuns) + target.apply_status_effect(/datum/status_effect/dazed) /obj/item/melee/baton/telescopic/suicide_act(mob/living/user) var/mob/living/carbon/human/human_user = user diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 8a601736e7816..3bfb14ebb4d03 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -348,8 +348,8 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) custom_materials = list(/datum/material/iron =SHEET_MATERIAL_AMOUNT) item_flags = SKIP_FANTASY_ON_SPAWN - // Whether or not the chair causes the target to become shove stun vulnerable if smashed against someone from behind. - var/inflicts_stun_vulnerability = TRUE + // Duration of daze inflicted when the chair is smashed against someone from behind. + var/daze_amount = 3 SECONDS // What structure type does this chair become when placed? var/obj/structure/chair/origin_type = /obj/structure/chair @@ -432,11 +432,9 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) user.visible_message(span_danger("[user] smashes [src] to pieces against [give_this_fucker_the_chair]")) if(!HAS_TRAIT(give_this_fucker_the_chair, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) if(vulnerable_hit || give_this_fucker_the_chair.get_timed_status_effect_duration(/datum/status_effect/staggered)) - give_this_fucker_the_chair.Knockdown(2 SECONDS) + give_this_fucker_the_chair.Knockdown(2 SECONDS, daze_amount = daze_amount) if(give_this_fucker_the_chair.health < give_this_fucker_the_chair.maxHealth*0.5) give_this_fucker_the_chair.adjust_confusion(10 SECONDS) - if(inflicts_stun_vulnerability) - give_this_fucker_the_chair.apply_status_effect(/datum/status_effect/next_shove_stuns) smash(user) @@ -470,7 +468,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) hitsound = 'sound/items/weapons/genhit1.ogg' origin_type = /obj/structure/chair/stool/bamboo max_integrity = 40 //Submissive and breakable unlike the chad iron stool - inflicts_stun_vulnerability = FALSE //Not hard enough to cause them to become vulnerable to a shove + daze_amount = 0 //Not hard enough to cause them to become dazed /obj/item/chair/stool/narsie_act() return //sturdy enough to ignore a god @@ -484,7 +482,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) hitsound = 'sound/items/weapons/genhit1.ogg' origin_type = /obj/structure/chair/wood custom_materials = null - inflicts_stun_vulnerability = FALSE + daze_amount = 0 /obj/item/chair/wood/narsie_act() return @@ -606,7 +604,7 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/structure/chair/stool/bar, 0) throw_range = 5 //Lighter Weight --> Flies Farther. custom_materials = list(/datum/material/plastic =SHEET_MATERIAL_AMOUNT) max_integrity = 70 - inflicts_stun_vulnerability = FALSE + daze_amount = 0 origin_type = /obj/structure/chair/plastic /obj/structure/chair/musical diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index 22517603ef3fc..50c9d427c94a9 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -345,8 +345,7 @@ SIGNAL_HANDLER if((shove_flags & SHOVE_KNOCKDOWN_BLOCKED) || !(shove_flags & SHOVE_BLOCKED)) return - target.Knockdown(SHOVE_KNOCKDOWN_TABLE) - target.apply_status_effect(/datum/status_effect/next_shove_stuns) + target.Knockdown(SHOVE_KNOCKDOWN_TABLE, daze_amount = 3 SECONDS) target.visible_message(span_danger("[shover.name] shoves [target.name] onto \the [src]!"), span_userdanger("You're shoved onto \the [src] by [shover.name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, shover) to_chat(shover, span_danger("You shove [target.name] onto \the [src]!")) diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index 4337fc3eb0352..8f99f494eebb0 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -340,7 +340,7 @@ wash(CLEAN_WASH, TRUE) return TRUE -/turf/open/handle_slip(mob/living/slipper, knockdown_amount, obj/slippable, lube, paralyze_amount, force_drop) +/turf/open/handle_slip(mob/living/slipper, knockdown_amount, obj/slippable, lube, paralyze_amount, daze_amount, force_drop) if(slipper.movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE if(!has_gravity(src)) @@ -393,8 +393,8 @@ slipper.adjust_staggered_up_to(STAGGERED_SLOWDOWN_LENGTH, 10 SECONDS) slipper.stop_pulling() else - slipper.Knockdown(knockdown_amount) slipper.Paralyze(paralyze_amount) + slipper.Knockdown(knockdown_amount, daze_amount = daze_amount) if(!isnull(buckled_obj) && !ismob(buckled_obj)) buckled_obj.unbuckle_mob(slipper) diff --git a/code/modules/antagonists/heretic/magic/mansus_grasp.dm b/code/modules/antagonists/heretic/magic/mansus_grasp.dm index 1079d60d79ed7..03b44a393f1ec 100644 --- a/code/modules/antagonists/heretic/magic/mansus_grasp.dm +++ b/code/modules/antagonists/heretic/magic/mansus_grasp.dm @@ -64,9 +64,8 @@ return TRUE carbon_hit.adjust_timed_status_effect(4 SECONDS, /datum/status_effect/speech/slurring/heretic) - carbon_hit.AdjustKnockdown(5 SECONDS) + carbon_hit.AdjustKnockdown(5 SECONDS, daze_amount = 3 SECONDS) carbon_hit.adjustStaminaLoss(80) - carbon_hit.apply_status_effect(/datum/status_effect/next_shove_stuns) return TRUE diff --git a/code/modules/meteors/meteor_types.dm b/code/modules/meteors/meteor_types.dm index 0dab142f03ad0..8fec28c94f044 100644 --- a/code/modules/meteors/meteor_types.dm +++ b/code/modules/meteors/meteor_types.dm @@ -356,7 +356,7 @@ /obj/effect/meteor/banana/ram_turf(turf/bumped) for(var/mob/living/slipped in get_turf(bumped)) - slipped.slip(100, slipped.loc,- GALOSHES_DONT_HELP|SLIDE, 0, FALSE) + slipped.slip(100, slipped.loc,- GALOSHES_DONT_HELP|SLIDE) slipped.visible_message(span_warning("[src] honks [slipped] to the floor!"), span_userdanger("[src] harmlessly passes through you, knocking you over.")) get_hit() diff --git a/code/modules/mob/living/carbon/carbon_defense.dm b/code/modules/mob/living/carbon/carbon_defense.dm index 0be935c76f8b5..e1863e2f2c6fe 100644 --- a/code/modules/mob/living/carbon/carbon_defense.dm +++ b/code/modules/mob/living/carbon/carbon_defense.dm @@ -712,7 +712,7 @@ /mob/living/carbon/get_shove_flags(mob/living/shover, obj/item/weapon) . = ..() . |= SHOVE_CAN_STAGGER - if(IsKnockdown() && !IsParalyzed() && HAS_TRAIT(src, TRAIT_STUN_ON_NEXT_SHOVE)) + if(IsKnockdown() && !IsParalyzed() && HAS_TRAIT(src, TRAIT_DAZED)) . |= SHOVE_CAN_KICK_SIDE if(HAS_TRAIT(src, TRAIT_NO_SIDE_KICK)) // added as an extra check, just in case . &= ~SHOVE_CAN_KICK_SIDE diff --git a/code/modules/mob/living/carbon/carbon_movement.dm b/code/modules/mob/living/carbon/carbon_movement.dm index cb35aebfb0770..83b53e64cf9b8 100644 --- a/code/modules/mob/living/carbon/carbon_movement.dm +++ b/code/modules/mob/living/carbon/carbon_movement.dm @@ -1,10 +1,10 @@ -/mob/living/carbon/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, force_drop = FALSE) +/mob/living/carbon/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, daze, force_drop = FALSE) if(movement_type & MOVETYPES_NOT_TOUCHING_GROUND) return FALSE if(!(lube_flags & SLIDE_ICE)) log_combat(src, (slipped_on || get_turf(src)), "slipped on the", null, ((lube_flags & SLIDE) ? "(SLIDING)" : null)) ..() - return loc.handle_slip(src, knockdown_amount, slipped_on, lube_flags, paralyze, force_drop) + return loc.handle_slip(src, knockdown_amount, slipped_on, lube_flags, paralyze, daze, force_drop) /mob/living/carbon/Move(NewLoc, direct) . = ..() diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 2523ea4dd923e..29972735567cd 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -140,11 +140,9 @@ if(src == target || LAZYFIND(target.buckled_mobs, src) || !iscarbon(target)) return if(!(shove_flags & SHOVE_KNOCKDOWN_BLOCKED)) - target.Knockdown(SHOVE_KNOCKDOWN_HUMAN) - target.apply_status_effect(/datum/status_effect/next_shove_stuns) + target.Knockdown(SHOVE_KNOCKDOWN_HUMAN, daze_amount = 3 SECONDS) if(!HAS_TRAIT(src, TRAIT_BRAWLING_KNOCKDOWN_BLOCKED)) - Knockdown(SHOVE_KNOCKDOWN_COLLATERAL) - apply_status_effect(/datum/status_effect/next_shove_stuns) + Knockdown(SHOVE_KNOCKDOWN_COLLATERAL, daze_amount = 3 SECONDS) target.visible_message(span_danger("[shover] shoves [target.name] into [name]!"), span_userdanger("You're shoved into [name] by [shover]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) to_chat(src, span_danger("You shove [target.name] into [name]!")) diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index 52e59e098c1b7..57f32a92decf6 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -9,7 +9,7 @@ return return considering -/mob/living/carbon/human/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, force_drop = FALSE) +/mob/living/carbon/human/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, daze, force_drop = FALSE) if(HAS_TRAIT(src, TRAIT_NO_SLIP_ALL)) return FALSE diff --git a/code/modules/mob/living/carbon/human/status_procs.dm b/code/modules/mob/living/carbon/human/status_procs.dm index 6f4e8570099af..be2284f580d34 100644 --- a/code/modules/mob/living/carbon/human/status_procs.dm +++ b/code/modules/mob/living/carbon/human/status_procs.dm @@ -3,7 +3,7 @@ amount = dna.species.spec_stun(src, amount) return ..() -/mob/living/carbon/human/Knockdown(amount, ignore_canstun = FALSE) +/mob/living/carbon/human/Knockdown(amount, daze_amount = 0, ignore_canstun = FALSE) amount = dna.species.spec_stun(src, amount) * physiology.knockdown_mod return ..() diff --git a/code/modules/mob/living/living_defense.dm b/code/modules/mob/living/living_defense.dm index 40f92eb4507af..537f9a1e13f2d 100644 --- a/code/modules/mob/living/living_defense.dm +++ b/code/modules/mob/living/living_defense.dm @@ -748,8 +748,7 @@ if(!(shove_flags & SHOVE_DIRECTIONAL_BLOCKED) && (SEND_SIGNAL(target_shove_turf, COMSIG_LIVING_DISARM_COLLIDE, src, target, shove_flags, weapon) & COMSIG_LIVING_SHOVE_HANDLED)) return if((shove_flags & SHOVE_BLOCKED) && !(shove_flags & (SHOVE_KNOCKDOWN_BLOCKED|SHOVE_CAN_KICK_SIDE))) - target.Knockdown(SHOVE_KNOCKDOWN_SOLID) - target.apply_status_effect(/datum/status_effect/next_shove_stuns) + target.Knockdown(SHOVE_KNOCKDOWN_SOLID, daze_amount = 3 SECONDS) target.visible_message(span_danger("[name] shoves [target.name], knocking [target.p_them()] down!"), span_userdanger("You're knocked down from a shove by [name]!"), span_hear("You hear aggressive shuffling followed by a loud thud!"), COMBAT_MESSAGE_RANGE, src) to_chat(src, span_danger("You shove [target.name], knocking [target.p_them()] down!")) diff --git a/code/modules/mob/living/status_procs.dm b/code/modules/mob/living/status_procs.dm index 11815d71b1220..967b7cdabfd68 100644 --- a/code/modules/mob/living/status_procs.dm +++ b/code/modules/mob/living/status_procs.dm @@ -89,7 +89,7 @@ return K.duration - world.time return 0 -/mob/living/proc/Knockdown(amount, ignore_canstun = FALSE) //Can't go below remaining duration +/mob/living/proc/Knockdown(amount, daze_amount = 0, ignore_canstun = FALSE) //Can't go below remaining duration if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN) return if(check_stun_immunity(CANKNOCKDOWN, ignore_canstun)) @@ -99,6 +99,8 @@ K.duration = max(world.time + amount, K.duration) else if(amount > 0) K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount) + if(daze_amount > 0) + apply_status_effect(/datum/status_effect/dazed, daze_amount) return K /mob/living/proc/SetKnockdown(amount, ignore_canstun = FALSE) //Sets remaining duration @@ -117,7 +119,7 @@ K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount) return K -/mob/living/proc/AdjustKnockdown(amount, ignore_canstun = FALSE) //Adds to remaining duration +/mob/living/proc/AdjustKnockdown(amount, daze_amount = 0, ignore_canstun = FALSE) //Adds to remaining duration if(SEND_SIGNAL(src, COMSIG_LIVING_STATUS_KNOCKDOWN, amount, ignore_canstun) & COMPONENT_NO_STUN) return if(check_stun_immunity(CANKNOCKDOWN, ignore_canstun)) @@ -127,6 +129,8 @@ K.duration += amount else if(amount > 0) K = apply_status_effect(/datum/status_effect/incapacitating/knockdown, amount) + if(daze_amount > 0) + apply_status_effect(/datum/status_effect/dazed, daze_amount) return K /* IMMOBILIZED */ diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm index 36d722f68dcdb..f833ad9028a66 100644 --- a/code/modules/mob/mob_movement.dm +++ b/code/modules/mob/mob_movement.dm @@ -376,12 +376,13 @@ * slipped_on - optional, what'd we slip on? if not set, we assume they just fell over * lube - bitflag of "lube flags", see [mobs.dm] for more information * paralyze - time (in deciseconds) the slip leaves them paralyzed / unable to move + * daze - time (in deciseconds) the slip leaves them vulnerable to shove stuns * force_drop = the slip forces them to drop held items */ -/mob/proc/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, force_drop = FALSE) +/mob/proc/slip(knockdown_amount, obj/slipped_on, lube_flags, paralyze, daze, force_drop = FALSE) add_mob_memory(/datum/memory/was_slipped, antagonist = slipped_on) - SEND_SIGNAL(src, COMSIG_MOB_SLIPPED, knockdown_amount, slipped_on, lube_flags, paralyze, force_drop) + SEND_SIGNAL(src, COMSIG_MOB_SLIPPED, knockdown_amount, slipped_on, lube_flags, paralyze, daze, force_drop) //bodypart selection verbs - Cyberboss //8: repeated presses toggles through head - eyes - mouth diff --git a/code/modules/projectiles/projectile/bullets/special.dm b/code/modules/projectiles/projectile/bullets/special.dm index cd1439cbb01ae..1c9a5e4f38214 100644 --- a/code/modules/projectiles/projectile/bullets/special.dm +++ b/code/modules/projectiles/projectile/bullets/special.dm @@ -23,7 +23,7 @@ if(M.can_block_magic()) return BULLET_ACT_BLOCK else - M.slip(100, M.loc, GALOSHES_DONT_HELP|SLIDE, 0, FALSE) + M.slip(100, M.loc, GALOSHES_DONT_HELP|SLIDE) // Mime diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 25576568eb56f..109a4ff43a445 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -951,7 +951,7 @@ for(var/mob/living/nearby_mob in range(location, 3)) do_sparks(3,FALSE,nearby_mob) do_teleport(nearby_mob, get_turf(holder.my_atom), 3, no_effects=TRUE) - nearby_mob.Knockdown(20, TRUE) + nearby_mob.Knockdown(20, ignore_canstun = TRUE) nearby_mob.add_atom_colour("#cebfff", WASHABLE_COLOUR_PRIORITY) do_sparks(3,FALSE,nearby_mob) clear_products(holder, step_volume_added) From 67f6b0476bb8b49017cef8aeb29575e106de4106 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 04:38:58 +0000 Subject: [PATCH 059/104] Automatic changelog for PR #89313 [ci skip] --- html/changelogs/AutoChangeLog-pr-89313.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89313.yml diff --git a/html/changelogs/AutoChangeLog-pr-89313.yml b/html/changelogs/AutoChangeLog-pr-89313.yml new file mode 100644 index 0000000000000..17db15c736227 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89313.yml @@ -0,0 +1,4 @@ +author: "Runi-c" +delete-after: True +changes: + - balance: "slips now make you eligible for being shove stunned" \ No newline at end of file From 6ae890675881e2276f733b9e24590797e858bfa5 Mon Sep 17 00:00:00 2001 From: SmArtKar <44720187+SmArtKar@users.noreply.github.com> Date: Thu, 6 Feb 2025 06:10:09 +0100 Subject: [PATCH 060/104] Stops fishing achievement cheese (#89319) ## About The Pull Request By putting bought/dead/evolving and fishing it out, you could get a fishing achievement for any type of fish, which kinda ruined the challenge of fishing out rare sorts of fishes like Mastadons. ## Why It's Good For The Game Fishing cheevos should be indicative of what cool fishes you've caught, not of how much you've cheesed the game. ## Changelog :cl: balance: Removed an oversight which allowed you to farm fishing achievements /:cl: --------- Co-authored-by: Ghom <42542238+Ghommie@users.noreply.github.com> --- code/__DEFINES/traits/declarations.dm | 4 ++ code/_globalvars/traits/_traits.dm | 1 + code/modules/fishing/aquarium/aquarium_kit.dm | 1 + code/modules/fishing/fishing_minigame.dm | 37 ++++++++++++++----- code/modules/fishing/sources/_fish_source.dm | 2 + .../reagents/chemistry/recipes/others.dm | 5 ++- 6 files changed, 38 insertions(+), 12 deletions(-) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index b7069943e9099..6a66031fc2503 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -1429,4 +1429,8 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// Trait applied when the wire bundle component is added to an [/obj/item/integrated_circuit] #define TRAIT_COMPONENT_WIRE_BUNDLE "component_wire_bundle" +/// Trait that is added to fishes that someone already caught, be it in-game or just theoretically, such as when they're bought +/// Prevents fishing achievement from being granted by catching one of these +#define TRAIT_NO_FISHING_ACHIEVEMENT "no_fishing_achievement" + // END TRAIT DEFINES diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 6d4e0be910bbd..451e1d993c7e1 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -676,6 +676,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_RESIST_PSYCHIC" = TRAIT_RESIST_PSYCHIC, "TRAIT_FISH_WELL_COOKED" = TRAIT_FISH_WELL_COOKED, "TRAIT_YUCKY_FISH" = TRAIT_YUCKY_FISH, + "TRAIT_NO_FISHING_ACHIEVEMENT" = TRAIT_NO_FISHING_ACHIEVEMENT, ), /obj/item/fishing_rod = list( "TRAIT_ROD_ATTRACT_SHINY_LOVERS" = TRAIT_ROD_ATTRACT_SHINY_LOVERS, diff --git a/code/modules/fishing/aquarium/aquarium_kit.dm b/code/modules/fishing/aquarium/aquarium_kit.dm index f18f67b931370..751dff2609c76 100644 --- a/code/modules/fishing/aquarium/aquarium_kit.dm +++ b/code/modules/fishing/aquarium/aquarium_kit.dm @@ -39,6 +39,7 @@ if(fish_type) var/obj/item/fish/spawned_fish = new fish_type(null) ADD_TRAIT(spawned_fish, TRAIT_FISH_FROM_CASE, TRAIT_GENERIC) + ADD_TRAIT(spawned_fish, TRAIT_NO_FISHING_ACHIEVEMENT, TRAIT_GENERIC) spawned_fish.forceMove(src) // trigger storage.handle_entered /obj/item/storage/fish_case/proc/get_fish_type() diff --git a/code/modules/fishing/fishing_minigame.dm b/code/modules/fishing/fishing_minigame.dm index 41a967fafb723..d0a5bcb85ac35 100644 --- a/code/modules/fishing/fishing_minigame.dm +++ b/code/modules/fishing/fishing_minigame.dm @@ -350,6 +350,7 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) completed = TRUE if(phase == MINIGAME_PHASE) remove_minigame_hud() + if(!QDELETED(user) && user.mind && start_time && !(special_effects & FISHING_MINIGAME_RULE_NO_EXP)) var/seconds_spent = (world.time - start_time) * 0.1 var/extra_exp_malus = user.mind.get_skill_level(/datum/skill/fishing) - difficulty * 0.1 @@ -359,16 +360,32 @@ GLOBAL_LIST_EMPTY(fishing_challenges_by_user) user.mind.adjust_experience(/datum/skill/fishing, round(seconds_spent * FISHING_SKILL_EXP_PER_SECOND * experience_multiplier)) if(user.mind.get_skill_level(/datum/skill/fishing) >= SKILL_LEVEL_LEGENDARY) user.client?.give_award(/datum/award/achievement/skill/legendary_fisher, user) - if(win) - if(reward_path != FISHING_DUD) - playsound(location, 'sound/effects/bigsplash.ogg', 100) - if(ispath(reward_path, /obj/item/fish) || isfish(reward_path)) - var/obj/item/fish/fish_reward = reward_path - var/obj/item/fish/redirect_path = initial(fish_reward.fish_id_redirect_path) - var/fish_id = ispath(redirect_path, /obj/item/fish) ? initial(redirect_path.fish_id) : initial(fish_reward.fish_id) - if(fish_id) - user.client?.give_award(/datum/award/score/progress/fish, user, fish_id) - SEND_SIGNAL(user, COMSIG_MOB_COMPLETE_FISHING, src, win) + + if(!win) + SEND_SIGNAL(user, COMSIG_MOB_COMPLETE_FISHING, src, FALSE) + if(!QDELETED(src)) + qdel(src) + return + + if(reward_path != FISHING_DUD) + playsound(location, 'sound/effects/bigsplash.ogg', 100) + + var/valid_achievement_catch = FALSE + if (ispath(reward_path, /obj/item/fish)) + valid_achievement_catch = TRUE + else if (isfish(reward_path)) + var/obj/item/fish/fishy_individual = reward_path + if (!HAS_TRAIT(fishy_individual, TRAIT_NO_FISHING_ACHIEVEMENT) && fishy_individual.status == FISH_ALIVE) + valid_achievement_catch = TRUE + + if(valid_achievement_catch) + var/obj/item/fish/fish_reward = reward_path + var/obj/item/fish/redirect_path = initial(fish_reward.fish_id_redirect_path) + var/fish_id = ispath(redirect_path, /obj/item/fish) ? initial(redirect_path.fish_id) : initial(fish_reward.fish_id) + if(fish_id) + user.client?.give_award(/datum/award/score/progress/fish, user, fish_id) + + SEND_SIGNAL(user, COMSIG_MOB_COMPLETE_FISHING, src, TRUE) if(!QDELETED(src)) qdel(src) diff --git a/code/modules/fishing/sources/_fish_source.dm b/code/modules/fishing/sources/_fish_source.dm index c747450986389..58c9e1aea6583 100644 --- a/code/modules/fishing/sources/_fish_source.dm +++ b/code/modules/fishing/sources/_fish_source.dm @@ -273,6 +273,8 @@ GLOBAL_LIST_INIT(specific_fish_icons, generate_specific_fish_icons()) fisherman.balloon_alert(fisherman, "caught something!") return fisherman.balloon_alert(fisherman, "caught [reward]!") + if (isfish(reward)) + ADD_TRAIT(reward, TRAIT_NO_FISHING_ACHIEVEMENT, TRAIT_GENERIC) return reward diff --git a/code/modules/reagents/chemistry/recipes/others.dm b/code/modules/reagents/chemistry/recipes/others.dm index 109a4ff43a445..32b659365c2f4 100644 --- a/code/modules/reagents/chemistry/recipes/others.dm +++ b/code/modules/reagents/chemistry/recipes/others.dm @@ -594,8 +594,9 @@ // spawn from popssible fishes for(var/i in 1 to rand(1, created_volume)) // More flop. - var/obj/item/fish/spawned_fish = pick(fish_types) - new spawned_fish(location) + var/spawned_fish = pick(fish_types) + var/obj/item/fish/new_fish = new spawned_fish(location) + ADD_TRAIT(new_fish, TRAIT_NO_FISHING_ACHIEVEMENT, TRAIT_GENERIC) return ..() //monkey powder heehoo From b9924c43b24d3607554dfcdce025f163a10a5774 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 05:10:29 +0000 Subject: [PATCH 061/104] Automatic changelog for PR #89319 [ci skip] --- html/changelogs/AutoChangeLog-pr-89319.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89319.yml diff --git a/html/changelogs/AutoChangeLog-pr-89319.yml b/html/changelogs/AutoChangeLog-pr-89319.yml new file mode 100644 index 0000000000000..5b9335f772f92 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89319.yml @@ -0,0 +1,4 @@ +author: "SmArtKar" +delete-after: True +changes: + - balance: "Removed an oversight which allowed you to farm fishing achievements" \ No newline at end of file From a9fa5df0cd17e8fcb1f153bcbe45f043bc432f36 Mon Sep 17 00:00:00 2001 From: TiviPlus <57223640+TiviPlus@users.noreply.github.com> Date: Thu, 6 Feb 2025 19:57:48 +0100 Subject: [PATCH 062/104] Fixes DB admin ranks being 16 bits wide instead of 24 (#89348) ## About The Pull Request smallint is 2 bytes, increased it to mediumint which is 3 bytes Issue has not cropped up yet as theres only 15 flags right now, but there can be up to 24 in dm side soooo ``` DEBUG-SQL: MySqlError { ERROR 1264 (22003): Out of range value for column 'flags' at row 1 } | Query used: INSERT INTO admin_ranks - (rank, flags, exclude_flags, can_edit_flags) ``` my mysql is broken so I havent tested the update query but how bad can it be :clueless: ## Changelog :cl: server: An issue where more than 16 admin flags could not exist in the DB has been corrected /:cl: --------- Co-authored-by: TiviPlus <572233640+TiviPlus@users.noreply.com> --- SQL/database_changelog.md | 14 ++++++++++++-- SQL/tgstation_schema.sql | 6 +++--- SQL/tgstation_schema_prefixed.sql | 6 +++--- code/__DEFINES/subsystems.dm | 2 +- 4 files changed, 19 insertions(+), 9 deletions(-) diff --git a/SQL/database_changelog.md b/SQL/database_changelog.md index f8770e2868dbb..373d97bdf6c7b 100644 --- a/SQL/database_changelog.md +++ b/SQL/database_changelog.md @@ -5,15 +5,25 @@ Make sure to also update `DB_MAJOR_VERSION` and `DB_MINOR_VERSION`, which can be The latest database version is 5.28; The query to update the schema revision table is: ```sql -INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 28); +INSERT INTO `schema_revision` (`major`, `minor`) VALUES (5, 29); ``` or ```sql -INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 28); +INSERT INTO `SS13_schema_revision` (`major`, `minor`) VALUES (5, 29); ``` In any query remember to add a prefix to the table names if you use one. ----------------------------------------------------- +Version 5.29, 4 February 2024, by Tiviplus +Fixed admin rank table flags being capped at 16 in the DB instead of 24 (byond max) + +```sql +ALTER TABLE `admin_ranks` + MODIFY COLUMN `flags` mediumint(5) unsigned NOT NULL, + MODIFY COLUMN `exclude_flags` mediumint(5) unsigned NOT NULL, + MODIFY COLUMN `can_edit_flags` mediumint(5) unsigned NOT NULL; +``` +----------------------------------------------------- Version 5.28, 1 November 2024, by Ghommie Added `fish_progress` as the first 'progress' subtype of 'datum/award/scores' diff --git a/SQL/tgstation_schema.sql b/SQL/tgstation_schema.sql index ba3ff538f1c82..96933aa14e189 100644 --- a/SQL/tgstation_schema.sql +++ b/SQL/tgstation_schema.sql @@ -53,9 +53,9 @@ DROP TABLE IF EXISTS `admin_ranks`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `admin_ranks` ( `rank` varchar(32) NOT NULL, - `flags` smallint(5) unsigned NOT NULL, - `exclude_flags` smallint(5) unsigned NOT NULL, - `can_edit_flags` smallint(5) unsigned NOT NULL, + `flags` mediumint(5) unsigned NOT NULL, + `exclude_flags` mediumint(5) unsigned NOT NULL, + `can_edit_flags` mediumint(5) unsigned NOT NULL, PRIMARY KEY (`rank`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/SQL/tgstation_schema_prefixed.sql b/SQL/tgstation_schema_prefixed.sql index 525b1b0aa33e6..7b322d5a65275 100644 --- a/SQL/tgstation_schema_prefixed.sql +++ b/SQL/tgstation_schema_prefixed.sql @@ -53,9 +53,9 @@ DROP TABLE IF EXISTS `SS13_admin_ranks`; /*!40101 SET character_set_client = utf8 */; CREATE TABLE `SS13_admin_ranks` ( `rank` varchar(32) NOT NULL, - `flags` smallint(5) unsigned NOT NULL, - `exclude_flags` smallint(5) unsigned NOT NULL, - `can_edit_flags` smallint(5) unsigned NOT NULL, + `flags` mediumint(5) unsigned NOT NULL, + `exclude_flags` mediumint(5) unsigned NOT NULL, + `can_edit_flags` mediumint(5) unsigned NOT NULL, PRIMARY KEY (`rank`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci; /*!40101 SET character_set_client = @saved_cs_client */; diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm index e3547fb73e0a4..3354f6306d3f9 100644 --- a/code/__DEFINES/subsystems.dm +++ b/code/__DEFINES/subsystems.dm @@ -20,7 +20,7 @@ * * make sure you add an update to the schema_version stable in the db changelog */ -#define DB_MINOR_VERSION 28 +#define DB_MINOR_VERSION 29 //! ## Timing subsystem From d19a667717410fb41e96a5642326f302f477b7c4 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Thu, 6 Feb 2025 18:58:12 +0000 Subject: [PATCH 063/104] Automatic changelog for PR #89348 [ci skip] --- html/changelogs/AutoChangeLog-pr-89348.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89348.yml diff --git a/html/changelogs/AutoChangeLog-pr-89348.yml b/html/changelogs/AutoChangeLog-pr-89348.yml new file mode 100644 index 0000000000000..bb8e356a7b38d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89348.yml @@ -0,0 +1,4 @@ +author: "TiviPlus" +delete-after: True +changes: + - server: "An issue where more than 16 admin flags could not exist in the DB has been corrected" \ No newline at end of file From 25b686fb2d2bf6e12c1a8d6a5cbd0a8c9307e048 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 00:26:13 +0000 Subject: [PATCH 064/104] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-89313.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89319.yml | 4 ---- html/changelogs/AutoChangeLog-pr-89348.yml | 4 ---- html/changelogs/archive/2025-02.yml | 8 ++++++++ 4 files changed, 8 insertions(+), 12 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-89313.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89319.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-89348.yml diff --git a/html/changelogs/AutoChangeLog-pr-89313.yml b/html/changelogs/AutoChangeLog-pr-89313.yml deleted file mode 100644 index 17db15c736227..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89313.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Runi-c" -delete-after: True -changes: - - balance: "slips now make you eligible for being shove stunned" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89319.yml b/html/changelogs/AutoChangeLog-pr-89319.yml deleted file mode 100644 index 5b9335f772f92..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89319.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SmArtKar" -delete-after: True -changes: - - balance: "Removed an oversight which allowed you to farm fishing achievements" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-89348.yml b/html/changelogs/AutoChangeLog-pr-89348.yml deleted file mode 100644 index bb8e356a7b38d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-89348.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "TiviPlus" -delete-after: True -changes: - - server: "An issue where more than 16 admin flags could not exist in the DB has been corrected" \ No newline at end of file diff --git a/html/changelogs/archive/2025-02.yml b/html/changelogs/archive/2025-02.yml index 21a6354c617f2..f02e723ac4101 100644 --- a/html/changelogs/archive/2025-02.yml +++ b/html/changelogs/archive/2025-02.yml @@ -97,3 +97,11 @@ or as certain ghost roles, you will still return to your character's original mind, just in case you can be resurrected by some means. - bugfix: The basketball minigame now gives its players and referee temporary bodies. +2025-02-07: + Runi-c: + - balance: slips now make you eligible for being shove stunned + SmArtKar: + - balance: Removed an oversight which allowed you to farm fishing achievements + TiviPlus: + - server: An issue where more than 16 admin flags could not exist in the DB has + been corrected From 2ee02682f7a840115ad2edaa05733b7bf5ba6160 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 6 Feb 2025 20:44:10 -0500 Subject: [PATCH 065/104] Converts most other usages of `block()` to x/y/z format (#89290) ## About The Pull Request The sequel to https://github.com/tgstation/tgstation/pull/89234 > someone should do the rest at some point guess what, I'm that someone :3 ## Why It's Good For The Game Same reasoning as the previous PR: > less cluttered code is nice, and it should in theory be more optimized as we avoid the need to run min, max, and locate. ## Changelog No user-facing changes --- code/controllers/subsystem/explosions.dm | 20 ++++++++----- code/controllers/subsystem/mapping.dm | 11 +++---- code/datums/elements/mirage_border.dm | 7 +++-- code/datums/shuttles/_shuttle.dm | 4 +-- code/game/atoms_movable.dm | 22 +++++++------- code/game/world.dm | 10 ++++--- .../capture_the_flag/ctf_map_loading.dm | 12 ++------ code/modules/mapping/map_template.dm | 30 +++++-------------- code/modules/mapping/reader.dm | 5 ++-- .../space_management/space_transition.dm | 7 +++-- .../mapGenerators/repair.dm | 5 ++-- code/modules/shuttle/shuttle.dm | 19 ++++++------ code/modules/transport/transport_module.dm | 13 ++++---- 13 files changed, 75 insertions(+), 90 deletions(-) diff --git a/code/controllers/subsystem/explosions.dm b/code/controllers/subsystem/explosions.dm index 2b61cabb86074..36dbba09eae01 100644 --- a/code/controllers/subsystem/explosions.dm +++ b/code/controllers/subsystem/explosions.dm @@ -635,23 +635,27 @@ ADMIN_VERB(check_bomb_impacts, R_DEBUG, "Check Bomb Impact", "See what the effec // top left to one before top right if(highest_y <= max_y) candidates += block( - locate(max(lowest_x, 1), highest_y, our_z), - locate(min(highest_x - 1, max_x), highest_y, our_z)) + lowest_x, highest_y, our_z, + highest_x - 1, highest_y, our_z + ) // top right to one before bottom right if(highest_x <= max_x) candidates += block( - locate(highest_x, min(highest_y, max_y), our_z), - locate(highest_x, max(lowest_y + 1, 1), our_z)) + highest_x, highest_y, our_z, + highest_x, lowest_y + 1, our_z + ) // bottom right to one before bottom left if(lowest_y >= 1) candidates += block( - locate(min(highest_x, max_x), lowest_y, our_z), - locate(max(lowest_x + 1, 1), lowest_y, our_z)) + highest_x, lowest_y, our_z, + lowest_x + 1, lowest_y, our_z + ) // bottom left to one before top left if(lowest_x >= 1) candidates += block( - locate(lowest_x, max(lowest_y, 1), our_z), - locate(lowest_x, min(highest_y - 1, max_y), our_z)) + lowest_x, lowest_y, our_z, + lowest_x, highest_y - 1, our_z + ) if(!do_directional) outlist += candidates diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 27bb029be150c..b4184f8a34d6c 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -645,10 +645,11 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away if(!level_trait(z,ZTRAIT_RESERVED)) clearing_reserved_turfs = FALSE CRASH("Invalid z level prepared for reservations.") - var/turf/A = get_turf(locate(SHUTTLE_TRANSIT_BORDER,SHUTTLE_TRANSIT_BORDER,z)) - var/turf/B = get_turf(locate(world.maxx - SHUTTLE_TRANSIT_BORDER,world.maxy - SHUTTLE_TRANSIT_BORDER,z)) - var/block = block(A, B) - for(var/turf/T as anything in block) + var/list/reserved_block = block( + SHUTTLE_TRANSIT_BORDER, SHUTTLE_TRANSIT_BORDER, z, + world.maxx - SHUTTLE_TRANSIT_BORDER, world.maxy - SHUTTLE_TRANSIT_BORDER, z + ) + for(var/turf/T as anything in reserved_block) // No need to empty() these, because they just got created and are already /turf/open/space/basic. T.turf_flags = UNUSED_RESERVATION_TURF T.blocks_air = TRUE @@ -658,7 +659,7 @@ ADMIN_VERB(load_away_mission, R_FUN, "Load Away Mission", "Load a specific away if(SSatoms.initialized) SSatoms.InitializeAtoms(Z_TURFS(z)) - unused_turfs["[z]"] = block + unused_turfs["[z]"] = reserved_block reservation_ready["[z]"] = TRUE clearing_reserved_turfs = FALSE diff --git a/code/datums/elements/mirage_border.dm b/code/datums/elements/mirage_border.dm index ca7c422dd1127..b7af7ee91f605 100644 --- a/code/datums/elements/mirage_border.dm +++ b/code/datums/elements/mirage_border.dm @@ -20,9 +20,10 @@ var/x = target_turf.x var/y = target_turf.y var/z = clamp(target_turf.z, 1, world.maxz) - var/turf/southwest = locate(clamp(x - (direction & WEST ? range : 0), 1, world.maxx), clamp(y - (direction & SOUTH ? range : 0), 1, world.maxy), z) - var/turf/northeast = locate(clamp(x + (direction & EAST ? range : 0), 1, world.maxx), clamp(y + (direction & NORTH ? range : 0), 1, world.maxy), z) - holder.vis_contents += block(southwest, northeast) + holder.vis_contents += block( + x - (direction & WEST ? range : 0), y - (direction & SOUTH ? range : 0), z, + x + (direction & EAST ? range : 0), y + (direction & NORTH ? range : 0), z + ) if(direction & SOUTH) holder.pixel_y -= ICON_SIZE_Y * range if(direction & WEST) diff --git a/code/datums/shuttles/_shuttle.dm b/code/datums/shuttles/_shuttle.dm index 94c20d41b7365..52cb31a11fd76 100644 --- a/code/datums/shuttles/_shuttle.dm +++ b/code/datums/shuttles/_shuttle.dm @@ -56,8 +56,8 @@ . = ..() if(!.) return - var/list/turfs = block( locate(.[MAP_MINX], .[MAP_MINY], .[MAP_MINZ]), - locate(.[MAP_MAXX], .[MAP_MAXY], .[MAP_MAXZ])) + var/list/turfs = block( .[MAP_MINX], .[MAP_MINY], .[MAP_MINZ], + .[MAP_MAXX], .[MAP_MAXY], .[MAP_MAXZ]) for(var/i in 1 to turfs.len) var/turf/place = turfs[i] if(isspaceturf(place)) // This assumes all shuttles are loaded in a single spot then moved to their real destination. diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm index 5c61186b585f0..d07aad057c298 100644 --- a/code/game/atoms_movable.dm +++ b/code/game/atoms_movable.dm @@ -663,13 +663,12 @@ var/list/new_locs if(is_multi_tile_object && isturf(newloc)) + var/dx = newloc.x + var/dy = newloc.y + var/dz = newloc.z new_locs = block( - newloc, - locate( - min(world.maxx, newloc.x + CEILING(bound_width / 32, 1)), - min(world.maxy, newloc.y + CEILING(bound_height / 32, 1)), - newloc.z - ) + dx, dy, dz, + dx + ceil(bound_width / 32), dy + ceil(bound_height / 32), dz ) // If this is a multi-tile object then we need to predict the new locs and check if they allow our entrance. for(var/atom/entering_loc as anything in new_locs) if(!entering_loc.Enter(src)) @@ -1155,13 +1154,12 @@ return FALSE if(is_multi_tile && isturf(destination)) + var/dx = destination.x + var/dy = destination.y + var/dz = destination.z var/list/new_locs = block( - destination, - locate( - min(world.maxx, destination.x + ROUND_UP(bound_width / ICON_SIZE_X)), - min(world.maxy, destination.y + ROUND_UP(bound_height / ICON_SIZE_Y)), - destination.z - ) + dx, dy, dz, + dx + ROUND_UP(bound_width / ICON_SIZE_X), dy + ROUND_UP(bound_height / ICON_SIZE_Y), dz ) if(old_area && old_area != destarea) old_area.Exited(src, movement_dir) diff --git a/code/game/world.dm b/code/game/world.dm index 79ba0f231e992..0633e197acc37 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -456,8 +456,9 @@ GLOBAL_PROTECT(tracy_init_reason) LISTASSERTLEN(global_area.turfs_by_zlevel, map_load_z_cutoff, list()) for (var/zlevel in 1 to map_load_z_cutoff) var/list/to_add = block( - locate(old_max + 1, 1, zlevel), - locate(maxx, maxy, zlevel)) + old_max + 1, 1, zlevel, + maxx, maxy, zlevel + ) global_area.turfs_by_zlevel[zlevel] += to_add @@ -472,8 +473,9 @@ GLOBAL_PROTECT(tracy_init_reason) LISTASSERTLEN(global_area.turfs_by_zlevel, map_load_z_cutoff, list()) for (var/zlevel in 1 to map_load_z_cutoff) var/list/to_add = block( - locate(1, old_maxy + 1, 1), - locate(maxx, maxy, map_load_z_cutoff)) + 1, old_maxy + 1, 1, + maxx, maxy, map_load_z_cutoff + ) global_area.turfs_by_zlevel[zlevel] += to_add /world/proc/incrementMaxZ() diff --git a/code/modules/capture_the_flag/ctf_map_loading.dm b/code/modules/capture_the_flag/ctf_map_loading.dm index 4c2f6b319e036..9e23d61747323 100644 --- a/code/modules/capture_the_flag/ctf_map_loading.dm +++ b/code/modules/capture_the_flag/ctf_map_loading.dm @@ -14,16 +14,8 @@ GLOBAL_DATUM(ctf_spawner, /obj/effect/landmark/ctf) /obj/effect/landmark/ctf/Destroy() if(map_bounds) for(var/turf/ctf_turf in block( - locate( - map_bounds[MAP_MINX], - map_bounds[MAP_MINY], - map_bounds[MAP_MINZ], - ), - locate( - map_bounds[MAP_MAXX], - map_bounds[MAP_MAXY], - map_bounds[MAP_MAXZ], - ) + map_bounds[MAP_MINX], map_bounds[MAP_MINY], map_bounds[MAP_MINZ], + map_bounds[MAP_MAXX], map_bounds[MAP_MAXY], map_bounds[MAP_MAXZ] )) ctf_turf.empty() GLOB.ctf_spawner = null diff --git a/code/modules/mapping/map_template.dm b/code/modules/mapping/map_template.dm index 950f3e2809ef2..0f6ff85eed92f 100644 --- a/code/modules/mapping/map_template.dm +++ b/code/modules/mapping/map_template.dm @@ -61,17 +61,9 @@ var/list/area/areas = list() var/list/turfs = block( - locate( - bounds[MAP_MINX], - bounds[MAP_MINY], - bounds[MAP_MINZ] - ), - locate( - bounds[MAP_MAXX], - bounds[MAP_MAXY], - bounds[MAP_MAXZ] - ) - ) + bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ], + bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ] + ) for(var/turf/current_turf as anything in turfs) var/area/current_turfs_area = current_turf.loc areas |= current_turfs_area @@ -114,17 +106,9 @@ //calculate all turfs inside the border var/list/template_and_bordering_turfs = block( - locate( - max(bounds[MAP_MINX]-1, 1), - max(bounds[MAP_MINY]-1, 1), - bounds[MAP_MINZ] - ), - locate( - min(bounds[MAP_MAXX]+1, world.maxx), - min(bounds[MAP_MAXY]+1, world.maxy), - bounds[MAP_MAXZ] - ) - ) + bounds[MAP_MINX]-1, bounds[MAP_MINY]-1, bounds[MAP_MINZ], + bounds[MAP_MAXX]+1, bounds[MAP_MAXY]+1, bounds[MAP_MAXZ] + ) for(var/turf/affected_turf as anything in template_and_bordering_turfs) affected_turf.air_update_turf(TRUE, TRUE) affected_turf.levelupdate() @@ -230,7 +214,7 @@ var/turf/corner = locate(placement.x - round(width/2), placement.y - round(height/2), placement.z) if(corner) placement = corner - return block(placement, locate(placement.x+width-1, placement.y+height-1, placement.z)) + return block(placement.x, placement.y, placement.z, placement.x+width-1, placement.y+height-1, placement.z) /// Takes in a type path, locates an instance of that type in the cached map, and calculates its offset from the origin of the map, returns this offset in the form list(x, y). /datum/map_template/proc/discover_offset(obj/marker) diff --git a/code/modules/mapping/reader.dm b/code/modules/mapping/reader.dm index 10d506f8c48e5..1efcf71676e6c 100644 --- a/code/modules/mapping/reader.dm +++ b/code/modules/mapping/reader.dm @@ -350,8 +350,9 @@ if(!no_changeturf) var/list/turfs = block( - locate(bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ]), - locate(bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ])) + bounds[MAP_MINX], bounds[MAP_MINY], bounds[MAP_MINZ], + bounds[MAP_MAXX], bounds[MAP_MAXY], bounds[MAP_MAXZ] + ) for(var/turf/T as anything in turfs) //we do this after we load everything in. if we don't, we'll have weird atmos bugs regarding atmos adjacent turfs T.AfterChange(CHANGETURF_IGNORE_AIR) diff --git a/code/modules/mapping/space_management/space_transition.dm b/code/modules/mapping/space_management/space_transition.dm index b61897dd7b6b4..e5db045e92d20 100644 --- a/code/modules/mapping/space_management/space_transition.dm +++ b/code/modules/mapping/space_management/space_transition.dm @@ -131,9 +131,10 @@ continue var/zlevelnumber = level.z_value for(var/side in 1 to 4) - var/turf/beginning = locate(x_pos_beginning[side], y_pos_beginning[side], zlevelnumber) - var/turf/ending = locate(x_pos_ending[side], y_pos_ending[side], zlevelnumber) - var/list/turfblock = block(beginning, ending) + var/list/turfblock = block( + x_pos_beginning[side], y_pos_beginning[side], zlevelnumber, + x_pos_ending[side], y_pos_ending[side], zlevelnumber + ) var/dirside = 2**(side-1) var/x_target = x_pos_transition[side] == 1 ? 0 : x_pos_transition[side] var/y_target = y_pos_transition[side] == 1 ? 0 : y_pos_transition[side] diff --git a/code/modules/procedural_mapping/mapGenerators/repair.dm b/code/modules/procedural_mapping/mapGenerators/repair.dm index da086773591de..e33f3e1f0cc42 100644 --- a/code/modules/procedural_mapping/mapGenerators/repair.dm +++ b/code/modules/procedural_mapping/mapGenerators/repair.dm @@ -50,8 +50,9 @@ require_area_resort() var/list/generation_turfs = block( - locate(bounds[MAP_MINX], bounds[MAP_MINY], SSmapping.station_start), - locate(bounds[MAP_MAXX], bounds[MAP_MAXY], z_offset - 1)) + bounds[MAP_MINX], bounds[MAP_MINY], SSmapping.station_start, + bounds[MAP_MAXX], bounds[MAP_MAXY], z_offset - 1 + ) for(var/turf/gen_turf as anything in generation_turfs) atoms += gen_turf for(var/atom in gen_turf) diff --git a/code/modules/shuttle/shuttle.dm b/code/modules/shuttle/shuttle.dm index dbb4fc5386b23..28b2516fda84c 100644 --- a/code/modules/shuttle/shuttle.dm +++ b/code/modules/shuttle/shuttle.dm @@ -109,10 +109,11 @@ ///returns turfs within our projected rectangle in no particular order /obj/docking_port/proc/return_turfs() - var/list/L = return_coords() - var/turf/T0 = locate(L[1],L[2],z) - var/turf/T1 = locate(L[3],L[4],z) - return block(T0,T1) + var/list/coords = return_coords() + return block( + coords[1], coords[2], z, + coords[3], coords[4], z + ) ///returns turfs within our projected rectangle in a specific order.this ensures that turfs are copied over in the same order, regardless of any rotation /obj/docking_port/proc/return_ordered_turfs(_x, _y, _z, _dir) @@ -147,17 +148,15 @@ /obj/docking_port/proc/highlight(_color = "#f00") SetInvisibility(INVISIBILITY_NONE) SET_PLANE_IMPLICIT(src, GHOST_PLANE) - var/list/L = return_coords() - var/turf/T0 = locate(L[1],L[2],z) - var/turf/T1 = locate(L[3],L[4],z) - for(var/turf/T in block(T0,T1)) + var/list/coords = return_coords() + for(var/turf/T in block(coords[1], coords[2], z, coords[3], coords[4], z)) T.color = _color LAZYINITLIST(T.atom_colours) T.maptext = null if(_color) - var/turf/T = locate(L[1], L[2], z) + var/turf/T = locate(coords[1], coords[2], z) T.color = "#0f0" - T = locate(L[3], L[4], z) + T = locate(coords[3], coords[4], z) T.color = "#00f" #endif diff --git a/code/modules/transport/transport_module.dm b/code/modules/transport/transport_module.dm index 2c02b507bf27e..83fd824bd6af0 100644 --- a/code/modules/transport/transport_module.dm +++ b/code/modules/transport/transport_module.dm @@ -304,15 +304,16 @@ var/x_offset = ROUND_UP(bound_width / ICON_SIZE_X) - 1 //how many tiles our horizontally farthest edge is from us var/y_offset = ROUND_UP(bound_height / ICON_SIZE_Y) - 1 //how many tiles our vertically farthest edge is from us + var/destination_x = destination.x + var/destination_y = destination.y + var/destination_z = destination.z //the x coordinate of the edge furthest from our future destination, which would be our right hand side - var/back_edge_x = destination.x + x_offset//if we arent multitile this should just be destination.x - var/upper_edge_y = destination.y + y_offset - - var/turf/upper_right_corner = locate(min(world.maxx, back_edge_x), min(world.maxy, upper_edge_y), destination.z) + var/back_edge_x = destination_x + x_offset//if we arent multitile this should just be destination.x + var/upper_edge_y = destination_y + y_offset var/list/dest_locs = block( - destination, - upper_right_corner + destination_x, destination_y, destination_z, + back_edge_x, upper_edge_y, destination_z ) var/list/entering_locs = dest_locs - locs From ad5a70eac632f37125dd000d146df69af889fdfe Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:30:13 +1100 Subject: [PATCH 066/104] Refactors gun repair and maintenance. Gun maintenance kits; available in cargo or the security equipment vendor (#89205) ## About The Pull Request Misfire chance, gun jamming (currently only on boltaction rifles) and integrity repairs are now handled by gun maintenance kits. Using a kit on a gun resets any misfire chance or jamming, and restores the weapon's integrity back to full. You can find gun maintenance kits in security equipment vendors, or order a crate of them from cargo. You can also make a maint version to retain the improvised nature of the previous cleaning functionaltiy. ## Why It's Good For The Game Firstly, clearing misfires was always a little confusing for most players, as it required a bolt of cloth to fix. That's really on me for making that as confusing as possible. We ended up with multiple firearm degradation mechanics, so consolidating their restoration makes it easier for future code maintenance. I disliked that the kits existed but were mostly only for the sake of an extremely niche interaction. And that interaction was, at best, kind of niche. Expanding out their use to gun maintenance generally is honestly better design. ## Changelog :cl: refactor: Gun maintenance is now consolidated into a single item, the gun maintenance kit, rather than multiple different item interactions. It is handled on the maintenance kit itself, and not in gun code. qol: You can order maintenance kits from cargo, and get some out of the security equipment vendor. Helpful if someone spilled acid onto your disabler. You can also make a makeshift one from maintenance trash. /:cl: --- .../SpaceRuins/infested_frigate.dmm | 4 +- .../components/crafting/ranged_weapon.dm | 13 +++ code/game/objects/items/gun_maintenance.dm | 82 ++++++++++++++++-- code/game/objects/items/storage/toolbox.dm | 14 --- code/modules/cargo/packs/imports.dm | 2 +- code/modules/cargo/packs/security.dm | 8 ++ code/modules/projectiles/guns/ballistic.dm | 17 ---- .../projectiles/guns/ballistic/rifle.dm | 30 +++---- code/modules/vending/security.dm | 1 + icons/obj/storage/toolbox.dmi | Bin 2300 -> 2415 bytes 10 files changed, 112 insertions(+), 59 deletions(-) diff --git a/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm b/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm index c925d017ad3a3..aa130e8ddcd1e 100644 --- a/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm +++ b/_maps/RandomRuins/SpaceRuins/infested_frigate.dmm @@ -1044,8 +1044,8 @@ pixel_x = 28 }, /obj/item/storage/toolbox/syndicate, -/obj/item/storage/toolbox/maint_kit, -/obj/item/storage/toolbox/maint_kit, +/obj/item/gun_maintenance_supplies, +/obj/item/gun_maintenance_supplies, /obj/item/storage/toolbox/electrical, /obj/item/storage/box/lights/bulbs, /obj/item/stack/sheet/glass{ diff --git a/code/datums/components/crafting/ranged_weapon.dm b/code/datums/components/crafting/ranged_weapon.dm index f5deb979cb50e..22735bcc5a362 100644 --- a/code/datums/components/crafting/ranged_weapon.dm +++ b/code/datums/components/crafting/ranged_weapon.dm @@ -43,6 +43,19 @@ time = 5 SECONDS category = CAT_WEAPON_RANGED +/datum/crafting_recipe/riflestock + name = "Makeshift Gun Maintenance Kit" + tool_behaviors = list(TOOL_WRENCH, TOOL_WELDER, TOOL_SCREWDRIVER) + result = /obj/item/gun_maintenance_supplies/makeshift + reqs = list( + /obj/item/stack/sheet/iron = 5, + /obj/item/stack/sticky_tape = 1, + /obj/item/pipe = 1, + /obj/item/stack/sheet/cloth = 2, + ) + time = 5 SECONDS + category = CAT_WEAPON_RANGED + /datum/crafting_recipe/advancedegun name = "Advanced Energy Gun" result = /obj/item/gun/energy/e_gun/nuclear diff --git a/code/game/objects/items/gun_maintenance.dm b/code/game/objects/items/gun_maintenance.dm index 072ec395c191c..77ba80352910b 100644 --- a/code/game/objects/items/gun_maintenance.dm +++ b/code/game/objects/items/gun_maintenance.dm @@ -1,6 +1,78 @@ /obj/item/gun_maintenance_supplies - name = "gun maintenance supplies" - desc = "plastic box containing gun maintenance supplies and spare parts. Use them on a rifle to clean it." - icon = 'icons/obj/storage/box.dmi' - icon_state = "plasticbox" - w_class = WEIGHT_CLASS_SMALL + name = "gun maintenance kit" + desc = "A toolbox containing gun maintenance supplies and spare parts. Can be applied to firearms to maintain them." + icon = 'icons/obj/storage/toolbox.dmi' + icon_state = "maint_kit" + inhand_icon_state = "ammobox" + lefthand_file = 'icons/mob/inhands/equipment/toolbox_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/toolbox_righthand.dmi' + force = 12 + throwforce = 12 + throw_speed = 2 + throw_range = 7 + demolition_mod = 1.25 + w_class = WEIGHT_CLASS_BULKY + drop_sound = 'sound/items/handling/ammobox_drop.ogg' + pickup_sound = 'sound/items/handling/ammobox_pickup.ogg' + /// How many times we can use this maintenance kit to maintain a gun + var/uses = 3 + /// THe maximum uses, used for our examine text. + var/max_uses = 3 + +/obj/item/gun_maintenance_supplies/examine(mob/user) + . = ..() + . += span_info("This kit has [uses] uses out of [max_uses] left.") + +/obj/item/gun_maintenance_supplies/interact_with_atom(atom/interacting_with, mob/living/user, list/modifiers) + . = ..() + if(. & ITEM_INTERACT_ANY_BLOCKER) + return ITEM_INTERACT_BLOCKING + + if(!isgun(interacting_with)) + balloon_alert(user, "not a gun!") + return ITEM_INTERACT_BLOCKING + + var/obj/item/gun/gun_to_fix = interacting_with + + var/gun_is_damaged = gun_to_fix.get_integrity() < gun_to_fix.max_integrity + var/use_charge = FALSE + + if(gun_is_damaged) + gun_to_fix.repair_damage(gun_to_fix.max_integrity) + use_charge = TRUE + + if(istype(gun_to_fix, /obj/item/gun/ballistic)) + var/obj/item/gun/ballistic/ballistic_gun_to_fix = gun_to_fix + + if(ballistic_gun_to_fix.misfire_probability > initial(ballistic_gun_to_fix.misfire_probability)) + ballistic_gun_to_fix.misfire_probability = initial(ballistic_gun_to_fix.misfire_probability) + + if(istype(ballistic_gun_to_fix, /obj/item/gun/ballistic/rifle/boltaction)) + var/obj/item/gun/ballistic/rifle/boltaction/rifle_to_fix = ballistic_gun_to_fix + if(rifle_to_fix.jammed) + rifle_to_fix.jammed = FALSE + rifle_to_fix.unjam_chance = initial(rifle_to_fix.unjam_chance) + rifle_to_fix.jamming_chance = initial(rifle_to_fix.jamming_chance) + use_charge = TRUE + + if(!use_charge) + balloon_alert(user, "no need for repair!") + return ITEM_INTERACT_BLOCKING + + balloon_alert(user, "maintenance complete") + use_the_kit() + return ITEM_INTERACT_SUCCESS + +/obj/item/gun_maintenance_supplies/proc/use_the_kit() + uses -- + if(!uses) + qdel(src) + +/obj/item/gun_maintenance_supplies/makeshift + name = "makeshift gun maintenance kit" + desc = "A toolbox containing enough supplies to juryrig repairs on firearms. Can be applied to firearms to maintain them. \ + The tools are a little basic, and the materials low-quality, but it gets the job done." + icon_state = "maint_kit_makeshift" + inhand_icon_state = "toolbox_blue" + uses = 1 + max_uses = 1 diff --git a/code/game/objects/items/storage/toolbox.dm b/code/game/objects/items/storage/toolbox.dm index f23198efd4c9d..3683258723fd9 100644 --- a/code/game/objects/items/storage/toolbox.dm +++ b/code/game/objects/items/storage/toolbox.dm @@ -387,20 +387,6 @@ name = "4.6x30mm AP ammo box" ammo_to_spawn = /obj/item/ammo_box/magazine/wt550m9/wtap -/obj/item/storage/toolbox/maint_kit - name = "gun maintenance kit" - desc = "It contains some gun maintenance supplies" - icon_state = "maint_kit" - inhand_icon_state = "ammobox" - has_latches = FALSE - drop_sound = 'sound/items/handling/ammobox_drop.ogg' - pickup_sound = 'sound/items/handling/ammobox_pickup.ogg' - -/obj/item/storage/toolbox/maint_kit/PopulateContents() - new /obj/item/gun_maintenance_supplies(src) - new /obj/item/gun_maintenance_supplies(src) - new /obj/item/gun_maintenance_supplies(src) - //repairbot assembly /obj/item/storage/toolbox/tool_act(mob/living/user, obj/item/tool, list/modifiers) if(!istype(tool, /obj/item/assembly/prox_sensor)) diff --git a/code/modules/cargo/packs/imports.dm b/code/modules/cargo/packs/imports.dm index 8735763a6b048..c1aa946319e92 100644 --- a/code/modules/cargo/packs/imports.dm +++ b/code/modules/cargo/packs/imports.dm @@ -218,7 +218,7 @@ /obj/item/ammo_box/strilka310/surplus, /obj/item/storage/toolbox/ammobox/strilka310, /obj/item/storage/toolbox/ammobox/strilka310/surplus, - /obj/item/storage/toolbox/maint_kit, + /obj/item/gun_maintenance_supplies, /obj/item/clothing/suit/armor/vest/russian, /obj/item/clothing/head/helmet/rus_helmet, /obj/item/clothing/shoes/russian, diff --git a/code/modules/cargo/packs/security.dm b/code/modules/cargo/packs/security.dm index 612e9f5b3f92c..8227305f743a4 100644 --- a/code/modules/cargo/packs/security.dm +++ b/code/modules/cargo/packs/security.dm @@ -113,6 +113,14 @@ ) crate_name = "security supply crate" +/datum/supply_pack/security/maintenance_kits + name = "Gun Maintenance Kits" + desc = "Three gun maintenance kits for the repair and maintenance of a firearm." + access_view = ACCESS_BRIG + contains = list(/obj/item/gun_maintenance_supplies = 3) + cost = CARGO_CRATE_VALUE * 2 + crate_name = "gun maintenance kit crate" + /datum/supply_pack/security/firingpins name = "Standard Firing Pins Crate" desc = "Upgrade your arsenal with 10 standard firing pins." diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index 6f865171580b2..a5bb311c9c539 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -452,10 +452,6 @@ if (sawoff(user, A)) return - if(misfire_probability && istype(A, /obj/item/stack/sheet/cloth)) - if(guncleaning(user, A)) - return - return FALSE /obj/item/gun/ballistic/proc/check_if_held(mob/user) @@ -685,19 +681,6 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( update_appearance() return TRUE -/obj/item/gun/ballistic/proc/guncleaning(mob/user, obj/item/A) - if(misfire_probability == initial(misfire_probability)) - balloon_alert(user, "it's already clean!") - return - - user.changeNext_move(CLICK_CD_MELEE) - balloon_alert(user, "cleaning...") - - if(do_after(user, 10 SECONDS, target = src)) - misfire_probability = initial(misfire_probability) - balloon_alert(user, "fouling cleaned out") - return TRUE - /obj/item/gun/ballistic/wrench_act(mob/living/user, obj/item/I) if(!can_modify_ammo) return diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 0c0bcf18b00e2..2c41389c2305a 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -77,17 +77,16 @@ update_appearance() /obj/item/gun/ballistic/rifle/boltaction/attack_self(mob/user) - if(can_jam) - if(jammed) - if(prob(unjam_chance)) - jammed = FALSE - unjam_chance = 10 - else - unjam_chance += 10 - balloon_alert(user, "jammed!") - playsound(user,'sound/items/weapons/jammed.ogg', 75, TRUE) - return FALSE - ..() + if(jammed) + if(prob(unjam_chance)) + jammed = FALSE + unjam_chance = initial(unjam_chance) + else + unjam_chance += 10 + balloon_alert(user, "jammed!") + playsound(user,'sound/items/weapons/jammed.ogg', 75, TRUE) + return FALSE + return ..() /obj/item/gun/ballistic/rifle/boltaction/process_fire(mob/user) if(can_jam) @@ -105,15 +104,6 @@ . = ..() - if(istype(item, /obj/item/gun_maintenance_supplies)) - if(!can_jam) - balloon_alert(user, "can't jam!") - return - if(do_after(user, 10 SECONDS, target = src)) - user.visible_message(span_notice("[user] finishes maintaining [src].")) - jamming_chance = initial(jamming_chance) - qdel(item) - /obj/item/gun/ballistic/rifle/boltaction/blow_up(mob/user) . = FALSE if(chambered?.loaded_projectile) diff --git a/code/modules/vending/security.dm b/code/modules/vending/security.dm index a86f5562862d9..bf0b9dbee3862 100644 --- a/code/modules/vending/security.dm +++ b/code/modules/vending/security.dm @@ -17,6 +17,7 @@ /obj/item/restraints/legcuffs/bola/energy = 7, /obj/item/clothing/gloves/tackler = 5, /obj/item/holosign_creator/security = 2, + /obj/item/gun_maintenance_supplies = 2, ) contraband = list( /obj/item/clothing/glasses/sunglasses = 2, diff --git a/icons/obj/storage/toolbox.dmi b/icons/obj/storage/toolbox.dmi index 49385d5b73cf2a90b028d6fbd3931e1db29fdd28..ccc9c2cc4397e82ecf722fcea81860525f534073 100644 GIT binary patch delta 2094 zcmV+}2+{Za5$_VPHUR+g*KvwmawuRP=f0#smn1Xc; zJ97NTMcnc>pqXZSy{c9l9@TBV&392<=nyoT)bz5%J6O{>qX?G9I{Wz)-8mcn7>&(D zTQ~HqT;z=R#2phkZ(K*HEMYF+Z~Q<^-Ho`%uHO+#h#8|N9%&=Og<* z-T~kM00#$2L_t(|ob8D4J2-B*9FUlB+%A1kphHD^^uL8L|Oj- zkLfHLG@CRKMixomb%G>5VcunC$VYN#62F%1Se67oIFK7$+y`2psTL5{Tb(-Fure_-|L4Vum7PPIv> z?%-R#{zr($BMLGh8@~R>i2cVDWI{H4{Z9~wPbkQQY^3LJwOYHi7QxxYw`hDmFkB{*N)!Gu~kfFZhgp-q#qu-8BD9vYrfQl%fe_r^mk^pHf=S z6@l#f(j|Zl=|X9X0;)kn5Ks;F1p(FIP!y=u$kIh4Ko;`Tjws-y^*N4OpJolq0vZGX z4T69MMSx$!83GtbtxpxehV6%(La1h50FQu^BOukM2;d>&^9K>&>qi2Pa1nBH>q}R8 zig1y7m_;nme{zKSoZR}z&uJMxE`ANDtWzHV0000000000@IR)D=`qNWke^{(200S) zbIb*U90_?JGhmP-t9kbYqW6M=Ovr|>|0TkGNkJxL!`J@`aq)_ROvr|R{vl#89F0b3 ziz>l~{f+XGkQ0IK3pNB@;vx&2y<|ghMqFfp^H*#Lf6j@EEYKgZm#{w^XbKebQGSk8 zRDmv?I(VxUIHOYsZ?yvFbn4)(R$xen9=(8lt-xBjW&~uEDI}pxAqiy)NhnifgS^t~ z{vp%tak+c;r_7nlau89`&N>7I%pn=OTFE3;+FNFfw1!R<7%`N5@rqJIq`YALRq`MaL z?_dpl^8y>L0c8bX_yTlT%mDxZ000000002st6@EhwEsRbliW8~^|S00000 z0002K8v4&<207ZQ+*m*EmX_GxH}?Nm5h${Mzj6P6C4mzA`^NtNDgtHp_l^C36J_`J ze~tZrv%sdU!D4f>z_$1Q8CO?V83ODAu%-Qf#`yJEFR&apTmAo`-Txo36c`%>GUlKr z9~$%FMvvck5gVRByv*6p#pgE*=*Z9exq07^n;xIF1|E{3`4j*E00000004mh1)fCN z^{k8M`)_=nEi;&4rVMfI4{X=wjGD0U1d^rL1CgOeg=yOs4z^9-IFRbVpgm z>R^+HM-Z6J=0P||UqKkmeQYqBX}?oe|6PdmCy{&8o2*cK%2YL&Dgu6h%lGjXe~&z|4&P@VZ`peRBc| zWmg0M00000007?++uZkBg>CP@e;YCM-=iqHxmo_U-J2V9Ea$hk%l!6M&Xdp5Odv;= z>(B4MM~lVc&RtNV$i2fGDZl6Pdnq@4KCumf-2OW*Fj_>(3mh$6jX+**`g~$50(t%S zh`z89#f`KAIl1ZciERkv_TR}Ay1Pr}2;Ebr(EWXq(>-Mh<$OM|1%dqjf4jSQ_wN1s z_wOiVZ{bS$hYuf;oa_m?>GO#G z#OM~kjUbHx;^W7U$yFxVf0Oc0pFSmdvL^^M8etg5@%Z&PMmr(C!?pmPJ8>M45eVk$ z6#D%6bMgw)J$VX!`SK;n>7G1=Lj3K=<1u=Uu!t!%_lW=*hJpm}00$xd_Mvrw%FGM! z_fDR{m-_EE1kfVJqZ=190!ScCRxlX>ssCxc~qF07*qoM6N<$f_#qsA^-pY delta 1978 zcmV;r2Sxbr68sUcHUR+$lQ#hk4%-P=)oLWq`p{ZenA)}p#tolJI~H=;6N2a~Q&Oe#S(7l{a4`jP>(B-9I0X&Yib zX++fr<=|@n<69h|C?GSxF&%>PEI%h^p{$l=CP1VMiwyyQSM_&o4ZRvMf3bX=ytZ9- z`1+3@ahtaR)im4dRkPaU(cISCd{@=_0YRclo#7?k!II7ekDzI6i_@oI&&BY^sB|IP z+i0?KmQ&7A?ikBCWqp$GmhY*9xuwW*9R>0b9&yWhf7<>0)o;!i6M_IJhX?=w2AxSn zK~#90?VJl+8b=g{QA!tYf0)ofVq2{RS0M^*t!4=jy0p(Kn#5fG|Bva+nH_d+y92Tp zOwMboF~2YH$D6F`q@W#I}cP~GQK zPz4uNVEY-Lf^Be71$LkFDcA)UMW9}xydXG)N~K2!vFDlzRLcX{AtIF=4RDY9kcz8$$ zQfpmWLzeo&3yzMC4t_g0V$@zr0y?sQjx3;~3mhLGAO3!Lf6S=A(gfn`i?#qUWE-U+ z3+M)0l7McoBMImRd$K^K0$Z2N0BqzJOT?{uKEobX1q?_61|$Iknt-^6V+1IU zUY{;N4I6nbAyTs_Kxe>75K!vV1n3lrc`gEC{Y1c#ZbD9CebFwDkZw}>Y+{MJBh}|5 z)(1bQRm3>^e?6eHOnnG~AP9mW2!bHUcT9`Y=D?YhpHN&5oJsj9<%|PoQr@9-IdGP0 z-g-@Fzh)2<7{vO|3GO+An7|;`e?d6AU=R}+#Mkc;y1jnCPexJ+J?*TN_oW;JTCe#O zw7^9bI63E2Z~`u>!082_f>Ur&1v-8H7Iu1FLxFPMe^1VdiZ0M%ONWj|ffKfL=x7u; zWlM*SMu8ridh!N#i~>vLh8a-NmXLzBgcP(Tq@XR474lNM^@mEUE#&UWpDHJ=ke{9Y zrE+>EpUnIym~fSX8oPfRf{ zwM|F@e+Gp7^72gO@=_{*-$44&-8{uSg(dX2ig^ijyU}5a`8Ti!p1i<{dqCR(6tMsk zDdq@*AP9mW2!bF8@@RO^BI>{QEqS{A{grd2|K2yWx0Cww>G%Ja%dP$QrE^<<-}?E$ za=Eep-nZnd_4m`w_5OQ5-Tr;%pATf+zt8;he}Sx9f0?%yv+mz#{`o+3hs~ycpLL#j z|K6VWR(gI8Yq*!3M@!>T&o6uvS_Li7&%A%1b&enif*=TjAP9mWkB0pX4`_}&dA_7_V?^o{sFCk`zP0~v7g)75m~CzsSoi)v zf9LAzDn@|c0M@ks&$)hcZ5Ei%TU!19Ub_E2U@mZN5r|oXhP-FZdn-ME1V_ zpv3M%z8?t`RH_;49v}kV#G?ZAHbj1V>m^`k%zk+NH~)Ha0vbhEgdhllAP9mW-w^BE z_gaK?@4s8I^xuOZxVf4CZ@V`)f8<=vZ*S-M?X8+;j-~$|%x1GYcg6?;_l^!qelO(r zN}h*6V*i~M7|eq34Gw0mK_Ds5MIfpF9DyR-N2KYaM`o&iTQSIIwq{21nNB<0x?_TOpq)c5_t#Fu-Ie=gjGZo(zP zj$9?bg?mphKgwIc8~FYM|K<5||D9}1RY3Z$%W19%xVg{3Wa>W<$Rqt2L74% Date: Fri, 7 Feb 2025 02:30:34 +0000 Subject: [PATCH 067/104] Automatic changelog for PR #89205 [ci skip] --- html/changelogs/AutoChangeLog-pr-89205.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89205.yml diff --git a/html/changelogs/AutoChangeLog-pr-89205.yml b/html/changelogs/AutoChangeLog-pr-89205.yml new file mode 100644 index 0000000000000..0116ca9ee4011 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89205.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - refactor: "Gun maintenance is now consolidated into a single item, the gun maintenance kit, rather than multiple different item interactions. It is handled on the maintenance kit itself, and not in gun code." + - qol: "You can order maintenance kits from cargo, and get some out of the security equipment vendor. Helpful if someone spilled acid onto your disabler. You can also make a makeshift one from maintenance trash." \ No newline at end of file From 8b8e5f5e0fce55e14da325961363832a91b66593 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 6 Feb 2025 22:19:13 -0500 Subject: [PATCH 068/104] [NO GBP] fix my whoopsies from the void cloak fix pr (#89373) ## About The Pull Request thanks @MrMelbert for pointing out the mistake in my sleep deprived code - I accidentally registered `SIGNAL_ADDTRAIT(TRAIT_EXAMINE_SKIP), SIGNAL_REMOVETRAIT(TRAIT_EXAMINE_SKIP)` instead of `SIGNAL_ADDTRAIT(TRAIT_NO_WORN_ICON), SIGNAL_REMOVETRAIT(TRAIT_NO_WORN_ICON)` also, I accidentally left this in: ``` item.add_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON), REF(src)) // i'd use examine hide but its a flag and yeah ``` after making `TRAIT_EXAMINE_SKIP` a trait, so I added that. ## Why It's Good For The Game this should work properly ## Changelog :cl: fix: Fixed some mistakes I made while fixing the void cloak. /:cl: --- code/game/objects/items.dm | 4 ++-- code/modules/antagonists/heretic/items/heretic_armor.dm | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 3a5351d08f2c4..2597f763e25d6 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -696,7 +696,7 @@ if(item_flags & DROPDEL && !QDELETED(src)) qdel(src) item_flags &= ~IN_INVENTORY - UnregisterSignal(src, list(SIGNAL_ADDTRAIT(TRAIT_EXAMINE_SKIP), SIGNAL_REMOVETRAIT(TRAIT_EXAMINE_SKIP))) + UnregisterSignal(src, list(SIGNAL_ADDTRAIT(TRAIT_NO_WORN_ICON), SIGNAL_REMOVETRAIT(TRAIT_NO_WORN_ICON))) SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user) if(!silent) playsound(src, drop_sound, DROP_SOUND_VOLUME, vary = sound_vary, ignore_walls = FALSE) @@ -761,7 +761,7 @@ give_item_action(action, user, slot) item_flags |= IN_INVENTORY - RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_EXAMINE_SKIP), SIGNAL_REMOVETRAIT(TRAIT_EXAMINE_SKIP)), PROC_REF(update_slot_icon), override = TRUE) + RegisterSignals(src, list(SIGNAL_ADDTRAIT(TRAIT_NO_WORN_ICON), SIGNAL_REMOVETRAIT(TRAIT_NO_WORN_ICON)), PROC_REF(update_slot_icon), override = TRUE) if(!initial) if(equip_sound && (slot_flags & slot)) playsound(src, equip_sound, EQUIP_SOUND_VOLUME, TRUE, ignore_walls = FALSE) diff --git a/code/modules/antagonists/heretic/items/heretic_armor.dm b/code/modules/antagonists/heretic/items/heretic_armor.dm index b425c77a5034b..1d06412819f6f 100644 --- a/code/modules/antagonists/heretic/items/heretic_armor.dm +++ b/code/modules/antagonists/heretic/items/heretic_armor.dm @@ -111,11 +111,11 @@ /obj/item/clothing/suit/hooded/cultrobes/void/proc/hide_item(datum/source, obj/item/item, slot) SIGNAL_HANDLER if(slot & ITEM_SLOT_SUITSTORE) - item.add_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON), REF(src)) // i'd use examine hide but its a flag and yeah + item.add_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON, TRAIT_EXAMINE_SKIP), REF(src)) /obj/item/clothing/suit/hooded/cultrobes/void/proc/show_item(datum/source, obj/item/item, slot) SIGNAL_HANDLER - item.remove_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON), REF(src)) + item.remove_traits(list(TRAIT_NO_STRIP, TRAIT_NO_WORN_ICON, TRAIT_EXAMINE_SKIP), REF(src)) /obj/item/clothing/suit/hooded/cultrobes/void/examine(mob/user) . = ..() From 911e19c67b9f9e33e0997f34f2e383053e91cd5c Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 03:19:36 +0000 Subject: [PATCH 069/104] Automatic changelog for PR #89373 [ci skip] --- html/changelogs/AutoChangeLog-pr-89373.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89373.yml diff --git a/html/changelogs/AutoChangeLog-pr-89373.yml b/html/changelogs/AutoChangeLog-pr-89373.yml new file mode 100644 index 0000000000000..5cd0e2b2dcdb8 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89373.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "Fixed some mistakes I made while fixing the void cloak." \ No newline at end of file From 2b89a0493932fab70fd0affbc0a9faf5e220740e Mon Sep 17 00:00:00 2001 From: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com> Date: Fri, 7 Feb 2025 02:53:02 -0500 Subject: [PATCH 070/104] Unit Test failures now output a job summary, making it easier to see what the failures are. (#89284) This change was requested by Absolucy, of catgirl fame. ## About The Pull Request The CI is very useful for figuring out if you made any errors with your changes. Among other things, it runs unit tests on a variety of maps and BYOND versions, making sure everything still works as expected. Unfortunately, figuring out the specific errors you got in CI is a bit of a pain. You could scroll through the individual logs - but the logs are so long, it'd take forever. You could also use the annotations section, but that's gets filled with generic error messages: ![image](https://github.com/user-attachments/assets/0c01374d-65fd-4586-8bea-e71725e3ffe5) This PR helps on this matter, by adding [a job summary](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#adding-a-job-summary) whenever a failure is detected. Here's an example where I intentionally generated fails: ![image](https://github.com/user-attachments/assets/6f0fd948-125f-4685-9230-20fa48b2b357) (If you want to see how it looks on your own screen, have a look: ) As it is set up currently, each integration test job will generate its own summary; each summary contains one section per failed test; each section will contain the associated failure message(s) in a code block. This system is pretty basic currently (for example, breaking something across all maps will cause many job summaries to be generated), but it's a step up from what we had previously. Ideally, I'll come back to this later, and improve on the job summary output - for example, by merging identical errors across maps, and having the failures generated as a singular job summary. ## Why It's Good For The Game Having all the failures summarized in one place, without generic failure messages splattered in-between, can make it easier to diagnose issues detected by CI. --- .github/workflows/run_integration_tests.yml | 24 +++++++++++++++++++++ tools/ci/run_server.sh | 1 + 2 files changed, 25 insertions(+) diff --git a/.github/workflows/run_integration_tests.yml b/.github/workflows/run_integration_tests.yml index fc00b8cedc11e..6afc99b72612f 100644 --- a/.github/workflows/run_integration_tests.yml +++ b/.github/workflows/run_integration_tests.yml @@ -61,6 +61,7 @@ jobs: source $HOME/BYOND/byond/bin/byondsetup tools/build/build --ci dm -DCIBUILDING -DANSICOLORS -Werror -ITG0001 -I"loop_checks" - name: Run Tests + id: run_tests run: | source $HOME/BYOND/byond/bin/byondsetup bash tools/ci/run_server.sh ${{ inputs.map }} @@ -71,6 +72,29 @@ jobs: name: test_artifacts_${{ inputs.map }}_${{ inputs.major }}_${{ inputs.minor }} path: data/screenshots_new/ retention-days: 1 + - name: On test fail, write a step summary + if: always() && steps.run_tests.outcome == 'failure' + run: | + # Get a JSON array of failed unit tests + FAILED_UNIT_TESTS=$(jq 'to_entries | map(.value | select(.status == 1))' data/unit_tests.json) + + FAIL_COUNT=$(echo $FAILED_UNIT_TESTS | jq 'length') + + echo "# Test failures" >> $GITHUB_STEP_SUMMARY + echo "$FAIL_COUNT tests failed." >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + + for i in $( seq $FAIL_COUNT ); do + CURRENT_FAIL=$(echo $FAILED_UNIT_TESTS | jq --arg i $i '.[($i | tonumber) - 1]') + + TEST=$(echo $CURRENT_FAIL | jq --raw-output '.name') + + echo "### $TEST" >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo $CURRENT_FAIL | jq --raw-output '.message' >> $GITHUB_STEP_SUMMARY + echo '```' >> $GITHUB_STEP_SUMMARY + echo "" >> $GITHUB_STEP_SUMMARY + done - name: Check client Compatibility if: always() && steps.compile_tests.outcome == 'success' uses: tgstation/byond-client-compatibility-check@v3 diff --git a/tools/ci/run_server.sh b/tools/ci/run_server.sh index baf172d8ec3d8..e14d35cd9d4d6 100644 --- a/tools/ci/run_server.sh +++ b/tools/ci/run_server.sh @@ -22,5 +22,6 @@ cd .. mkdir -p data/screenshots_new cp -r ci_test/data/screenshots_new data/screenshots_new +cp ci_test/data/unit_tests.json data/unit_tests.json cat ci_test/data/logs/ci/clean_run.lk From 686cff0061a719f039499c538a61ff8857ebf914 Mon Sep 17 00:00:00 2001 From: Thunder12345 Date: Fri, 7 Feb 2025 14:36:31 +0000 Subject: [PATCH 071/104] Removed the mounted machine gun from the meta central domain (#89371) ## About The Pull Request See title, ding dong the machine gun is gone. ## Why It's Good For The Game It turned out to be a bad idea to put a mounted MG right next to a hostile player spawn in a low difficulty domain. Removing it should make the pirate spawn less capable of wiping the entire bitrunning squad before they clear the first pack of mobs. ## Changelog :cl: map: Removed a mounted machine gun from the Meta Central bitrunning domain, expect 85% less instant wipes. /:cl: --- _maps/virtual_domains/meta_central.dmm | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/_maps/virtual_domains/meta_central.dmm b/_maps/virtual_domains/meta_central.dmm index 3fc4ed7f21e1f..76f90e2c88bb6 100644 --- a/_maps/virtual_domains/meta_central.dmm +++ b/_maps/virtual_domains/meta_central.dmm @@ -1339,13 +1339,6 @@ /obj/item/pickaxe/rusted, /turf/open/floor/iron, /area/virtual_domain) -"lx" = ( -/obj/structure/barricade/sandbags, -/obj/machinery/deployable_turret{ - dir = 1 - }, -/turf/open/floor/plating, -/area/virtual_domain) "lC" = ( /obj/machinery/door/firedoor, /obj/machinery/door/airlock/public/glass{ @@ -7784,7 +7777,7 @@ LG uS hd Ol -lx +wN vU hp lu From 80d3d8a230bba7cb41fba11c7bd75831935c8698 Mon Sep 17 00:00:00 2001 From: "tgstation-ci[bot]" <179393467+tgstation-ci[bot]@users.noreply.github.com> Date: Fri, 7 Feb 2025 14:36:52 +0000 Subject: [PATCH 072/104] Automatic changelog for PR #89371 [ci skip] --- html/changelogs/AutoChangeLog-pr-89371.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-89371.yml diff --git a/html/changelogs/AutoChangeLog-pr-89371.yml b/html/changelogs/AutoChangeLog-pr-89371.yml new file mode 100644 index 0000000000000..b7ef76f2a0e10 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-89371.yml @@ -0,0 +1,4 @@ +author: "Thunder12345" +delete-after: True +changes: + - map: "Removed a mounted machine gun from the Meta Central bitrunning domain, expect 85% less instant wipes." \ No newline at end of file From bf61287cdb5259792c9274f70db0a39fc04309b3 Mon Sep 17 00:00:00 2001 From: Wallem <66052067+Wallemations@users.noreply.github.com> Date: Fri, 7 Feb 2025 13:54:21 -0500 Subject: [PATCH 073/104] Makes integrated circuit nodes more colorful (#89360) ## About The Pull Request Makes it so nodes in an integrated circuit are colored depending on their category in the component menu. Before: ![1212121212121212](https://github.com/user-attachments/assets/aec4602f-c837-415f-8f42-0dcfb9e0e4aa) After: ![452345235345](https://github.com/user-attachments/assets/2a28f471-f0c1-4fda-9727-41db18894cb1) All categories (BCI has been changed to solid black since this for contrast purposes) ![e](https://private-user-images.githubusercontent.com/66052067/410190943-b66d26b0-29b5-4b3f-8e65-35e6a44b74d1.png?jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJnaXRodWIuY29tIiwiYXVkIjoicmF3LmdpdGh1YnVzZXJjb250ZW50LmNvbSIsImtleSI6ImtleTUiLCJleHAiOjE3Mzg3OTU0OTIsIm5iZiI6MTczODc5NTE5MiwicGF0aCI6Ii82NjA1MjA2Ny80MTAxOTA5NDMtYjY2ZDI2YjAtMjliNS00YjNmLThlNjUtMzVlNmE0NGI3NGQxLnBuZz9YLUFtei1BbGdvcml0aG09QVdTNC1ITUFDLVNIQTI1NiZYLUFtei1DcmVkZW50aWFsPUFLSUFWQ09EWUxTQTUzUFFLNFpBJTJGMjAyNTAyMDUlMkZ1cy1lYXN0LTElMkZzMyUyRmF3czRfcmVxdWVzdCZYLUFtei1EYXRlPTIwMjUwMjA1VDIyMzk1MlomWC1BbXotRXhwaXJlcz0zMDAmWC1BbXotU2lnbmF0dXJlPWI5MzMxOWUyMzUxMmRkZTQwMThkOTNiNTk3OTEyOTExNWY4NjNkODE0YWJjZjE0MTQwYzM2YTZjYjY0ZGQ4ZDEmWC1BbXotU2lnbmVkSGVhZGVycz1ob3N0In0.uRa_SkIjdhzEbedzzLI1hDzOK-vpgC2ZNoQtvxo4ijE) If I was some sort of tgui magician I'd try to implement a way to add comment fields, but since I'm nowhere near that, I figured this was the least I could do. ## Why It's Good For The Game This makes it far easier to read integrated circuits and remember what they do. While there's still inherently some amount of confusion due to the nature of how node-based programming visually works, hopefully having it so nodes aren't all the same color helps a bit. ## Changelog :cl: Wallem qol: Integrated Circuit nodes are now colored depending on their type. /:cl: --- code/__DEFINES/wiremod.dm | 2 + .../wiremod/components/action/soundemitter.dm | 13 +++- code/modules/wiremod/core/component.dm | 22 ++++++- .../wiremod/core/integrated_circuit.dm | 2 + .../IntegratedCircuit/DisplayComponent.jsx | 18 +++++- .../IntegratedCircuit/ObjectComponent.jsx | 28 ++++++--- .../styles/interfaces/IntegratedCircuit.scss | 62 +++++++++++++++++++ 7 files changed, 133 insertions(+), 14 deletions(-) diff --git a/code/__DEFINES/wiremod.dm b/code/__DEFINES/wiremod.dm index 421650e3bf1e7..b606f938869a1 100644 --- a/code/__DEFINES/wiremod.dm +++ b/code/__DEFINES/wiremod.dm @@ -123,6 +123,8 @@ #define CIRCUIT_FLAG_REFUSE_MODULE (1<<5) /// This circuit component cannot be inserted into the same circuit multiple times. Only use this for major headaches. #define CIRCUIT_NO_DUPLICATES (1<<6) +/// This circuit component is currently disabled via configs +#define CIRCUIT_FLAG_DISABLED (1<<7) // Datatype flags /// The datatype supports manual inputs diff --git a/code/modules/wiremod/components/action/soundemitter.dm b/code/modules/wiremod/components/action/soundemitter.dm index 676ce8744385f..144a56295dd90 100644 --- a/code/modules/wiremod/components/action/soundemitter.dm +++ b/code/modules/wiremod/components/action/soundemitter.dm @@ -33,11 +33,19 @@ var/list/options_map +/obj/item/circuit_component/soundemitter/Initialize(mapload) + if(CONFIG_GET(flag/disallow_circuit_sounds)) + update_ui_alerts(new_flag=CIRCUIT_FLAG_DISABLED) + . = ..() + /obj/item/circuit_component/soundemitter/get_ui_notices() . = ..() . += create_ui_notice("Sound Cooldown: [DisplayTimeText(sound_cooldown)]", "orange", "stopwatch") if(CONFIG_GET(flag/disallow_circuit_sounds)) . += create_ui_notice("Non-functional", "red", "exclamation") + update_ui_alerts(new_flag=CIRCUIT_FLAG_DISABLED) + else + update_ui_alerts(remove_flag=CIRCUIT_FLAG_DISABLED) /obj/item/circuit_component/soundemitter/populate_ports() @@ -79,10 +87,11 @@ /obj/item/circuit_component/soundemitter/input_received(datum/port/input/port) if(CONFIG_GET(flag/disallow_circuit_sounds)) - ui_color = "red" + // Without constantly checking the config 24/7 or sending a signal to every circuit, best we can do to update existing emitters is this. + update_ui_alerts(new_flag=CIRCUIT_FLAG_DISABLED) return else - ui_color = initial(ui_color) + update_ui_alerts(remove_flag=CIRCUIT_FLAG_DISABLED) if(!parent.shell) return diff --git a/code/modules/wiremod/core/component.dm b/code/modules/wiremod/core/component.dm index 07f3a5b55a379..7dda865fb6409 100644 --- a/code/modules/wiremod/core/component.dm +++ b/code/modules/wiremod/core/component.dm @@ -64,6 +64,10 @@ /// The UI buttons of this circuit component. An assoc list that has this format: "button_icon" = "action_name" var/ui_buttons = null + /// The "important" UI tooltips of this circuit component. Used for important things like instant & disabled circuits, they're drawn next to the default tooltip icon. + /// An assoc list with the format ui_alerts["alert_icon"] = "alert_name". + var/ui_alerts = list() + /// Called when the option ports should be set up /obj/item/circuit_component/proc/populate_options() return @@ -86,8 +90,7 @@ trigger_input = add_input_port("Trigger", PORT_TYPE_SIGNAL, order = 2) if((circuit_flags & CIRCUIT_FLAG_OUTPUT_SIGNAL) && !trigger_output) trigger_output = add_output_port("Triggered", PORT_TYPE_SIGNAL, order = 2) - if(circuit_flags & CIRCUIT_FLAG_INSTANT) - ui_color = "orange" + update_ui_alerts() /obj/item/circuit_component/Destroy() if(parent) @@ -113,6 +116,21 @@ if(circuit_flags & CIRCUIT_FLAG_REFUSE_MODULE) . += span_notice("It's incompatible with module components.") +/// updates the ui alerts in the given component. new_flag adds flags, remove_flag removes them +/obj/item/circuit_component/proc/update_ui_alerts(new_flag, remove_flag) + if(new_flag) + circuit_flags |= new_flag + if(remove_flag) + circuit_flags &= ~remove_flag + if(circuit_flags & CIRCUIT_FLAG_INSTANT) + ui_alerts["tachometer-alt"] = "Instant" + else + ui_alerts -= "tachometer-alt" + if(circuit_flags & CIRCUIT_FLAG_DISABLED) + ui_alerts["exclamation"] = "Non-functional" + else + ui_alerts -= "exclamation" + /** * Called when a shell is registered from the component/the component is added to a circuit. * diff --git a/code/modules/wiremod/core/integrated_circuit.dm b/code/modules/wiremod/core/integrated_circuit.dm index 1023a59eb2100..dfaef0abcaa47 100644 --- a/code/modules/wiremod/core/integrated_circuit.dm +++ b/code/modules/wiremod/core/integrated_circuit.dm @@ -380,6 +380,8 @@ GLOBAL_LIST_EMPTY_TYPED(integrated_circuits, /obj/item/integrated_circuit) component_data["y"] = component.rel_y component_data["removable"] = component.removable component_data["color"] = component.ui_color + component_data["category"] = component.category + component_data["ui_alerts"] = component.ui_alerts component_data["ui_buttons"] = component.ui_buttons .["components"] += list(component_data) diff --git a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx index b0251a09e64bf..23269cd156744 100644 --- a/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx +++ b/tgui/packages/tgui/interfaces/IntegratedCircuit/DisplayComponent.jsx @@ -1,5 +1,6 @@ import { Component, createRef } from 'react'; import { Box, Button, Stack } from 'tgui-core/components'; +import { classes } from 'tgui-core/react'; import { noop } from './constants'; import { Port } from './Port'; @@ -39,24 +40,35 @@ export class DisplayComponent extends Component { render() { const { component, fixedSize, ...rest } = this.props; + const categoryClass = `ObjectComponent__Category__${component.category || 'Unassigned'}`; return (
{component.name} + {!!component.ui_alerts && + Object.keys(component.ui_alerts).map((icon) => ( + + ); if (is_blind) return content; - return {content}; + return content; } diff --git a/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx index 9a4f97362f8a6..1b70487f2df39 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/RawContents.tsx @@ -1,4 +1,4 @@ -import { Flex } from 'tgui-core/components'; +import { Box } from 'tgui-core/components'; import { createSearch } from 'tgui-core/string'; import { LootBox } from './LootBox'; @@ -17,12 +17,10 @@ export function RawContents(props: Props) { ); return ( - + {filteredContents.map((item) => ( - - - + ))} - + ); } diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx index 6c3c358636a2a..a010982357d5c 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/index.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -1,6 +1,8 @@ import { useState } from 'react'; -import { Button, Input, Section, Stack } from 'tgui-core/components'; +import { useMemo } from 'react'; +import { Box, Button, Input, Section } from 'tgui-core/components'; import { isEscape } from 'tgui-core/keys'; +import { clamp } from 'tgui-core/math'; import { BooleanLike } from 'tgui-core/react'; import { useBackend } from '../../backend'; @@ -18,54 +20,78 @@ export function LootPanel(props) { const { act, data } = useBackend(); const { contents = [], searching } = data; + // limitations: items with different stack counts, charges etc. + const contentsByPathName = useMemo(() => { + const acc: Record = {}; + + for (let i = 0; i < contents.length; i++) { + const item = contents[i]; + if (item.path) { + if (!acc[item.path + item.name]) { + acc[item.path + item.name] = []; + } + acc[item.path + item.name].push(item); + } else { + acc[item.ref] = [item]; + } + } + return acc; + }, [contents]); + const [grouping, setGrouping] = useState(true); const [searchText, setSearchText] = useState(''); - const total = contents.length ? contents.length - 1 : 0; + const headerHeight = 38; + const itemHeight = 38; + const minHeight = headerHeight + itemHeight; + const maxHeight = headerHeight + itemHeight * 10; + const height: number = clamp( + headerHeight + + (!grouping ? contents.length : Object.keys(contentsByPathName).length) * + itemHeight, + minHeight, + maxHeight, + ); return ( - + + setSearchText(value)} + placeholder={`Search items...`} + /> +