From 4339c0ba49b4b15aa132b983173ef57144965329 Mon Sep 17 00:00:00 2001 From: Jacquerel Date: Thu, 6 Jun 2024 00:13:38 +0100 Subject: [PATCH 01/81] Mutadone restores your original monkey status (#83720) ## About The Pull Request Before PR: Giving mutadone to a monkey turns it into a human Giving mutadone to a human does nothing about its human status After PR: Giving mutadone to a monkey created from a monkey cube does nothing about its monkey status Giving mutadone to a monkey which was originally a human restores it to being a human Giving mutadone to a human who has never been a monkey does nothing about its human status Giving mutadone to a human who was originally a monkey returns it to being a monkey I couldn't think of any better way to achieve this than putting a trait on the monkey typepath but if anyone has one, I'd love to hear it (actually, maybe I could just typecheck the mob... but that seems equally gross) ## Why It's Good For The Game Treating "being a monkey" as a mutation makes sense from the perspective of the DNA console but not from the perspective of certain other game mechanics. A chemical which "removes all mutations" should _intuitively_ restore people to the state they were in at the start of the round (so monkeys turned into humans should return to monkey, and vice versa) rather than unilaterally enact rapid evolution upon monkeys. At least, I don't _think_ it's meant to be a lore implication that all test apes on the station are transformed humans... This has a couple of side effects, both of which I think are desirable. Firstly- some mechanics work on humans but not monkeys (see #83698), and can be circumvented by spraying mutadone gas into a monkey pen. This will now only be achievable by individually mutating each monkey, which requires more effort for whatever your desired result is. Secondly- this adds a downside to the common "cure-all" surgical method of turning a monkey into a human and transplanting a brain into it. This new body will still genetically remember being a monkey, adding some element of risk to this otherwise undramatic means of curing basically any ailment in the game. Thirdly- Some people have admitted to using mutadoned monkeys to create a large number of humans to kill for Heretic and Changeling progression, which I also don't want them to do, so making this take longer is a positive. ## Changelog :cl: balance: Mutadone restores your originally monkey status, rather than always turning monkeys into humans /:cl: --- code/__DEFINES/traits/declarations.dm | 3 +++ code/_globalvars/traits/_traits.dm | 1 + code/datums/mutations/body.dm | 1 + code/modules/mob/living/carbon/human/monkey.dm | 1 + .../reagents/chemistry/reagents/medicine_reagents.dm | 12 ++++++++++++ 5 files changed, 18 insertions(+) diff --git a/code/__DEFINES/traits/declarations.dm b/code/__DEFINES/traits/declarations.dm index 580b6ef226456..457f7dfe45183 100644 --- a/code/__DEFINES/traits/declarations.dm +++ b/code/__DEFINES/traits/declarations.dm @@ -231,6 +231,9 @@ Remember to update _globalvars/traits.dm if you're adding/removing/renaming trai /// These mobs have particularly hygienic tongues #define TRAIT_WOUND_LICKER "wound_licker" +/// This trait designate that the mob was originally a monkey +#define TRAIT_BORN_MONKEY "born_as_a_monkey" + /// Added to a mob, allows that mob to experience flavour-based moodlets when examining food #define TRAIT_REMOTE_TASTING "remote_tasting" diff --git a/code/_globalvars/traits/_traits.dm b/code/_globalvars/traits/_traits.dm index 10b50f03e9ed6..94349d689de66 100644 --- a/code/_globalvars/traits/_traits.dm +++ b/code/_globalvars/traits/_traits.dm @@ -147,6 +147,7 @@ GLOBAL_LIST_INIT(traits_by_type, list( "TRAIT_BOMBIMMUNE" = TRAIT_BOMBIMMUNE, "TRAIT_BONSAI" = TRAIT_BONSAI, "TRAIT_BOOZE_SLIDER" = TRAIT_BOOZE_SLIDER, + "TRAIT_BORN_MONKEY" = TRAIT_BORN_MONKEY, "TRAIT_BRAINWASHING" = TRAIT_BRAINWASHING, "TRAIT_BRAWLING_KNOCKDOWN_BLOCKED" = TRAIT_BRAWLING_KNOCKDOWN_BLOCKED, "TRAIT_BYPASS_EARLY_IRRADIATED_CHECK" = TRAIT_BYPASS_EARLY_IRRADIATED_CHECK, diff --git a/code/datums/mutations/body.dm b/code/datums/mutations/body.dm index b45d0a6499e83..896820746d61d 100644 --- a/code/datums/mutations/body.dm +++ b/code/datums/mutations/body.dm @@ -196,6 +196,7 @@ quality = NEGATIVE remove_on_aheal = FALSE locked = TRUE //Species specific, keep out of actual gene pool + mutadone_proof = TRUE var/datum/species/original_species = /datum/species/human var/original_name diff --git a/code/modules/mob/living/carbon/human/monkey.dm b/code/modules/mob/living/carbon/human/monkey.dm index 7a2e7bb74747d..e63b35ab42af4 100644 --- a/code/modules/mob/living/carbon/human/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey.dm @@ -4,6 +4,7 @@ ai_controller = /datum/ai_controller/monkey /mob/living/carbon/human/species/monkey/Initialize(mapload, cubespawned = FALSE, mob/spawner) + ADD_TRAIT(src, TRAIT_BORN_MONKEY, INNATE_TRAIT) if (cubespawned) var/cap = CONFIG_GET(number/monkeycap) if (LAZYLEN(SSmobs.cubemonkeys) > cap) diff --git a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm index be9f32073157f..40513f930bfba 100644 --- a/code/modules/reagents/chemistry/reagents/medicine_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/medicine_reagents.dm @@ -1086,6 +1086,18 @@ ph = 2 chemical_flags = REAGENT_CAN_BE_SYNTHESIZED +/datum/reagent/medicine/mutadone/on_mob_metabolize(mob/living/affected_mob) + . = ..() + if (!ishuman(affected_mob)) + return + var/mob/living/carbon/human/human_mob = affected_mob + if (ismonkey(human_mob)) + if (!HAS_TRAIT(human_mob, TRAIT_BORN_MONKEY)) + human_mob.dna.remove_mutation(/datum/mutation/human/race) + else if (HAS_TRAIT(human_mob, TRAIT_BORN_MONKEY)) + human_mob.monkeyize() + + /datum/reagent/medicine/mutadone/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.remove_status_effect(/datum/status_effect/jitter) From 7cffec5cb4fc401095c13ea66a24487dec9c82da Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:16:19 +1200 Subject: [PATCH 02/81] Automatic changelog for PR #83720 [ci skip] --- html/changelogs/AutoChangeLog-pr-83720.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83720.yml diff --git a/html/changelogs/AutoChangeLog-pr-83720.yml b/html/changelogs/AutoChangeLog-pr-83720.yml new file mode 100644 index 0000000000000..2b7882210efe5 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83720.yml @@ -0,0 +1,4 @@ +author: "Jacquerel" +delete-after: True +changes: + - balance: "Mutadone restores your originally monkey status, rather than always turning monkeys into humans" \ No newline at end of file From e29c240a6cd7b5d9b880eb8bac42a5d308c83741 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Thu, 6 Jun 2024 00:32:49 +0000 Subject: [PATCH 03/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-81920.yml | 5 ---- html/changelogs/AutoChangeLog-pr-83471.yml | 4 --- html/changelogs/AutoChangeLog-pr-83487.yml | 7 ----- html/changelogs/AutoChangeLog-pr-83629.yml | 10 ------- html/changelogs/AutoChangeLog-pr-83659.yml | 4 --- html/changelogs/AutoChangeLog-pr-83697.yml | 6 ---- html/changelogs/AutoChangeLog-pr-83698.yml | 4 --- html/changelogs/AutoChangeLog-pr-83720.yml | 4 --- html/changelogs/archive/2024-06.yml | 34 ++++++++++++++++++++++ 9 files changed, 34 insertions(+), 44 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-81920.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83471.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83487.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83629.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83659.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83697.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83698.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83720.yml diff --git a/html/changelogs/AutoChangeLog-pr-81920.yml b/html/changelogs/AutoChangeLog-pr-81920.yml deleted file mode 100644 index dcf10c410e455..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-81920.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "Ben10Omintrix" -delete-after: True -changes: - - refactor: "honkbots are now basic mobs, please report any bugs" - - rscadd: "honkbots will try to slip people on banana peels" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83471.yml b/html/changelogs/AutoChangeLog-pr-83471.yml deleted file mode 100644 index b1e825dec9b24..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83471.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "Corrosive slime left behind after a slime fails to eat you can be scraped off with your hands, or shaken off in some other way, by clicking on the debuff. This is slower and less effective than washing it off using water." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83487.yml b/html/changelogs/AutoChangeLog-pr-83487.yml deleted file mode 100644 index c7407a21f5207..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83487.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - balance: "cultist shades can no longer contribute to rune invocation until they've been out of their soulstone for a minute. Put them in a shell for God's sake!" - - code_imp: "sweeps up cultist antag datum code into its own subfolder." - - code_imp: "cult shades now have their own antag datum." - - bugfix: "constructs now properly clear the cultist antag datum and transfer the mind slightly earlier." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83629.yml b/html/changelogs/AutoChangeLog-pr-83629.yml deleted file mode 100644 index da5ccb97bc66b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83629.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - qol: "more examines & screentips for plumbing machinery" - - qol: "plumbing grinder has a grind/juice mode which be toggled by hand" - - code_imp: "improved attack chain for RPLD & plumbing grinder" - - bugfix: "You can deconstruct the plumbing grinder with the RPLD" - - bugfix: "You can attack the plumbing grinder with any item in combat mode without getting that item consumed" - - bugfix: "You cannot grind abstract/ hologram items in the plumbing grinder" - - bugfix: "growing vat now uses the correct layer selected on rapid plumbing device" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83659.yml b/html/changelogs/AutoChangeLog-pr-83659.yml deleted file mode 100644 index 8daf3a629a664..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83659.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "mc-oofert" -delete-after: True -changes: - - balance: "cult stun gets weaker when they get red eyes and later more when they have halos" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83697.yml b/html/changelogs/AutoChangeLog-pr-83697.yml deleted file mode 100644 index 2d14759bc4c7f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83697.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - balance: "Doubled number of assignable wildcard slots on grey ID cards" - - balance: "Doubled number of assignable wildcard slots on silver ID cards" - - balance: "Doubled number of assignable wildcard slots on agent/chameleon ID cards" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83698.yml b/html/changelogs/AutoChangeLog-pr-83698.yml deleted file mode 100644 index 56ded989cb45e..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83698.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - rscadd: "A unique kind of mob is created when a Monkey is infested by a Legion." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83720.yml b/html/changelogs/AutoChangeLog-pr-83720.yml deleted file mode 100644 index 2b7882210efe5..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83720.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Jacquerel" -delete-after: True -changes: - - balance: "Mutadone restores your originally monkey status, rather than always turning monkeys into humans" \ No newline at end of file diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml index a2b1e0f705674..d3c188fd73c68 100644 --- a/html/changelogs/archive/2024-06.yml +++ b/html/changelogs/archive/2024-06.yml @@ -229,3 +229,37 @@ sprites. vendingmachine24: - spellcheck: Changed grammar in cat_house.dm +2024-06-06: + Ben10Omintrix: + - refactor: honkbots are now basic mobs, please report any bugs + - rscadd: honkbots will try to slip people on banana peels + Jacquerel: + - balance: Mutadone restores your originally monkey status, rather than always turning + monkeys into humans + - rscadd: A unique kind of mob is created when a Monkey is infested by a Legion. + - balance: Corrosive slime left behind after a slime fails to eat you can be scraped + off with your hands, or shaken off in some other way, by clicking on the debuff. + This is slower and less effective than washing it off using water. + LT3: + - balance: Doubled number of assignable wildcard slots on grey ID cards + - balance: Doubled number of assignable wildcard slots on silver ID cards + - balance: Doubled number of assignable wildcard slots on agent/chameleon ID cards + Rhials: + - balance: cultist shades can no longer contribute to rune invocation until they've + been out of their soulstone for a minute. Put them in a shell for God's sake! + - code_imp: sweeps up cultist antag datum code into its own subfolder. + - code_imp: cult shades now have their own antag datum. + - bugfix: constructs now properly clear the cultist antag datum and transfer the + mind slightly earlier. + SyncIt21: + - qol: more examines & screentips for plumbing machinery + - qol: plumbing grinder has a grind/juice mode which be toggled by hand + - code_imp: improved attack chain for RPLD & plumbing grinder + - bugfix: You can deconstruct the plumbing grinder with the RPLD + - bugfix: You can attack the plumbing grinder with any item in combat mode without + getting that item consumed + - bugfix: You cannot grind abstract/ hologram items in the plumbing grinder + - bugfix: growing vat now uses the correct layer selected on rapid plumbing device + mc-oofert: + - balance: cult stun gets weaker when they get red eyes and later more when they + have halos From 50f57b4b09d4cf957d3d38270f032165686e56f0 Mon Sep 17 00:00:00 2001 From: Jeremiah <42397676+jlsnow301@users.noreply.github.com> Date: Wed, 5 Jun 2024 18:01:20 -0700 Subject: [PATCH 04/81] tgui: changes typescript module resolution to recommended setting (#83597) ## About The Pull Request Swaps moduleResolution to the recommended setting. Should have no averse effects anywhere. Current moduleResolution: "Node" gives this tooltip message: `Node: Deprecated, use "Node10" in TypeScript 5.0+ instead` This PR: moduleResolution: "Bundler" `Bundler: This is the recommended setting in TypeScript 5.0+ for applications that use a bundler` (aka us) More info https://www.typescriptlang.org/tsconfig/#moduleResolution ## Why It's Good For The Game If you're wondering what this PR is even for, I'd like to centralize tg components eventually so we can distribute them as a npm package. This lets me use the aliased imports from that package, so if we do make that change it's one line: ![image](https://github.com/tgstation/tgstation/assets/42397676/1dbb0180-01ea-42fb-b8c2-dc83c3b2bd1a) In return we get to delete the entire tgui components folder, their style sheets, the common package, and maybe more. I have tested this using my (future PR) tgui library and it works. --- tgui/tsconfig.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tgui/tsconfig.json b/tgui/tsconfig.json index 9241d7bc9cbb3..99186312c9491 100644 --- a/tgui/tsconfig.json +++ b/tgui/tsconfig.json @@ -14,7 +14,7 @@ "ScriptHost" ], "module": "ESNext", - "moduleResolution": "Node", + "moduleResolution": "Bundler", "noEmit": true, "resolveJsonModule": true, "skipLibCheck": true, From d6d13f372e4aed38a46f9a0dd880667de3f4e8fa Mon Sep 17 00:00:00 2001 From: RedBaronFlyer <45489195+RedBaronFlyer@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:49:48 -0400 Subject: [PATCH 05/81] janitor keyring now spawns in all janitor's backpacks instead of only the first one's (#83103) ## About The Pull Request This PR makes it so that all janitors spawn with the keyring, instead of just the first one. So the janitor keyring was added roughly a year ago. I like it a lot but the one aspect that I never quite got was how the spawning worked. Currently, the janitor keyring spawns for the first janitor only. Any additional janitors will not get a keyring. The reasoning for doing so is as follows: (Per Adds the Janitor access keyring #73768 PR): _"I also wanted to limit how easy this is to greytide/steal, currently only the first Janitor spawns with the key. I thought it would be too easy to exploit otherwise, or essentially stolen roundstart if there were no Janitors."_ Although I understand the idea, I feel like the potential issue was overblown. There are significantly easier ways to tide than a keyring that: 1. Requires a head of staff to head to their office and grant keyring access. (Most heads of staff do not know how to do this, or that you can even do this) 2. Requires you to fumble with the keys at each door for several seconds, which makes an incredibly distinct and unique sound. 3. Expires after ten minutes. This isn't to mention other jobs that either start off with significant access (paramedic) or jobs that spawn with the tools to tide easily (engineering). If the keyring is being used for tiding, the head of staff can revoke access or have security/department personnel deal with whoever is abusing access ICly. ## Why It's Good For The Game Allows multiple janitors to respond to emergency mess calls. The second (or more) janitors aren't permanently lacking an important tool of the job the whole shift. ## Changelog :cl: add: Janitorial keyrings are now part of every janitor's toolkit instead of just the first one. /:cl: --- code/modules/jobs/job_types/janitor.dm | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/code/modules/jobs/job_types/janitor.dm b/code/modules/jobs/job_types/janitor.dm index 7b562bca670e6..13a3496c609d3 100644 --- a/code/modules/jobs/job_types/janitor.dm +++ b/code/modules/jobs/job_types/janitor.dm @@ -41,6 +41,7 @@ belt = /obj/item/modular_computer/pda/janitor ears = /obj/item/radio/headset/headset_srv skillchips = list(/obj/item/skillchip/job/janitor) + backpack_contents = list(/obj/item/access_key) /datum/outfit/job/janitor/pre_equip(mob/living/carbon/human/human_equipper, visuals_only) . = ..() @@ -48,11 +49,6 @@ backpack_contents += list(/obj/item/gun/ballistic/revolver) r_pocket = /obj/item/ammo_box/a357 - var/static/access_key_given = FALSE - if(!access_key_given && !visuals_only) - access_key_given = TRUE - backpack_contents += list(/obj/item/access_key) - /datum/outfit/job/janitor/get_types_to_preload() . = ..() if(check_holidays(GARBAGEDAY)) From 8e80467ec16bda2724cc25041e7ee20ee23ba720 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 13:57:16 +1200 Subject: [PATCH 06/81] Automatic changelog for PR #83103 [ci skip] --- html/changelogs/AutoChangeLog-pr-83103.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83103.yml diff --git a/html/changelogs/AutoChangeLog-pr-83103.yml b/html/changelogs/AutoChangeLog-pr-83103.yml new file mode 100644 index 0000000000000..3fff3c226022f --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83103.yml @@ -0,0 +1,4 @@ +author: "RedBaronFlyer" +delete-after: True +changes: + - rscadd: "Janitorial keyrings are now part of every janitor's toolkit instead of just the first one." \ No newline at end of file From 35216f127cad1e45ea55ab3151f65bb1c9777209 Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Thu, 6 Jun 2024 04:54:29 +0100 Subject: [PATCH 07/81] Paradox clones copy the voice. (#83729) ## About The Pull Request I have no idea if this works because I didn't setup TTS to test, but it's simple. Makes paradox clones use the victim's voice. ## Why It's Good For The Game Closes #81450 Because it doesn't make sense for a clone to have a different voice. ## Changelog :cl: fix: Fixes paradox clones using a different voice from the owner. /:cl: --- code/modules/mob/living/carbon/human/human_helpers.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/modules/mob/living/carbon/human/human_helpers.dm b/code/modules/mob/living/carbon/human/human_helpers.dm index 4caaac92bd533..da2c057d740bb 100644 --- a/code/modules/mob/living/carbon/human/human_helpers.dm +++ b/code/modules/mob/living/carbon/human/human_helpers.dm @@ -315,6 +315,8 @@ clone.fully_replace_character_name(null, dna.real_name) copy_clothing_prefs(clone) clone.age = age + clone.voice = voice + clone.pitch = pitch dna.transfer_identity(clone, transfer_SE = TRUE, transfer_species = TRUE) clone.dress_up_as_job(SSjob.GetJob(job)) From 3c6fe8fcd1aba93ff4a3f6579b6a03f01f73cfaa Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:54:51 +1200 Subject: [PATCH 08/81] Automatic changelog for PR #83729 [ci skip] --- html/changelogs/AutoChangeLog-pr-83729.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83729.yml diff --git a/html/changelogs/AutoChangeLog-pr-83729.yml b/html/changelogs/AutoChangeLog-pr-83729.yml new file mode 100644 index 0000000000000..af3a1e7123f19 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83729.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - bugfix: "Fixes paradox clones using a different voice from the owner." \ No newline at end of file From 29e99ddc97ec34c734187fd8a3cc1a7a5977b80e Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:56:36 -0400 Subject: [PATCH 09/81] Fixes COMSIG_ATOM_POST_DIR_CHANGE sending the wrong oldDir argument (#83727) ## About The Pull Request It didn't cache dir, so it just sent newDir. ## Why It's Good For The Game im starting to hate this signal ## Changelog :cl: fix: COMSIG_ATOM_POST_DIR_CHANGE should ACTUALLY work now /:cl: --- code/game/atom/_atom.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 46b4a1c391f22..f182d14d97e67 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -565,8 +565,9 @@ newdir = dir return SEND_SIGNAL(src, COMSIG_ATOM_DIR_CHANGE, dir, newdir) + var/oldDir = dir dir = newdir - SEND_SIGNAL(src, COMSIG_ATOM_POST_DIR_CHANGE, dir, newdir) + SEND_SIGNAL(src, COMSIG_ATOM_POST_DIR_CHANGE, oldDir, newdir) if(smoothing_flags & SMOOTH_BORDER_OBJECT) QUEUE_SMOOTH_NEIGHBORS(src) From e39925a1c054085393dc6507589769b27ebdc4f3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:56:55 +1200 Subject: [PATCH 10/81] Automatic changelog for PR #83727 [ci skip] --- html/changelogs/AutoChangeLog-pr-83727.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83727.yml diff --git a/html/changelogs/AutoChangeLog-pr-83727.yml b/html/changelogs/AutoChangeLog-pr-83727.yml new file mode 100644 index 0000000000000..43106a2e857dd --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83727.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - bugfix: "COMSIG_ATOM_POST_DIR_CHANGE should ACTUALLY work now" \ No newline at end of file From 078a4a21b7819edd192529c2bb7f137a44520338 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Thu, 6 Jun 2024 06:01:01 +0200 Subject: [PATCH 11/81] Fixes RLD glowsticks not actually glowing (#83725) ## About The Pull Request So apparently RLD glowsticks just straight up didn't glow, but also thought they were on. Looking into it, this seemed to be an issue of it using `G.light_on = TRUE` rather than `G.turn_on()`. Replacing it with the latter fixes our issue. We then also just, replace the single letter variable `G`. ## Why It's Good For The Game Y'know I think glowsticks should probably like, actually glow, right? ## Changelog :cl: fix: RLD glowsticks actually glow again. /:cl: --- code/game/objects/items/rcd/RLD.dm | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/code/game/objects/items/rcd/RLD.dm b/code/game/objects/items/rcd/RLD.dm index 6272c7a374d37..e321e5e941d67 100644 --- a/code/game/objects/items/rcd/RLD.dm +++ b/code/game/objects/items/rcd/RLD.dm @@ -188,12 +188,12 @@ if(!useResource(GLOW_STICK_COST, user)) return FALSE activate() - var/obj/item/flashlight/glowstick/G = new /obj/item/flashlight/glowstick(start) - G.color = color_choice - G.set_light_color(G.color) - G.throw_at(A, 9, 3, user) - G.light_on = TRUE - G.update_brightness() + var/obj/item/flashlight/glowstick/new_stick = new /obj/item/flashlight/glowstick(start) + new_stick.color = color_choice + new_stick.set_light_color(new_stick.color) + new_stick.throw_at(A, 9, 3, user) + new_stick.turn_on() + new_stick.update_brightness() return TRUE From b8fb2224bf071a67386ae4e6573d96af4127841f Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:01:22 +1200 Subject: [PATCH 12/81] Automatic changelog for PR #83725 [ci skip] --- html/changelogs/AutoChangeLog-pr-83725.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83725.yml diff --git a/html/changelogs/AutoChangeLog-pr-83725.yml b/html/changelogs/AutoChangeLog-pr-83725.yml new file mode 100644 index 0000000000000..2f0fa7f196361 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83725.yml @@ -0,0 +1,4 @@ +author: "00-Steven" +delete-after: True +changes: + - bugfix: "RLD glowsticks actually glow again." \ No newline at end of file From 98ee18f39f7b6b5c9365315e07c71487e4b3ad29 Mon Sep 17 00:00:00 2001 From: EEASAS <109891564+EEASAS@users.noreply.github.com> Date: Thu, 6 Jun 2024 01:04:20 -0300 Subject: [PATCH 13/81] Fixes a sorting pipe in Birdshot (#83723) ## About The Pull Request fixed a singular sorting disposal pipe in janitor office in Birdshot ## Why It's Good For The Game fixes are good i guess ## Changelog :cl: fix: fixed the mis-rotated disposals pipe on birdshot /:cl: --- _maps/map_files/Birdshot/birdshot.dmm | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_maps/map_files/Birdshot/birdshot.dmm b/_maps/map_files/Birdshot/birdshot.dmm index dc6252b564ed4..3b567283936bd 100644 --- a/_maps/map_files/Birdshot/birdshot.dmm +++ b/_maps/map_files/Birdshot/birdshot.dmm @@ -38619,11 +38619,11 @@ dir = 1 }, /obj/machinery/atmospherics/pipe/smart/manifold4w/supply/hidden/layer4, -/obj/structure/disposalpipe/sorting/mail{ - dir = 4 - }, /obj/machinery/atmospherics/pipe/smart/manifold4w/scrubbers/hidden/layer2, /obj/effect/mapping_helpers/mail_sorting/service/janitor_closet, +/obj/structure/disposalpipe/sorting/mail/flip{ + dir = 8 + }, /turf/open/floor/iron/white/small, /area/station/service/janitor) "nVe" = ( From 486ebf6c4daa0ac8853d2a756bc148a6dd297ca1 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:04:39 +1200 Subject: [PATCH 14/81] Automatic changelog for PR #83723 [ci skip] --- html/changelogs/AutoChangeLog-pr-83723.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83723.yml diff --git a/html/changelogs/AutoChangeLog-pr-83723.yml b/html/changelogs/AutoChangeLog-pr-83723.yml new file mode 100644 index 0000000000000..0f5e6c311c5dc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83723.yml @@ -0,0 +1,4 @@ +author: "EEASAS" +delete-after: True +changes: + - bugfix: "fixed the mis-rotated disposals pipe on birdshot" \ No newline at end of file From f7ad080d7626ee7815dc344f16c3f8560977f051 Mon Sep 17 00:00:00 2001 From: san7890 Date: Wed, 5 Jun 2024 22:37:35 -0600 Subject: [PATCH 15/81] Fixes Using 'ESC' Key To Unbind Keybindings + Adds Function to Check It Elsewhere (#83710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request Consequence of #80335 (d3554b3902384071415bb09e408ecebd9396fe5a) ![image](https://github.com/tgstation/tgstation/assets/34697715/cce22c30-e4d0-4f92-b8af-de908fbcce28) Likely some weird IE shit, we get "Esc" instead of "Escape". I added it as a function so this is a bit hardier to potentially breaking so it doesn't go haywire silently again when we migrate to Webview2. It's also likely that a weird combo of OS and IE and BYOND Version and whatever will spit out "Esc" instead of "Escape", so let's just have a helper function to access both so we don't have to worry about it any more. ✅: Works on my machine ## Why It's Good For The Game Players should be allowed to unbind whatever keys they want, regressions are bad. New helper function that can check both cases (since we're unsure of why either case pops up and it's unlikely that we have control over it) was implemented in every spot where we were checking `KEY.Escape` in this PR as well. ## Changelog :cl: fix: Using the 'ESC' key on your keyboard to unbind a key in the keybindings preferences menu should now work as expected. This should also be fixed for people in a variety of other spots too. /:cl: My javascript is a bit bad let me know if I'm doing something wack --- tgui/packages/common/keys.ts | 19 +++++++++++++++++++ tgui/packages/tgui-say/TguiSay.tsx | 9 +++++---- tgui/packages/tgui/components/Button.tsx | 6 +++--- tgui/packages/tgui/components/Input.tsx | 4 ++-- tgui/packages/tgui/components/NumberInput.tsx | 4 ++-- tgui/packages/tgui/components/TextArea.tsx | 4 ++-- tgui/packages/tgui/interfaces/AlertModal.tsx | 11 +++++++---- .../tgui/interfaces/KeyComboModal.tsx | 8 ++++---- .../tgui/interfaces/LootPanel/index.tsx | 4 ++-- .../tgui/interfaces/NumberInputModal.tsx | 4 ++-- .../PreferencesMenu/KeybindingsPage.tsx | 6 +++--- .../tgui/interfaces/TextInputModal.tsx | 4 ++-- 12 files changed, 53 insertions(+), 30 deletions(-) diff --git a/tgui/packages/common/keys.ts b/tgui/packages/common/keys.ts index 34ac9e1614dde..3e913151707ff 100644 --- a/tgui/packages/common/keys.ts +++ b/tgui/packages/common/keys.ts @@ -5,6 +5,7 @@ * Handles modifier keys (Shift, Alt, Control) and arrow keys. * * For alphabetical keys, use the actual character (e.g. 'a') instead of the key code. + * Don't access Esc or Escape directly, use isEscape() instead * * Something isn't here that you want? Just add it: * @url https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values @@ -16,6 +17,8 @@ * // do something * } * ``` + * + * */ export enum KEY { Alt = 'Alt', @@ -25,6 +28,7 @@ export enum KEY { Down = 'ArrowDown', End = 'End', Enter = 'Enter', + Esc = 'Esc', Escape = 'Escape', Home = 'Home', Insert = 'Insert', @@ -37,3 +41,18 @@ export enum KEY { Tab = 'Tab', Up = 'ArrowUp', } + +/** + * ### isEscape + * + * Checks if the user has hit the 'ESC' key on their keyboard. + * There's a weirdness in BYOND where this could be either the string + * 'Escape' or 'Esc' depending on the browser. This function handles + * both cases. + * + * @param key - the key to check, typically from event.key + * @returns true if key is Escape or Esc, false otherwise + */ +export function isEscape(key: string): boolean { + return key === KEY.Esc || key === KEY.Escape; +} diff --git a/tgui/packages/tgui-say/TguiSay.tsx b/tgui/packages/tgui-say/TguiSay.tsx index 39043a978b8cf..7bc459c7f2e84 100644 --- a/tgui/packages/tgui-say/TguiSay.tsx +++ b/tgui/packages/tgui-say/TguiSay.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { BooleanLike } from 'common/react'; import { Component, createRef, RefObject } from 'react'; import { dragStartHandler } from 'tgui/drag'; @@ -245,9 +245,10 @@ export class TguiSay extends Component<{}, State> { this.handleIncrementChannel(); break; - case KEY.Escape: - this.handleClose(); - break; + default: + if (isEscape(event.key)) { + this.handleClose(); + } } } diff --git a/tgui/packages/tgui/components/Button.tsx b/tgui/packages/tgui/components/Button.tsx index 25b1e78f06177..ec621de621ef0 100644 --- a/tgui/packages/tgui/components/Button.tsx +++ b/tgui/packages/tgui/components/Button.tsx @@ -5,7 +5,7 @@ */ import { Placement } from '@popperjs/core'; -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { BooleanLike, classes } from 'common/react'; import { ChangeEvent, @@ -131,7 +131,7 @@ export const Button = (props: Props) => { } // Refocus layout on pressing escape. - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { event.preventDefault(); } }} @@ -343,7 +343,7 @@ const ButtonInput = (props: InputProps) => { commitResult(event); return; } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { setInInput(false); } }} diff --git a/tgui/packages/tgui/components/Input.tsx b/tgui/packages/tgui/components/Input.tsx index 36d928ce2151a..9bc48aa809406 100644 --- a/tgui/packages/tgui/components/Input.tsx +++ b/tgui/packages/tgui/components/Input.tsx @@ -4,7 +4,7 @@ * @license MIT */ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { classes } from 'common/react'; import { debounce } from 'common/timer'; import { KeyboardEvent, SyntheticEvent, useEffect, useRef } from 'react'; @@ -127,7 +127,7 @@ export function Input(props: Props) { return; } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { onEscape?.(event); event.currentTarget.value = toInputValue(value); diff --git a/tgui/packages/tgui/components/NumberInput.tsx b/tgui/packages/tgui/components/NumberInput.tsx index 572b0070bcaa9..892a43eddf3c0 100644 --- a/tgui/packages/tgui/components/NumberInput.tsx +++ b/tgui/packages/tgui/components/NumberInput.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { clamp } from 'common/math'; import { BooleanLike, classes } from 'common/react'; import { @@ -239,7 +239,7 @@ export class NumberInput extends Component { onChange?.(targetValue); onDrag?.(targetValue); } - } else if (event.key === KEY.Escape) { + } else if (isEscape(event.key)) { this.setState({ editing: false, }); diff --git a/tgui/packages/tgui/components/TextArea.tsx b/tgui/packages/tgui/components/TextArea.tsx index 82302b98b2b63..0482229b8fd4b 100644 --- a/tgui/packages/tgui/components/TextArea.tsx +++ b/tgui/packages/tgui/components/TextArea.tsx @@ -5,7 +5,7 @@ * @license MIT */ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { classes } from 'common/react'; import { forwardRef, @@ -82,7 +82,7 @@ export const TextArea = forwardRef( return; } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { onEscape?.(event); if (selfClear) { event.currentTarget.value = ''; diff --git a/tgui/packages/tgui/interfaces/AlertModal.tsx b/tgui/packages/tgui/interfaces/AlertModal.tsx index 62b6e8bbbc328..5924dc7ae7cf2 100644 --- a/tgui/packages/tgui/interfaces/AlertModal.tsx +++ b/tgui/packages/tgui/interfaces/AlertModal.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { BooleanLike } from 'common/react'; import { KeyboardEvent, useState } from 'react'; @@ -55,9 +55,6 @@ export function AlertModal(props) { case KEY.Enter: act('choose', { choice: buttons[selected] }); return; - case KEY.Escape: - act('cancel'); - return; case KEY.Left: event.preventDefault(); onKey(DIRECTION.Decrement); @@ -67,6 +64,12 @@ export function AlertModal(props) { event.preventDefault(); onKey(DIRECTION.Increment); return; + + default: + if (isEscape(event.key)) { + act('cancel'); + return; + } } } diff --git a/tgui/packages/tgui/interfaces/KeyComboModal.tsx b/tgui/packages/tgui/interfaces/KeyComboModal.tsx index e0b598764f156..0340ae811cd77 100644 --- a/tgui/packages/tgui/interfaces/KeyComboModal.tsx +++ b/tgui/packages/tgui/interfaces/KeyComboModal.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { useState } from 'react'; import { useBackend, useLocalState } from '../backend'; @@ -20,7 +20,7 @@ const isStandardKey = (event: React.KeyboardEvent): boolean => { event.key !== KEY.Alt && event.key !== KEY.Control && event.key !== KEY.Shift && - event.key !== KEY.Escape + !isEscape(event.key) ); }; @@ -97,7 +97,7 @@ export const KeyComboModal = (props) => { if (event.key === KEY.Enter) { act('submit', { entry: input }); } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { act('cancel'); } return; @@ -109,7 +109,7 @@ export const KeyComboModal = (props) => { setValue(formatKeyboardEvent(event)); setBinding(false); return; - } else if (event.key === KEY.Escape) { + } else if (isEscape(event.key)) { setValue(init_value); setBinding(false); return; diff --git a/tgui/packages/tgui/interfaces/LootPanel/index.tsx b/tgui/packages/tgui/interfaces/LootPanel/index.tsx index bc6330b1806f7..c04306204045c 100644 --- a/tgui/packages/tgui/interfaces/LootPanel/index.tsx +++ b/tgui/packages/tgui/interfaces/LootPanel/index.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape } from 'common/keys'; import { BooleanLike } from 'common/react'; import { useState } from 'react'; @@ -27,7 +27,7 @@ export function LootPanel(props) { { - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { Byond.sendMessage('close'); } }} diff --git a/tgui/packages/tgui/interfaces/NumberInputModal.tsx b/tgui/packages/tgui/interfaces/NumberInputModal.tsx index 938b24d0c6e07..c7c7b1c5831ca 100644 --- a/tgui/packages/tgui/interfaces/NumberInputModal.tsx +++ b/tgui/packages/tgui/interfaces/NumberInputModal.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { useState } from 'react'; import { useBackend } from '../backend'; @@ -44,7 +44,7 @@ export const NumberInputModal = (props) => { if (event.key === KEY.Enter) { act('submit', { entry: input }); } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { act('cancel'); } }} diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx index 32d39c287df94..874095b84eac2 100644 --- a/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/KeybindingsPage.tsx @@ -1,5 +1,5 @@ import { range, sortBy } from 'common/collections'; -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { Component } from 'react'; import { resolveAsset } from '../../assets'; @@ -42,7 +42,7 @@ const isStandardKey = (event: KeyboardEvent): boolean => { event.key !== KEY.Alt && event.key !== KEY.Control && event.key !== KEY.Shift && - event.key !== KEY.Escape + !isEscape(event.key) ); }; @@ -287,7 +287,7 @@ export class KeybindingsPage extends Component<{}, KeybindingsPageState> { if (isStandardKey(event)) { this.setRebindingHotkey(formatKeyboardEvent(event)); return; - } else if (event.key === KEY.Escape) { + } else if (isEscape(event.key)) { this.setRebindingHotkey(undefined); return; } diff --git a/tgui/packages/tgui/interfaces/TextInputModal.tsx b/tgui/packages/tgui/interfaces/TextInputModal.tsx index 52517bcbbfe3b..980fa6db797fb 100644 --- a/tgui/packages/tgui/interfaces/TextInputModal.tsx +++ b/tgui/packages/tgui/interfaces/TextInputModal.tsx @@ -1,4 +1,4 @@ -import { KEY } from 'common/keys'; +import { isEscape, KEY } from 'common/keys'; import { KeyboardEvent, useState } from 'react'; import { useBackend } from '../backend'; @@ -67,7 +67,7 @@ export const TextInputModal = (props) => { ) { act('submit', { entry: input }); } - if (event.key === KEY.Escape) { + if (isEscape(event.key)) { act('cancel'); } }} From 96aab0bf53681c753dc59d193b06d841246fc57f Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:37:53 +1200 Subject: [PATCH 16/81] Automatic changelog for PR #83710 [ci skip] --- html/changelogs/AutoChangeLog-pr-83710.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83710.yml diff --git a/html/changelogs/AutoChangeLog-pr-83710.yml b/html/changelogs/AutoChangeLog-pr-83710.yml new file mode 100644 index 0000000000000..a02f0e991cdc1 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83710.yml @@ -0,0 +1,4 @@ +author: "san7890" +delete-after: True +changes: + - bugfix: "Using the 'ESC' key on your keyboard to unbind a key in the keybindings preferences menu should now work as expected. This should also be fixed for people in a variety of other spots too." \ No newline at end of file From f26e2bb58c55f521c41f2dd2ee1fb847ae5612b6 Mon Sep 17 00:00:00 2001 From: zxaber <37497534+zxaber@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:41:40 -0700 Subject: [PATCH 17/81] Fixes tool-based flashes being stuck at intensity 1 (#83703) ## About The Pull Request A long-old bug due to the use of `min(flash_strength, 1)`. The intention was clearly to have the flash be *at least* level 1, because flash_strength defaults to nothing but can be set to 2. However, `min(x,y)` uses the lowest value, making it always return 1. So we change it to `max()`. ## Why It's Good For The Game Bugfix. Sunglasses users cope. ## Changelog :cl: fix: Tool-based flashes (read: from welders) are no longer incorrectly locked at flash level 1. Wear proper PPE! /:cl: --- code/datums/elements/tool_flash.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/elements/tool_flash.dm b/code/datums/elements/tool_flash.dm index fd7c298d6c54e..f17d60970bf58 100644 --- a/code/datums/elements/tool_flash.dm +++ b/code/datums/elements/tool_flash.dm @@ -34,4 +34,4 @@ SIGNAL_HANDLER if(user && get_dist(get_turf(source), get_turf(user)) <= 1) - user.flash_act(min(flash_strength,1)) + user.flash_act(max(flash_strength,1)) From 6cabe58b4579757edf0f394ab76b99a40f037ece Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:42:02 +1200 Subject: [PATCH 18/81] Automatic changelog for PR #83703 [ci skip] --- html/changelogs/AutoChangeLog-pr-83703.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83703.yml diff --git a/html/changelogs/AutoChangeLog-pr-83703.yml b/html/changelogs/AutoChangeLog-pr-83703.yml new file mode 100644 index 0000000000000..fe215399c4886 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83703.yml @@ -0,0 +1,4 @@ +author: "zxaber" +delete-after: True +changes: + - bugfix: "Tool-based flashes (read: from welders) are no longer incorrectly locked at flash level 1. Wear proper PPE!" \ No newline at end of file From 7204db12690108e9ed085093a0076bca7bbbae99 Mon Sep 17 00:00:00 2001 From: Lucy Date: Thu, 6 Jun 2024 00:48:09 -0400 Subject: [PATCH 19/81] Makes transferring functional wings to new bodies actually work (#83705) ## About The Pull Request Fixes the bug where, if you surgically remove functional wings and then re-implant them (even into yourself), the new owner won't get the toggle wings button. This fixes that. Also cleaned up some of the code. ## Why It's Good For The Game i assume this is a bug, as it's just kinda weird that the wings that work with one body won't work if you take them out and put them back in. ## Changelog :cl: fix: When implanting functional wings into a new body, they will actually be able to use said wings now. /:cl: --- .../organs/external/wings/functional_wings.dm | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/code/modules/surgery/organs/external/wings/functional_wings.dm b/code/modules/surgery/organs/external/wings/functional_wings.dm index da3fe3353035c..23f897bce95a2 100644 --- a/code/modules/surgery/organs/external/wings/functional_wings.dm +++ b/code/modules/surgery/organs/external/wings/functional_wings.dm @@ -8,7 +8,7 @@ /datum/action/innate/flight/Activate() var/mob/living/carbon/human/human = owner var/obj/item/organ/external/wings/functional/wings = human.get_organ_slot(ORGAN_SLOT_EXTERNAL_WINGS) - if(wings && wings.can_fly(human)) + if(wings?.can_fly(human)) wings.toggle_flight(human) if(!(human.movement_type & FLYING)) to_chat(human, span_notice("You settle gently back onto the ground...")) @@ -29,23 +29,26 @@ // grind_results = list(/datum/reagent/flightpotion = 5) food_reagents = list(/datum/reagent/flightpotion = 5) +/obj/item/organ/external/wings/functional/Destroy() + QDEL_NULL(fly) + return ..() + /obj/item/organ/external/wings/functional/Insert(mob/living/carbon/receiver, special, movement_flags) . = ..() - if(. && isnull(fly)) + if(!.) + return + if(QDELETED(fly)) fly = new - fly.Grant(receiver) + fly.Grant(receiver) /obj/item/organ/external/wings/functional/Remove(mob/living/carbon/organ_owner, special, movement_flags) . = ..() - - fly.Remove(organ_owner) - + fly?.Remove(organ_owner) if(wings_open) toggle_flight(organ_owner) /obj/item/organ/external/wings/functional/on_life(seconds_per_tick, times_fired) . = ..() - handle_flight(owner) ///Called on_life(). Handle flight code and check if we're still flying From f907dbeb192d5e25b78862851494889521269981 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:51:06 +1200 Subject: [PATCH 20/81] Automatic changelog for PR #83705 [ci skip] --- html/changelogs/AutoChangeLog-pr-83705.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83705.yml diff --git a/html/changelogs/AutoChangeLog-pr-83705.yml b/html/changelogs/AutoChangeLog-pr-83705.yml new file mode 100644 index 0000000000000..6f559c14e3cde --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83705.yml @@ -0,0 +1,4 @@ +author: "Absolucy" +delete-after: True +changes: + - bugfix: "When implanting functional wings into a new body, they will actually be able to use said wings now." \ No newline at end of file From 73dfd616349349b6573f886c348af5030b9687cf Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:54:18 +1000 Subject: [PATCH 21/81] [NO GBP] Fixes drake empowerment for berserker armor by adding drake remains, which are used to make drake armor and empower the suit (#83700) ## About The Pull Request Fixes https://github.com/tgstation/tgstation/issues/83684 Adds an intermediary item called drake remains, which are used to construct drake armor and empower berserker armor. There is no functional balance change here, as the components to make a drake armor are relatively the same. ## Why It's Good For The Game I borked it. This is the most reasonable and flexible method to fix the bug and what I should have done in the first place. ## Changelog :cl: fix: Drake empowerment for berserker armor now uses valuable drake remains, made from ashdrake hides and bones. add: Drake armor is made use drake remains to construct. (This is a net neutral to the previous recipe) /:cl: --- code/datums/components/crafting/tailoring.dm | 13 ++++++++++-- code/modules/cargo/exports/lavaland.dm | 1 + code/modules/mining/lavaland/tendril_loot.dm | 22 ++++++++++++++------ 3 files changed, 28 insertions(+), 8 deletions(-) diff --git a/code/datums/components/crafting/tailoring.dm b/code/datums/components/crafting/tailoring.dm index e2ba25e9c458c..2bcec49aeb504 100644 --- a/code/datums/components/crafting/tailoring.dm +++ b/code/datums/components/crafting/tailoring.dm @@ -255,10 +255,19 @@ /datum/crafting_recipe/drakecloak name = "Ash Drake Armour" result = /obj/item/clothing/suit/hooded/cloak/drake - time = 6 SECONDS + time = 4 SECONDS reqs = list( - /obj/item/stack/sheet/bone = 10, /obj/item/stack/sheet/sinew = 2, + /obj/item/drake_remains = 1, + ) + category = CAT_CLOTHING + +/datum/crafting_recipe/drakeremains + name = "Drake Remains" + result = /obj/item/drake_remains + time = 1 SECONDS + reqs = list( + /obj/item/stack/sheet/bone = 10, /obj/item/stack/sheet/animalhide/ashdrake = 5, ) category = CAT_CLOTHING diff --git a/code/modules/cargo/exports/lavaland.dm b/code/modules/cargo/exports/lavaland.dm index 51165be191c87..7102db0dd8f0d 100644 --- a/code/modules/cargo/exports/lavaland.dm +++ b/code/modules/cargo/exports/lavaland.dm @@ -33,6 +33,7 @@ export_types = list( /obj/item/dragons_blood, /obj/item/guardian_creator/miner, + /obj/item/drake_remains, /obj/item/lava_staff, /obj/item/melee/ghost_sword, /obj/item/prisoncube, diff --git a/code/modules/mining/lavaland/tendril_loot.dm b/code/modules/mining/lavaland/tendril_loot.dm index 7433b2b55daaa..6dfc8cfe40c3a 100644 --- a/code/modules/mining/lavaland/tendril_loot.dm +++ b/code/modules/mining/lavaland/tendril_loot.dm @@ -661,8 +661,8 @@ name = "berserker armor" desc = "This hulking armor seems to possess some kind of dark force within; howling in rage, hungry for carnage. \ The self-sealing stem bolts that allowed this suit to be spaceworthy have long since corroded. However, the entity \ - sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left within drake armor. \ - Feeding it seems to empower a suit piece, though turns the drake armor back to lifeless ash." + sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left in the remains of drakes. \ + Feeding it drake remains seems to empower a suit piece, though turns the remains back to lifeless ash." icon_state = "berserker" icon = 'icons/obj/clothing/suits/armor.dmi' worn_icon = 'icons/mob/clothing/suits/armor.dmi' @@ -697,7 +697,7 @@ /obj/item/clothing/suit/hooded/berserker/Initialize(mapload) . = ..() AddComponent(/datum/component/anti_magic, ALL, inventory_flags = ITEM_SLOT_OCLOTHING) - AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/clothing/suit/hooded/cloak/drake, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered") + AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/drake_remains, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered") allowed = GLOB.mining_suit_allowed #define MAX_BERSERK_CHARGE 100 @@ -710,8 +710,8 @@ name = "berserker helmet" desc = "This burdensome helmet seems to possess some kind of dark force within; howling in rage, hungry for carnage. \ The self-sealing stem bolts that allowed this helmet to be spaceworthy have long since corroded. However, the entity \ - sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left within drake armor. \ - Feeding it seems to empower a suit piece, though turns the drake armor back to lifeless ash." + sealed within the suit seems to hunger for the fleeting lifeforce found in the remains left in the remains of drakes. \ + Feeding it drake remains seems to empower a suit piece, though turns the remains back to lifeless ash." icon_state = "berserker" icon = 'icons/obj/clothing/head/helmet.dmi' worn_icon = 'icons/mob/clothing/head/helmet.dmi' @@ -732,7 +732,7 @@ /obj/item/clothing/head/hooded/berserker/Initialize(mapload) . = ..() ADD_TRAIT(src, TRAIT_NODROP, LOCKED_HELMET_TRAIT) - AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/clothing/suit/hooded/cloak/drake, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered") + AddComponent(/datum/component/armor_plate, maxamount = 1, upgrade_item = /obj/item/drake_remains, armor_mod = /datum/armor/drake_empowerment, upgrade_prefix = "empowered") /obj/item/clothing/head/hooded/berserker/examine() . = ..() @@ -800,6 +800,16 @@ #undef CHARGE_DRAINED_PER_SECOND #undef BERSERK_ATTACK_SPEED_MODIFIER +/obj/item/drake_remains + name = "drake remains" + desc = "The gathered remains of a drake. It still crackles with heat, and smells distinctly of brimstone." + icon = 'icons/obj/clothing/head/helmet.dmi' + icon_state = "dragon" + +/obj/item/drake_remains/Initialize(mapload) + . = ..() + particles = new /particles/bonfire() + /obj/item/clothing/glasses/godeye name = "eye of god" desc = "A strange eye, said to have been torn from an omniscient creature that used to roam the wastes." From b663fbff224eaa46f01988f8056c1a0516a1ca62 Mon Sep 17 00:00:00 2001 From: Afevis Date: Thu, 6 Jun 2024 00:54:32 -0400 Subject: [PATCH 22/81] Syndicate AI fixes (#83317) --- code/__HELPERS/mobs.dm | 11 ++++++++--- code/datums/wires/robot.dm | 5 +++-- code/game/machinery/computer/law.dm | 2 +- code/modules/antagonists/traitor/datum_traitor.dm | 2 +- 4 files changed, 13 insertions(+), 7 deletions(-) diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm index eb7fa2c3aa36b..5237132e4b10e 100644 --- a/code/__HELPERS/mobs.dm +++ b/code/__HELPERS/mobs.dm @@ -474,13 +474,18 @@ GLOBAL_LIST_INIT(skin_tone_names, list( . += borg //Returns a list of AI's -/proc/active_ais(check_mind=FALSE, z = null) +/proc/active_ais(check_mind=FALSE, z = null, skip_syndicate, only_syndicate) . = list() for(var/mob/living/silicon/ai/ai as anything in GLOB.ai_list) if(ai.stat == DEAD) continue if(ai.control_disabled) continue + var/syndie_ai = istype(ai, /mob/living/silicon/ai/weak_syndie) + if(skip_syndicate && syndie_ai) + continue + if(only_syndicate && !syndie_ai) + continue if(check_mind) if(!ai.mind) continue @@ -507,8 +512,8 @@ GLOBAL_LIST_INIT(skin_tone_names, list( . = pick(borgs) return . -/proc/select_active_ai(mob/user, z = null) - var/list/ais = active_ais(FALSE, z) +/proc/select_active_ai(mob/user, z = null, skip_syndicate, only_syndicate) + var/list/ais = active_ais(FALSE, z, skip_syndicate, only_syndicate) if(ais.len) if(user) . = input(user,"AI signals detected:", "AI Selection", ais[1]) in sort_list(ais) diff --git a/code/datums/wires/robot.dm b/code/datums/wires/robot.dm index cf8d9b238867f..2a45b8e2b3d27 100644 --- a/code/datums/wires/robot.dm +++ b/code/datums/wires/robot.dm @@ -35,10 +35,11 @@ if(WIRE_AI) // Pulse to pick a new AI. if(!R.emagged) var/new_ai + var/is_a_syndi_borg = (ROLE_SYNDICATE in R.faction) if(user) - new_ai = select_active_ai(user, R.z) + new_ai = select_active_ai(user, R.z, !is_a_syndi_borg, is_a_syndi_borg) else - new_ai = select_active_ai(R, R.z) + new_ai = select_active_ai(R, R.z, !is_a_syndi_borg, is_a_syndi_borg) R.notify_ai(AI_NOTIFICATION_CYBORG_DISCONNECTED) if(new_ai && (new_ai != R.connected_ai)) R.set_connected_ai(new_ai) diff --git a/code/game/machinery/computer/law.dm b/code/game/machinery/computer/law.dm index 816177f9f0edd..383a980a64da0 100644 --- a/code/game/machinery/computer/law.dm +++ b/code/game/machinery/computer/law.dm @@ -48,7 +48,7 @@ return INITIALIZE_HINT_QDEL /obj/machinery/computer/upload/ai/interact(mob/user) - current = select_active_ai(user, z) + current = select_active_ai(user, z, TRUE) if (!current) to_chat(user, span_alert("No active AIs detected!")) diff --git a/code/modules/antagonists/traitor/datum_traitor.dm b/code/modules/antagonists/traitor/datum_traitor.dm index d784175d62b6e..aba8c279456df 100644 --- a/code/modules/antagonists/traitor/datum_traitor.dm +++ b/code/modules/antagonists/traitor/datum_traitor.dm @@ -250,7 +250,7 @@ /datum/antagonist/traitor/proc/forge_single_generic_objective() if(prob(KILL_PROB)) - var/list/active_ais = active_ais() + var/list/active_ais = active_ais(skip_syndicate = TRUE) if(active_ais.len && prob(DESTROY_AI_PROB(GLOB.joined_player_list.len))) var/datum/objective/destroy/destroy_objective = new() destroy_objective.owner = owner From 21c39860ab7b7505b4130f80a89ed25350bc7ab1 Mon Sep 17 00:00:00 2001 From: Whoneedspacee Date: Thu, 6 Jun 2024 00:55:15 -0400 Subject: [PATCH 23/81] Fixes Bubblegums Melee Cooldown (#83694) ## About The Pull Request Fixes #63886 (The previous pr to fix added melee cooldown time but that only applies after the ability ends) Adds a cooldown to melee before the bubblegum starts charging so it won't melee while charging. ## Why It's Good For The Game This is how Bubblegum's charge worked before mob abilities but at the time of this abilities creation melee cooldowns were not apart of mob abilities and did not work properly together. ## Changelog :cl: fix: Bubblegum can no longer melee you while using his charge abilities. /:cl: --- code/datums/actions/mobs/charge.dm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/code/datums/actions/mobs/charge.dm b/code/datums/actions/mobs/charge.dm index 9aee4cd83456a..43fcbd57f69ba 100644 --- a/code/datums/actions/mobs/charge.dm +++ b/code/datums/actions/mobs/charge.dm @@ -23,6 +23,8 @@ /datum/action/cooldown/mob_cooldown/charge/Activate(atom/target_atom) disable_cooldown_actions() + // No charging and meleeing (overridded by StartCooldown after charge ends) + next_melee_use_time = world.time + 100 SECONDS charge_sequence(owner, target_atom, charge_delay, charge_past) StartCooldown() enable_cooldown_actions() From adb9c966ca27046d55fbda457a7e6e0159d39818 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:55:27 +1200 Subject: [PATCH 24/81] Automatic changelog for PR #83700 [ci skip] --- html/changelogs/AutoChangeLog-pr-83700.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83700.yml diff --git a/html/changelogs/AutoChangeLog-pr-83700.yml b/html/changelogs/AutoChangeLog-pr-83700.yml new file mode 100644 index 0000000000000..ec2937bc0be32 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83700.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "Drake empowerment for berserker armor now uses valuable drake remains, made from ashdrake hides and bones." + - rscadd: "Drake armor is made use drake remains to construct. (This is a net neutral to the previous recipe)" \ No newline at end of file From 2bd002d5edf8b890e9f8c02eb07934050594e69a Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 16:55:46 +1200 Subject: [PATCH 25/81] Automatic changelog for PR #83317 [ci skip] --- html/changelogs/AutoChangeLog-pr-83317.yml | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83317.yml diff --git a/html/changelogs/AutoChangeLog-pr-83317.yml b/html/changelogs/AutoChangeLog-pr-83317.yml new file mode 100644 index 0000000000000..788928563d40c --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83317.yml @@ -0,0 +1,7 @@ +author: "ShizCalev" +delete-after: True +changes: + - bugfix: "Syndicate AI can no longer be selected via the station law upload console." + - bugfix: "Non-syndicate borgs can no longer accidentally be slaved to syndicate AI by pulsing their AI wires." + - bugfix: "Syndicate borgs can no longer be slaved to the station AI by pulsing their AI wires." + - bugfix: "Syndicate operatives onboard the station can no longer end up with an objective to destroy their own syndicate AI." \ No newline at end of file From f0f3459d79a32a296e615b603355237d7d46ecb5 Mon Sep 17 00:00:00 2001 From: Wayland-Smithy <64715958+Wayland-Smithy@users.noreply.github.com> Date: Wed, 5 Jun 2024 21:56:27 -0700 Subject: [PATCH 26/81] Fix Pre-Loaded Syndicate AI appearing in PDA messenger (#83692) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## About The Pull Request What it says on the tin. I experienced this one personally when a lawyer (ofc) called out my existence mere moments after being activated through no fault of my own 🧂 ## Why It's Good For The Game Fix good. ## Changelog :cl: fix: Pre-Loaded Syndicate Intellicard AI's no longer appear in PDA messenger. /:cl: --- code/game/objects/items/devices/aicard_evil.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/game/objects/items/devices/aicard_evil.dm b/code/game/objects/items/devices/aicard_evil.dm index 8aaa9f0311116..3e8c56ce940fd 100644 --- a/code/game/objects/items/devices/aicard_evil.dm +++ b/code/game/objects/items/devices/aicard_evil.dm @@ -62,6 +62,11 @@ // Make it look evil!!! new_ai.hologram_appearance = mutable_appearance('icons/mob/silicon/ai.dmi',"xeno_queen") //good enough new_ai.icon_state = resolve_ai_icon("hades") + // Hide PDA from messenger + var/datum/computer_file/program/messenger/msg = locate() in new_ai.modularInterface.stored_files + if(msg) + msg.invisible = TRUE + // Transfer the AI from the core we created into the card, then delete the core capture_ai(new_ai, user) var/obj/structure/ai_core/deactivated/detritus = locate() in get_turf(src) From 0d679c045f831c65a449b5848d2d26a53b0a35af Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:03:47 +1200 Subject: [PATCH 27/81] Automatic changelog for PR #83694 [ci skip] --- html/changelogs/AutoChangeLog-pr-83694.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83694.yml diff --git a/html/changelogs/AutoChangeLog-pr-83694.yml b/html/changelogs/AutoChangeLog-pr-83694.yml new file mode 100644 index 0000000000000..a82a580ef8e23 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83694.yml @@ -0,0 +1,4 @@ +author: "Whoneedspacee" +delete-after: True +changes: + - bugfix: "Bubblegum can no longer melee you while using his charge abilities." \ No newline at end of file From c5f1367a494e8e96a8218c66eeb9bf79152c2243 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 17:04:11 +1200 Subject: [PATCH 28/81] Automatic changelog for PR #83692 [ci skip] --- html/changelogs/AutoChangeLog-pr-83692.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83692.yml diff --git a/html/changelogs/AutoChangeLog-pr-83692.yml b/html/changelogs/AutoChangeLog-pr-83692.yml new file mode 100644 index 0000000000000..4dfa490dc3e2d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83692.yml @@ -0,0 +1,4 @@ +author: "Wayland-Smithy" +delete-after: True +changes: + - bugfix: "Pre-Loaded Syndicate Intellicard AI's no longer appear in PDA messenger." \ No newline at end of file From 4cc434510a12bb67157d316dfa7d62e933bf8b9a Mon Sep 17 00:00:00 2001 From: Pickle-Coding <58013024+Pickle-Coding@users.noreply.github.com> Date: Thu, 6 Jun 2024 10:10:24 +0100 Subject: [PATCH 29/81] Fixes brig cell timer adjusting reducing the time by the time served for every operation. The maximum allowed time is based on the timer and not time served. (#83520) ## About The Pull Request Fixes brig cell timer reducing the time by the time served for every operation. This caused increasing time on timers that were run sufficiently long enough to actually decrease time instead, which was dumb. Also sets the max timer for the brig cell to be based on the timer and not account for time served. ## Why It's Good For The Game Makes the buttons work as advertised. ## Changelog :cl: fix: Fixes the brig cell timer adjustment not working correctly on live timers. /:cl: --- code/game/machinery/doors/brigdoors.dm | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm index 0ddbd58a5c8c8..34a161acac1b3 100644 --- a/code/game/machinery/doors/brigdoors.dm +++ b/code/game/machinery/doors/brigdoors.dm @@ -17,12 +17,14 @@ text_color = "#F44" header_text_color = "#F88" - var/id = null // id of linked machinery/lockers - + /// ID of linked machinery/lockers. + var/id = null + /// The time at which the timer started. var/activation_time = 0 + /// The time offset from the activation time before releasing. var/timer_duration = 0 - - var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing + /// Is the timer on? + var/timing = FALSE ///List of weakrefs to nearby doors var/list/doors = list() ///List of weakrefs to nearby flashers @@ -138,7 +140,7 @@ sec_radio.talk_into(src, "Timer has expired. Releasing prisoner.", FREQ_SECURITY) timing = FALSE - activation_time = null + activation_time = 0 set_timer(0) end_processing() @@ -168,12 +170,12 @@ /** * Return time left. * Arguments: - * * seconds - return time in seconds it TRUE, else deciseconds. + * * seconds - Return the time in seconds if TRUE, else deciseconds. */ /obj/machinery/status_display/door_timer/proc/time_left(seconds = FALSE) - . = max(0, timer_duration - (activation_time ? world.time - activation_time : 0)) + . = max(0, timer_duration + activation_time - world.time) if(seconds) - . /= 10 + . /= (1 SECONDS) /** * Set the timer. Does NOT automatically start counting down, but does update the display. @@ -184,7 +186,7 @@ * value - time in deciseconds to set the timer for. */ /obj/machinery/status_display/door_timer/proc/set_timer(value) - var/new_time = clamp(value, 0, MAX_TIMER) + var/new_time = clamp(value, 0, MAX_TIMER + world.time - activation_time) . = new_time == timer_duration //return 1 on no change timer_duration = new_time update_content() @@ -229,7 +231,7 @@ if("time") var/value = text2num(params["adjust"]) if(value) - . = set_timer(time_left() + value) + . = set_timer(timer_duration + value) user.investigate_log("modified the timer by [value/10] seconds for cell [id], currently [time_left(seconds = TRUE)]", INVESTIGATE_RECORDS) user.log_message("modified the timer by [value/10] seconds for cell [id], currently [time_left(seconds = TRUE)]", LOG_ATTACK) if("start") From 83e4c65aa24178a83b859a24e68bd743b5ecb9f4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:10:42 +1200 Subject: [PATCH 30/81] Automatic changelog for PR #83520 [ci skip] --- html/changelogs/AutoChangeLog-pr-83520.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83520.yml diff --git a/html/changelogs/AutoChangeLog-pr-83520.yml b/html/changelogs/AutoChangeLog-pr-83520.yml new file mode 100644 index 0000000000000..1d05b20a7fa22 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83520.yml @@ -0,0 +1,4 @@ +author: "Pickle-Coding" +delete-after: True +changes: + - bugfix: "Fixes the brig cell timer adjustment not working correctly on live timers." \ No newline at end of file From 90870586943994a8d1c8779f14ed626983fc13f5 Mon Sep 17 00:00:00 2001 From: Fazzie <84548101+EuSouAFazer@users.noreply.github.com> Date: Thu, 6 Jun 2024 06:13:15 -0300 Subject: [PATCH 31/81] Makes the Clown Stamp give out clown cells (#83585) ## About The Pull Request This PR makes it so swabbing the clown's stamp also gives clown cells for Cytology. ## Why It's Good For The Game Right now for these cell lines you either need to swab the clown's shoes, clothes or mask - items that many clowns won't be too happy to part with, even if for a few seconds. Furthermore it means you only get 3 tries to get the cell line you want, alongside having a chance of having all of the cell lines rather than just two (making the process a lot more harder if i does happen). Letting the stamp give out cells both makes getting a single petri dish faster ("Clown give me the stamp" "K") but also means if you're going for one specific cell line you have more chances to get it, making the whole process of getting experimental clowns faster and more reliable overall. ## Changelog :cl: qol: Swabbing the clown's stamp also gives clown cells. :cl: --- code/modules/paperwork/stamps.dm | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/code/modules/paperwork/stamps.dm b/code/modules/paperwork/stamps.dm index 1a0ce1dc37b80..1eae74d242cef 100644 --- a/code/modules/paperwork/stamps.dm +++ b/code/modules/paperwork/stamps.dm @@ -88,6 +88,11 @@ icon_state = "stamp-clown" dye_color = DYE_CLOWN +/obj/item/stamp/clown/Initialize(mapload) + . = ..() + + AddElement(/datum/element/swabable, CELL_LINE_TABLE_CLOWN, CELL_VIRUS_TABLE_GENERIC, rand(2,3), 0) + /obj/item/stamp/mime name = "mime's rubber stamp" icon_state = "stamp-mime" From 7a9e37bb7e3226b4a8897b62d6fd60b04d3b072b Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Thu, 6 Jun 2024 14:43:52 +0530 Subject: [PATCH 32/81] Auto Lathe Runtime Fixes (#83587) ## About The Pull Request - Fixes #83581 Using an autolathe in any area without an APC causes this runtime ![Screenshot (417)](https://github.com/tgstation/tgstation/assets/110812394/bb10adbc-3702-4255-b93b-ca722cb8d67c) Also caught another bug which causes the UI to hang if the lathe runs out of material mid printing ## Changelog :cl: fix: autolathes don't hang when printing items in areas without apc or if it runs out of materials mid printing /:cl: --------- Co-authored-by: san7890 --- code/game/machinery/autolathe.dm | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm index 9b33a901d9ebe..3ad109b30e544 100644 --- a/code/game/machinery/autolathe.dm +++ b/code/game/machinery/autolathe.dm @@ -329,17 +329,21 @@ if(!directly_use_energy(charge_per_item)) // provide the wait time until lathe is ready var/area/my_area = get_area(src) var/obj/machinery/power/apc/my_apc = my_area.apc - var/charging_wait = my_apc.time_to_charge(charge_per_item) - if(!isnull(charging_wait)) - say("Unable to continue production, APC overload. Wait [DisplayTimeText(charging_wait, round_seconds_to = 1)] and try again.") + if(!QDELETED(my_apc)) + var/charging_wait = my_apc.time_to_charge(charge_per_item) + if(!isnull(charging_wait)) + say("Unable to continue production, APC overload. Wait [DisplayTimeText(charging_wait, round_seconds_to = 1)] and try again.") + else + say("Unable to continue production, power grid overload.") else - say("Unable to continue production, power grid overload.") + say("Unable to continue production, no APC in area.") finalize_build() return var/is_stack = ispath(design.build_path, /obj/item/stack) if(!materials.has_materials(materials_needed, material_cost_coefficient, is_stack ? items_remaining : 1)) say("Unable to continue production, missing materials.") + finalize_build() return materials.use_materials(materials_needed, material_cost_coefficient, is_stack ? items_remaining : 1) From 36db5b9557a01d827961e0f377ac7f4e9bc1a3c0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:13:58 +1200 Subject: [PATCH 33/81] Automatic changelog for PR #83585 [ci skip] --- html/changelogs/AutoChangeLog-pr-83585.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83585.yml diff --git a/html/changelogs/AutoChangeLog-pr-83585.yml b/html/changelogs/AutoChangeLog-pr-83585.yml new file mode 100644 index 0000000000000..763c4c4689b44 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83585.yml @@ -0,0 +1,4 @@ +author: "EuSouAFazer" +delete-after: True +changes: + - qol: "Swabbing the clown's stamp also gives clown cells.\n:cl:" \ No newline at end of file From 5f07f55142a6ec83a29405b60faa5bb77677d0bf Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:14:21 +1200 Subject: [PATCH 34/81] Automatic changelog for PR #83587 [ci skip] --- html/changelogs/AutoChangeLog-pr-83587.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83587.yml diff --git a/html/changelogs/AutoChangeLog-pr-83587.yml b/html/changelogs/AutoChangeLog-pr-83587.yml new file mode 100644 index 0000000000000..22d1ee5b2b99d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83587.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "autolathes don't hang when printing items in areas without apc or if it runs out of materials mid printing" \ No newline at end of file From ac1afe332d6f6ec12ed06c10acb380db2c64571b Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:15:24 +1000 Subject: [PATCH 35/81] Fixes some coffee inconsistencies (#83607) ## About The Pull Request Coffee varieties now cause jittering when overdosing on the chemical, and not as part of the baseline effects of the coffee. This is consistent with the base form of coffee. Pumpkin lattes actually function like the latte varieties rather than doing nothing at all. ## Why It's Good For The Game I think some of these were oversights, or simply not well thought through decisions. I particularly felt it was ridiculous that people were jittery from drinking a latte. Did the person who added this ever actually drink coffee? ## Changelog :cl: qol: Coffee types are overall more consistent, causing jittering only from the overdose effect. fix: Pumpkin lattes will actually work like coffee. /:cl: --- .../reagents/drinks/drink_reagents.dm | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index f753f2f1c325c..ec0c316c45825 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -358,34 +358,42 @@ description = "Coffee and ice, refreshing and cool." color = "#102838" // rgb: 16, 40, 56 nutriment_factor = 0 + overdose_threshold = 80 taste_description = "bitter coldness" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED metabolized_traits = list(TRAIT_STIMULATED) +/datum/reagent/consumable/icecoffee/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) + /datum/reagent/consumable/icecoffee/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-40 * REM * seconds_per_tick) affected_mob.adjust_bodytemperature(-5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) - affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) /datum/reagent/consumable/hot_ice_coffee name = "Hot Ice Coffee" description = "Coffee with pulsing ice shards" color = "#102838" // rgb: 16, 40, 56 nutriment_factor = 0 + overdose_threshold = 80 taste_description = "bitter coldness and a hint of smoke" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED metabolized_traits = list(TRAIT_STIMULATED) +/datum/reagent/consumable/hot_ice_coffee/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) + /datum/reagent/consumable/hot_ice_coffee/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) affected_mob.AdjustSleeping(-60 * REM * seconds_per_tick) affected_mob.adjust_bodytemperature(-7 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, affected_mob.get_body_temp_normal()) - affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) if(affected_mob.adjustToxLoss(1 * REM * seconds_per_tick, updating_health = FALSE, required_biotype = affected_biotype)) return UPDATE_MOB_HEALTH @@ -701,12 +709,17 @@ name = "Soy Latte" description = "A nice and tasty beverage while you are reading your hippie books." color = "#cc6404" // rgb: 204,100,4 + overdose_threshold = 80 quality = DRINK_NICE taste_description = "creamy coffee" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED glass_price = DRINK_PRICE_EASY metabolized_traits = list(TRAIT_STIMULATED) +/datum/reagent/consumable/soy_latte/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) + /datum/reagent/consumable/soy_latte/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) @@ -714,7 +727,6 @@ var/need_mob_update need_mob_update = affected_mob.SetSleeping(0) affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) - affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) need_mob_update += affected_mob.heal_bodypart_damage(brute = 1 * REM * seconds_per_tick, burn = 0, updating_health = FALSE) if(need_mob_update) @@ -724,12 +736,17 @@ name = "Cafe Latte" description = "A nice, strong and tasty beverage while you are reading." color = "#cc6404" // rgb: 204,100,4 + overdose_threshold = 80 quality = DRINK_NICE taste_description = "bitter cream" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED glass_price = DRINK_PRICE_EASY metabolized_traits = list(TRAIT_STIMULATED) +/datum/reagent/consumable/cafe_latte/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) + /datum/reagent/consumable/cafe_latte/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) . = ..() affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) @@ -737,7 +754,6 @@ var/need_mob_update need_mob_update = affected_mob.SetSleeping(0) affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) - affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) need_mob_update += affected_mob.heal_bodypart_damage(brute = 1 * REM * seconds_per_tick, burn = 0, updating_health = FALSE) if(need_mob_update) @@ -851,12 +867,29 @@ name = "Pumpkin Latte" description = "A mix of pumpkin juice and coffee." color = "#F4A460" + overdose_threshold = 80 quality = DRINK_VERYGOOD nutriment_factor = 3 taste_description = "creamy pumpkin" chemical_flags = REAGENT_CAN_BE_SYNTHESIZED metabolized_traits = list(TRAIT_STIMULATED) +/datum/reagent/consumable/pumpkin_latte/overdose_process(mob/living/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.set_jitter_if_lower(10 SECONDS * REM * seconds_per_tick) + +/datum/reagent/consumable/pumpkin_latte/on_mob_life(mob/living/carbon/affected_mob, seconds_per_tick, times_fired) + . = ..() + affected_mob.adjust_dizzy(-10 SECONDS * REM * seconds_per_tick) + affected_mob.adjust_drowsiness(-6 SECONDS * REM * seconds_per_tick) + var/need_mob_update + need_mob_update = affected_mob.SetSleeping(0) + affected_mob.adjust_bodytemperature(5 * REM * TEMPERATURE_DAMAGE_COEFFICIENT * seconds_per_tick, 0, affected_mob.get_body_temp_normal()) + if(affected_mob.getBruteLoss() && SPT_PROB(10, seconds_per_tick)) + need_mob_update += affected_mob.heal_bodypart_damage(brute = 1 * REM * seconds_per_tick, burn = 0, updating_health = FALSE) + if(need_mob_update) + return UPDATE_MOB_HEALTH + /datum/reagent/consumable/gibbfloats name = "Gibb Floats" description = "Ice cream on top of a Dr. Gibb glass." From 413dc66af129c5af2e15653ae4fa30b5475995f5 Mon Sep 17 00:00:00 2001 From: lessthanthree <83487515+lessthnthree@users.noreply.github.com> Date: Thu, 6 Jun 2024 02:17:04 -0700 Subject: [PATCH 36/81] Tram crossing signal logic fixes (#83610) ## About The Pull Request Minor fixes to the tram crossing signal logic. Reverts an earlier change I made to the subsystem, which resulted in the signals being wildly off in their timings on a regular basis. Adjusted the red length corresponding to the properly timed signals. Removed define for degraded yellow, as that's now simplified into a check at signal activation time. ## Why It's Good For The Game Tram crossing lights better reflect tram status, staying green when the tram is broken therefore safe to walk. Consistently turn red when tram approaching. ## Changelog :cl: LT3 fix: Fixed timing issue where tram crossing signals would be out of sync with the moving tram fix: Tram crossing signals consistently show green when safe, blue when broken fix: Tram crossing signals show red instead of yellow when degraded /:cl: --- code/__DEFINES/transport.dm | 7 +-- code/datums/components/energized.dm | 4 +- code/modules/transport/tram/tram_signals.dm | 62 +++++++-------------- 3 files changed, 25 insertions(+), 48 deletions(-) diff --git a/code/__DEFINES/transport.dm b/code/__DEFINES/transport.dm index 452ba28535492..09d4f39280a8d 100644 --- a/code/__DEFINES/transport.dm +++ b/code/__DEFINES/transport.dm @@ -99,12 +99,11 @@ DEFINE_BITFIELD(request_flags, list( #define XING_STATE_RED 2 #define XING_STATE_MALF 3 -#define AMBER_THRESHOLD_NORMAL 45 -#define RED_THRESHOLD_NORMAL 20 -#define AMBER_THRESHOLD_DEGRADED 30 -#define RED_THRESHOLD_DEGRADED 15 +#define XING_THRESHOLD_AMBER 45 +#define XING_THRESHOLD_RED 27 #define DEFAULT_TRAM_LENGTH 10 +#define DEFAULT_TRAM_MIDPOINT 5 // Tram machinery subtype #define TRANSPORT_SYSTEM_NORMAL 0 diff --git a/code/datums/components/energized.dm b/code/datums/components/energized.dm index eb45ee66e2b12..255970bfd311c 100644 --- a/code/datums/components/energized.dm +++ b/code/datums/components/energized.dm @@ -95,7 +95,7 @@ tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 // How far away are we? negative if already passed. - var/approach_distance = tram_velocity_sign * (plate_pos - (tram_pos + (DEFAULT_TRAM_LENGTH * 0.5))) + var/approach_distance = tram_velocity_sign * (plate_pos - (tram_pos + DEFAULT_TRAM_MIDPOINT)) // Check if our victim is in the active path of the tram. if(!tram.controller_active) @@ -106,7 +106,7 @@ return FALSE if((tram.travel_direction & EAST) && outbound > tram.destination_platform.platform_code) return FALSE - if(approach_distance >= AMBER_THRESHOLD_DEGRADED) + if(approach_distance >= XING_THRESHOLD_AMBER) return FALSE // Finally the interesting part where they ACTUALLY get hit! diff --git a/code/modules/transport/tram/tram_signals.dm b/code/modules/transport/tram/tram_signals.dm index eb64866603043..db8aa17ddcb3e 100644 --- a/code/modules/transport/tram/tram_signals.dm +++ b/code/modules/transport/tram/tram_signals.dm @@ -17,7 +17,7 @@ interaction_flags_machine = INTERACT_MACHINE_OPEN circuit = /obj/item/circuitboard/machine/crossing_signal // pointless if it only takes 2 seconds to cross but updates every 2 seconds - subsystem_type = /datum/controller/subsystem/processing/fastprocess + subsystem_type = /datum/controller/subsystem/processing/transport light_color = LIGHT_COLOR_BABY_BLUE /// green, amber, or red for tram, blue if it's emag, tram missing, etc. var/signal_state = XING_STATE_MALF @@ -40,8 +40,8 @@ * Red: decent chance of getting hit, but if you're quick it's a decent gamble. * Amber: slow people may be in danger. */ - var/amber_distance_threshold = AMBER_THRESHOLD_NORMAL - var/red_distance_threshold = RED_THRESHOLD_NORMAL + var/amber_distance_threshold = XING_THRESHOLD_AMBER + var/red_distance_threshold = XING_THRESHOLD_RED /** Crossing signal subtypes * @@ -203,34 +203,18 @@ sensor_ref = null if(operating_status < TRANSPORT_REMOTE_WARNING) operating_status = TRANSPORT_REMOTE_WARNING - degraded_response() update_appearance() /obj/machinery/transport/crossing_signal/proc/wake_sensor() - if(operating_status > TRANSPORT_REMOTE_WARNING) - degraded_response() - return - var/obj/machinery/transport/guideway_sensor/linked_sensor = sensor_ref?.resolve() if(isnull(linked_sensor)) operating_status = TRANSPORT_REMOTE_WARNING - degraded_response() else if(linked_sensor.trigger_sensor()) operating_status = TRANSPORT_SYSTEM_NORMAL - normal_response() else operating_status = TRANSPORT_REMOTE_WARNING - degraded_response() - -/obj/machinery/transport/crossing_signal/proc/normal_response() - amber_distance_threshold = AMBER_THRESHOLD_NORMAL - red_distance_threshold = RED_THRESHOLD_NORMAL - -/obj/machinery/transport/crossing_signal/proc/degraded_response() - amber_distance_threshold = AMBER_THRESHOLD_DEGRADED - red_distance_threshold = RED_THRESHOLD_DEGRADED /obj/machinery/transport/crossing_signal/proc/clear_uplink() inbound = null @@ -316,20 +300,23 @@ end_processing() /obj/machinery/transport/crossing_signal/process() - + // idle aspect is green or blue depending on the signal status + // degraded signal operating conditions of any type show blue + var/idle_aspect = operating_status == TRANSPORT_SYSTEM_NORMAL ? XING_STATE_GREEN : XING_STATE_MALF var/datum/transport_controller/linear/tram/tram = transport_ref?.resolve() - // Check for stopped states. - if(!tram || !tram.controller_operational || !is_operational || !inbound || !outbound) + // Check for stopped states. Will kill the process since tram starting up will restart process. + if(!tram || !tram.controller_operational || !tram.controller_active || !is_operational || !inbound || !outbound) // Tram missing, we lost power, or something isn't right - // Throw the error message (blue) - set_signal_state(XING_STATE_MALF, force = !is_operational) + // Set idle and stop processing, since the tram won't be moving + set_signal_state(idle_aspect, force = !is_operational) return PROCESS_KILL var/obj/structure/transport/linear/tram_part = tram.return_closest_platform_to(src) + // The structure is gone, so we're done here. if(QDELETED(tram_part)) - set_signal_state(XING_STATE_MALF, force = !is_operational) + set_signal_state(idle_aspect, force = !is_operational) return PROCESS_KILL // Everything will be based on position and travel direction @@ -347,41 +334,32 @@ tram_velocity_sign = tram.travel_direction & EAST ? 1 : -1 // How far away are we? negative if already passed. - var/approach_distance = tram_velocity_sign * (signal_pos - (tram_pos + (DEFAULT_TRAM_LENGTH * 0.5))) - - // Check for stopped state. - // Will kill the process since tram starting up will restart process. - if(!tram.controller_active) - set_signal_state(XING_STATE_GREEN) - return PROCESS_KILL + var/approach_distance = tram_velocity_sign * (signal_pos - (tram_pos + DEFAULT_TRAM_MIDPOINT)) // Check if tram is driving away from us. - if(approach_distance < 0) + if(approach_distance < -abs(DEFAULT_TRAM_MIDPOINT)) // driving away. Green. In fact, in order to reverse, it'll have to stop, so let's go ahead and kill. - set_signal_state(XING_STATE_GREEN) + set_signal_state(idle_aspect) return PROCESS_KILL // Check the tram's terminus station. // INBOUND 1 < 2 < 3 // OUTBOUND 1 > 2 > 3 if(tram.travel_direction & WEST && inbound < tram.destination_platform.platform_code) - set_signal_state(XING_STATE_GREEN) + set_signal_state(idle_aspect) return PROCESS_KILL if(tram.travel_direction & EAST && outbound > tram.destination_platform.platform_code) - set_signal_state(XING_STATE_GREEN) + set_signal_state(idle_aspect) return PROCESS_KILL // Finally the interesting part where it's ACTUALLY approaching if(approach_distance <= red_distance_threshold) - if(operating_status != TRANSPORT_SYSTEM_NORMAL) - set_signal_state(XING_STATE_MALF) - else - set_signal_state(XING_STATE_RED) + set_signal_state(XING_STATE_RED) return - if(approach_distance <= amber_distance_threshold) + if(approach_distance <= amber_distance_threshold && operating_status == TRANSPORT_SYSTEM_NORMAL) set_signal_state(XING_STATE_AMBER) return - set_signal_state(XING_STATE_GREEN) + set_signal_state(idle_aspect) /** * Set the signal state and update appearance. From f6569b4a1410f55dfd01aba771e3dda7cd03faa5 Mon Sep 17 00:00:00 2001 From: Erol509 <81807356+Erol509@users.noreply.github.com> Date: Thu, 6 Jun 2024 11:17:34 +0200 Subject: [PATCH 37/81] Little QOL change for AI cyborg display power (#83625) ## About The Pull Request Slightly changes the formating from ugly 1e777 numbers to neat Jules format. ## FROM ![image](https://github.com/tgstation/tgstation/assets/81807356/755d4e2f-feed-4aa5-afed-e3f6f410910c) ## TO ![image](https://github.com/tgstation/tgstation/assets/81807356/1e276476-afa7-46f2-a5a2-ef2a245a4fa2) ## Why It's Good For The Game Much prettier stat panel and easier to read ## Changelog :cl: qol: Cyborgs on AI statpanel now have jules energy format. /:cl: --- code/modules/mob/living/silicon/ai/ai.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/modules/mob/living/silicon/ai/ai.dm b/code/modules/mob/living/silicon/ai/ai.dm index dfd9afeec4516..8354ff0447461 100644 --- a/code/modules/mob/living/silicon/ai/ai.dm +++ b/code/modules/mob/living/silicon/ai/ai.dm @@ -42,7 +42,7 @@ var/obj/machinery/ai_voicechanger/ai_voicechanger = null // reference to machine that holds the voicechanger var/malfhacking = FALSE // More or less a copy of the above var, so that malf AIs can hack and still get new cyborgs -- NeoFite /// List of hacked APCs - var/list/hacked_apcs = list() + var/list/hacked_apcs = list() var/malf_cooldown = 0 //Cooldown var for malf modules, stores a worldtime + cooldown var/obj/machinery/power/apc/malfhack @@ -333,7 +333,7 @@ else if(!connected_robot.cell || connected_robot.cell.charge <= 0) robot_status = "DEPOWERED" //Name, Health, Battery, Model, Area, and Status! Everything an AI wants to know about its borgies! - . += "[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[connected_robot.cell.charge]/[connected_robot.cell.maxcharge]" : "Empty"] | \ + . += "[connected_robot.name] | S.Integrity: [connected_robot.health]% | Cell: [connected_robot.cell ? "[display_energy(connected_robot.cell.charge)]/[display_energy(connected_robot.cell.maxcharge)]" : "Empty"] | \ Model: [connected_robot.designation] | Loc: [get_area_name(connected_robot, TRUE)] | Status: [robot_status]" . += "AI shell beacons detected: [LAZYLEN(GLOB.available_ai_shells)]" //Count of total AI shells From 8d69edbbf38c89a72fbc9f38c39e8c3874379ebb Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:21:45 +1200 Subject: [PATCH 38/81] Automatic changelog for PR #83607 [ci skip] --- html/changelogs/AutoChangeLog-pr-83607.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83607.yml diff --git a/html/changelogs/AutoChangeLog-pr-83607.yml b/html/changelogs/AutoChangeLog-pr-83607.yml new file mode 100644 index 0000000000000..157da5e87b1b0 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83607.yml @@ -0,0 +1,5 @@ +author: "necromanceranne" +delete-after: True +changes: + - qol: "Coffee types are overall more consistent, causing jittering only from the overdose effect." + - bugfix: "Pumpkin lattes will actually work like coffee." \ No newline at end of file From 3292170ed2c1021cd660bebc5d8a972896698d80 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:22:08 +1200 Subject: [PATCH 39/81] Automatic changelog for PR #83610 [ci skip] --- html/changelogs/AutoChangeLog-pr-83610.yml | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83610.yml diff --git a/html/changelogs/AutoChangeLog-pr-83610.yml b/html/changelogs/AutoChangeLog-pr-83610.yml new file mode 100644 index 0000000000000..40b34b9cff514 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83610.yml @@ -0,0 +1,6 @@ +author: "LT3" +delete-after: True +changes: + - bugfix: "Fixed timing issue where tram crossing signals would be out of sync with the moving tram" + - bugfix: "Tram crossing signals consistently show green when safe, blue when broken" + - bugfix: "Tram crossing signals show red instead of yellow when degraded" \ No newline at end of file From 511211dec84bf95365c7a8b2d02565efb1241728 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:22:25 +1200 Subject: [PATCH 40/81] Automatic changelog for PR #83625 [ci skip] --- html/changelogs/AutoChangeLog-pr-83625.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83625.yml diff --git a/html/changelogs/AutoChangeLog-pr-83625.yml b/html/changelogs/AutoChangeLog-pr-83625.yml new file mode 100644 index 0000000000000..a1a93ffa31f71 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83625.yml @@ -0,0 +1,4 @@ +author: "Erol509" +delete-after: True +changes: + - qol: "Cyborgs on AI statpanel now have jules energy format." \ No newline at end of file From 8a2bfdf38a8bdd33049f5248a43b8951b83463ee Mon Sep 17 00:00:00 2001 From: grungussuss <96586172+Sadboysuss@users.noreply.github.com> Date: Thu, 6 Jun 2024 12:38:26 +0300 Subject: [PATCH 41/81] Fixes curator whip disarming even after getting parried (#83543) ## About The Pull Request what the title says ### Test: https://github.com/tgstation/tgstation/assets/96586172/e68323e0-2f44-42db-9752-4c4b5d5c4a3c ## Changelog :cl: fix: curator whip will no longer disarm when parried /:cl: --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Co-authored-by: Jacquerel --- code/_onclick/item_attack.dm | 5 +++-- code/game/objects/items/melee/misc.dm | 6 ++++-- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm index 95622a7c60a72..18e9fa12a660a 100644 --- a/code/_onclick/item_attack.dm +++ b/code/_onclick/item_attack.dm @@ -234,7 +234,8 @@ user.client.give_award(/datum/award/achievement/misc/selfouch, user) user.do_attack_animation(target_mob) - target_mob.attacked_by(src, user) + if(!target_mob.attacked_by(src, user)) + return TRUE SEND_SIGNAL(src, COMSIG_ITEM_POST_ATTACK, target_mob, user, params) @@ -318,7 +319,7 @@ SEND_SIGNAL(attacking_item, COMSIG_ITEM_ATTACK_ZONE, src, user, targeting) if(damage <= 0) - return FALSE + return TRUE if(ishuman(src) || client) // istype(src) is kinda bad, but it's to avoid spamming the blackbox SSblackbox.record_feedback("nested tally", "item_used_for_combat", 1, list("[attacking_item.force]", "[attacking_item.type]")) diff --git a/code/game/objects/items/melee/misc.dm b/code/game/objects/items/melee/misc.dm index b3d33cd99e984..01bbc9262d0af 100644 --- a/code/game/objects/items/melee/misc.dm +++ b/code/game/objects/items/melee/misc.dm @@ -330,9 +330,11 @@ attack_verb_simple = list("flog", "whip", "lash", "discipline") hitsound = 'sound/weapons/whip.ogg' -/obj/item/melee/curator_whip/afterattack(target, mob/user, proximity_flag) +/obj/item/melee/curator_whip/attack(mob/living/target, mob/living/user, params) . = ..() - if(ishuman(target) && proximity_flag) + if(.) + return + if(ishuman(target)) var/mob/living/carbon/human/human_target = target human_target.drop_all_held_items() human_target.visible_message(span_danger("[user] disarms [human_target]!"), span_userdanger("[user] disarmed you!")) From 768ba2efc12e5f32a67e7394b92d199c5acb884b Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:39:25 +1200 Subject: [PATCH 42/81] Automatic changelog for PR #83543 [ci skip] --- html/changelogs/AutoChangeLog-pr-83543.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83543.yml diff --git a/html/changelogs/AutoChangeLog-pr-83543.yml b/html/changelogs/AutoChangeLog-pr-83543.yml new file mode 100644 index 0000000000000..97fbae4260357 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83543.yml @@ -0,0 +1,4 @@ +author: "Sadboysuss" +delete-after: True +changes: + - bugfix: "curator whip will no longer disarm when parried" \ No newline at end of file From c4587bf2aff2c76f527e614d84cbb42363a12b17 Mon Sep 17 00:00:00 2001 From: githubuser4141 <61243846+githubuser4141@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:46:39 +1200 Subject: [PATCH 43/81] Centcom/Nukie mechs receive better innate armor but cannot be upgraded (#83580) ## About The Pull Request QoL for antag mechs: no longer are you expected to sit around station Robotics with a [materials] [inducer] [experiment scanner] to upgrade your antag mechs, they are now appropriately armoured out of the box! Unfortunately, this high end armour cannot accept third party upgrade modules. Also good because of incoming (hopefully) sprite upgrades, maulers should become more attractive to buy. Inspired by maplestation.. NOTE: WEB-EDITED! NOT TESTED! ## Why It's Good For The Game Antags like Centcom or Syndicates don't have no time to sit around in the station robotics bay trying to upgrade their mechs - and it's insane to expect them to do so. This is especially poor for newer players who aren't aware of mech mechanics - such as a basic chainsaw or fireaxe dealing 15 or over damage to their mech when a upgraded Durand isn't affected by this. Makes antag/centcom mechs good 'against most threats' out of the box, so better for newbies and less stressful for experienced players who won't have to literally _do station jobs_ to get a good mech. Did you know: mech mechanics aren't even explained at all in-game? Balance wise, it's "good against everything" and loses the ability to be super-specialized against a single thing, while retaining higher-then-normal grades on everything else. Station mechs still have the ability to specialize in one armor, say, melee, but have much worse grades on bullet/laser/EMP, and often have less health. Previously, a trip to Robotics could get a D-GYGAX up to 85% melee while still retaining 40%/50% of bullet/laser which imo is a biit *too* good. The difference between say - 70% and 85% is fairly significant - 9 damage / 13.5 damage for 70% melee vs 4.5 / 6.7 damage for 85%, so twice as good. NOTE: Some of the mechs receive better bomb/energy armors, which weren't affected by armor upgrades. ## Changelog :cl: balance: Antag/Centcom mechs now have top notch un-upgradeable armor out of the box. You can't add armor to centcom or nukie mechs anymore, but their default armor rating is a lot higher. /:cl: --- code/modules/vehicles/mecha/combat/gygax.dm | 12 ++--- .../modules/vehicles/mecha/combat/marauder.dm | 45 ++++++++++++++----- 2 files changed, 39 insertions(+), 18 deletions(-) diff --git a/code/modules/vehicles/mecha/combat/gygax.dm b/code/modules/vehicles/mecha/combat/gygax.dm index 82fd77f22890d..0284f10d23d43 100644 --- a/code/modules/vehicles/mecha/combat/gygax.dm +++ b/code/modules/vehicles/mecha/combat/gygax.dm @@ -34,7 +34,7 @@ acid = 100 /obj/vehicle/sealed/mecha/gygax/dark - desc = "A lightweight exosuit, painted in a dark scheme. This model appears to have some modifications." + desc = "A lightweight exosuit, painted in a dark scheme. This model's armor has been upgraded with a cutting-edge armor composite, resulting in greater protection and performance at the cost of modularity." name = "\improper Dark Gygax" ui_theme = "syndicate" icon_state = "darkgygax" @@ -53,21 +53,21 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 4, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 0, ) equip_by_category = list( MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/scattershot, MECHA_R_ARM = null, MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), MECHA_POWER = list(), - MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/anticcw_armor_booster, /obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster), + MECHA_ARMOR = list(), ) destruction_sleep_duration = 20 /datum/armor/gygax_dark - melee = 40 - bullet = 40 - laser = 50 + melee = 70 + bullet = 50 + laser = 55 energy = 35 bomb = 20 fire = 100 diff --git a/code/modules/vehicles/mecha/combat/marauder.dm b/code/modules/vehicles/mecha/combat/marauder.dm index 750223a85d7ad..3cc73214fcac1 100644 --- a/code/modules/vehicles/mecha/combat/marauder.dm +++ b/code/modules/vehicles/mecha/combat/marauder.dm @@ -1,5 +1,5 @@ /obj/vehicle/sealed/mecha/marauder - desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations." + desc = "Heavy-duty, combat exosuit, developed after the Durand model. Rarely found among civilian populations. Its bleeding edge armour ensures maximum usability and protection at the cost of some modularity." name = "\improper Marauder" icon_state = "marauder" base_icon_state = "marauder" @@ -20,16 +20,16 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 5, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 0, ) bumpsmash = TRUE /datum/armor/mecha_marauder - melee = 50 - bullet = 55 - laser = 40 + melee = 70 + bullet = 60 + laser = 60 energy = 30 - bomb = 30 + bomb = 50 fire = 100 acid = 100 @@ -44,7 +44,7 @@ MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack, MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), MECHA_POWER = list(), - MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster), + MECHA_ARMOR = list(), ) /obj/vehicle/sealed/mecha/marauder/loaded/populate_parts() @@ -92,6 +92,7 @@ accesses = list(ACCESS_CENT_SPECOPS) movedelay = 3 max_integrity = 550 + armor_type = /datum/armor/mecha_seraph wreckage = /obj/structure/mecha_wreckage/seraph force = 55 max_equip_by_category = list( @@ -99,22 +100,33 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 5, MECHA_POWER = 1, - MECHA_ARMOR = 3, + MECHA_ARMOR = 0, ) equip_by_category = list( MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/energy/pulse, MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack, MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), MECHA_POWER = list(), - MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster), + MECHA_ARMOR = list(), ) +/datum/armor/mecha_seraph + melee = 80 + bullet = 65 + laser = 65 + energy = 50 + bomb = 50 + fire = 100 + acid = 100 + + /obj/vehicle/sealed/mecha/marauder/mauler - desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model." + desc = "Heavy-duty, combat exosuit, developed off of the existing Marauder model, its hardened exterior prevents the use of add-on armor packages." name = "\improper Mauler" ui_theme = "syndicate" icon_state = "mauler" base_icon_state = "mauler" + armor_type = /datum/armor/mecha_mauler accesses = list(ACCESS_SYNDICATE) wreckage = /obj/structure/mecha_wreckage/mauler mecha_flags = ID_LOCK_ON | CAN_STRAFE | IS_ENCLOSED | HAS_LIGHTS | MMI_COMPATIBLE @@ -123,7 +135,7 @@ MECHA_R_ARM = 1, MECHA_UTILITY = 4, MECHA_POWER = 1, - MECHA_ARMOR = 4, + MECHA_ARMOR = 0, ) equip_by_category = list( MECHA_L_ARM = null, @@ -134,13 +146,22 @@ ) destruction_sleep_duration = 20 +/datum/armor/mecha_mauler + melee = 80 + bullet = 60 + laser = 50 + energy = 30 + bomb = 50 + fire = 100 + acid = 100 + /obj/vehicle/sealed/mecha/marauder/mauler/loaded equip_by_category = list( MECHA_L_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/lmg, MECHA_R_ARM = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack, MECHA_UTILITY = list(/obj/item/mecha_parts/mecha_equipment/radio, /obj/item/mecha_parts/mecha_equipment/air_tank/full, /obj/item/mecha_parts/mecha_equipment/thrusters/ion), MECHA_POWER = list(), - MECHA_ARMOR = list(/obj/item/mecha_parts/mecha_equipment/armor/antiproj_armor_booster), + MECHA_ARMOR = list(), ) /obj/vehicle/sealed/mecha/marauder/mauler/loaded/Initialize(mapload) From e033153a03e6856915cd637b1529b223b0afdba0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Thu, 6 Jun 2024 21:47:15 +1200 Subject: [PATCH 44/81] Automatic changelog for PR #83580 [ci skip] --- html/changelogs/AutoChangeLog-pr-83580.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83580.yml diff --git a/html/changelogs/AutoChangeLog-pr-83580.yml b/html/changelogs/AutoChangeLog-pr-83580.yml new file mode 100644 index 0000000000000..9277fb1dbdd5d --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83580.yml @@ -0,0 +1,4 @@ +author: "githubuser4141" +delete-after: True +changes: + - balance: "Antag/Centcom mechs now have top notch un-upgradeable armor out of the box. You can't add armor to centcom or nukie mechs anymore, but their default armor rating is a lot higher." \ No newline at end of file From e9c45c44a5baa8b6b13d8d65448d5d27fe8f7280 Mon Sep 17 00:00:00 2001 From: IsaacExists <125638858+IsaacExists@users.noreply.github.com> Date: Thu, 6 Jun 2024 15:25:27 -0400 Subject: [PATCH 45/81] Blindfold Color Preference (#83670) ## About The Pull Request When selecting the Blindness quirk, you now have the option to choose a specific color for the blindfold much like how the tagger quirk handles spray can color preference. The blindfolds used to always take a blend RGB of both eye colors and apply it to the blindfold, now it _should_ only do that if you have the blind-personnel blindfold directly spawned on your eyes. If not, then it just handles it like how it did before this PR was submitted, and mobs generally shouldn't have the blind-personnel blindfold if they aren't blind anyways. ![IFcWtAQ](https://github.com/tgstation/tgstation/assets/125638858/0320edb0-2963-4e94-8da1-2136dadd6d14) ## Why It's Good For The Game While it isn't a big deal if your eye color matches the blindfold, some players (like a certain someone I know) would rather have their eye color be distinct, as such if you have a blue eye color on both eyes but want a purple or red blindfold, you don't have to go out of your way to paint it, which generally wouldn't work the way you'd want it to. In other words, it allows you to customize your character with more freedom, but only applies to those who willingly choose to suffer in the game. Being blind is fun! =) ## Changelog :cl: add: You may choose a color preference for your blindfold with the blindness quirk. /:cl: --- code/datums/quirks/negative_quirks/blindness.dm | 9 ++++++++- code/modules/client/preferences/blindfold_color.dm | 14 ++++++++++++++ tgstation.dme | 1 + .../character_preferences/blindfold_color.tsx | 6 ++++++ 4 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 code/modules/client/preferences/blindfold_color.dm create mode 100644 tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/blindfold_color.tsx diff --git a/code/datums/quirks/negative_quirks/blindness.dm b/code/datums/quirks/negative_quirks/blindness.dm index ce57e946fe92e..d0af915dc32b0 100644 --- a/code/datums/quirks/negative_quirks/blindness.dm +++ b/code/datums/quirks/negative_quirks/blindness.dm @@ -10,8 +10,15 @@ quirk_flags = QUIRK_HUMAN_ONLY|QUIRK_CHANGES_APPEARANCE mail_goodies = list(/obj/item/clothing/glasses/sunglasses, /obj/item/cane/white) +/datum/quirk_constant_data/blindfoldcolor + associated_typepath = /datum/quirk/item_quirk/blindness + customization_options = list(/datum/preference/color/blindfold_color) + /datum/quirk/item_quirk/blindness/add_unique(client/client_source) - give_item_to_holder(/obj/item/clothing/glasses/blindfold/white, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) + var/obj/item/clothing/glasses/blindfold/white/blindfold = new + blindfold.add_atom_colour(client_source?.prefs.read_preference(/datum/preference/color/blindfold_color), FIXED_COLOUR_PRIORITY) + blindfold.colored_before = TRUE + give_item_to_holder(blindfold, list(LOCATION_EYES = ITEM_SLOT_EYES, LOCATION_BACKPACK = ITEM_SLOT_BACKPACK, LOCATION_HANDS = ITEM_SLOT_HANDS)) /datum/quirk/item_quirk/blindness/add(client/client_source) quirk_holder.become_blind(QUIRK_TRAIT) diff --git a/code/modules/client/preferences/blindfold_color.dm b/code/modules/client/preferences/blindfold_color.dm new file mode 100644 index 0000000000000..9e6504579acb6 --- /dev/null +++ b/code/modules/client/preferences/blindfold_color.dm @@ -0,0 +1,14 @@ +/// Preference for the roundstart color of the blindfold given by the Blindness quirk. +/datum/preference/color/blindfold_color + category = PREFERENCE_CATEGORY_MANUALLY_RENDERED + savefile_key = "blindfold_color" + savefile_identifier = PREFERENCE_CHARACTER + +/datum/preference/color/blindfold_color/is_accessible(datum/preferences/preferences) + if (!..(preferences)) + return FALSE + + return /datum/quirk/item_quirk/blindness::name in preferences.all_quirks + +/datum/preference/color/blindfold_color/apply_to_human(mob/living/carbon/human/target, value) + return diff --git a/tgstation.dme b/tgstation.dme index 803e8fadfaa14..2d6dbda22bc66 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -3664,6 +3664,7 @@ #include "code\modules\client\preferences\ambient_occlusion.dm" #include "code\modules\client\preferences\assets.dm" #include "code\modules\client\preferences\auto_fit_viewport.dm" +#include "code\modules\client\preferences\blindfold_color.dm" #include "code\modules\client\preferences\body_type.dm" #include "code\modules\client\preferences\broadcast_login_logout.dm" #include "code\modules\client\preferences\clothing.dm" diff --git a/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/blindfold_color.tsx b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/blindfold_color.tsx new file mode 100644 index 0000000000000..8a59ced57a8f9 --- /dev/null +++ b/tgui/packages/tgui/interfaces/PreferencesMenu/preferences/features/character_preferences/blindfold_color.tsx @@ -0,0 +1,6 @@ +import { Feature, FeatureColorInput } from '../base'; + +export const blindfold_color: Feature = { + name: 'Blindfold color', + component: FeatureColorInput, +}; From a2d3d211e91846556f8e078c760d3e8babc12784 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 7 Jun 2024 07:25:47 +1200 Subject: [PATCH 46/81] Automatic changelog for PR #83670 [ci skip] --- html/changelogs/AutoChangeLog-pr-83670.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83670.yml diff --git a/html/changelogs/AutoChangeLog-pr-83670.yml b/html/changelogs/AutoChangeLog-pr-83670.yml new file mode 100644 index 0000000000000..25b009993a562 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83670.yml @@ -0,0 +1,4 @@ +author: "IsaacExists" +delete-after: True +changes: + - rscadd: "You may choose a color preference for your blindfold with the blindness quirk." \ No newline at end of file From 12c4688fe45bfd57789d5068279bb893f7fcf760 Mon Sep 17 00:00:00 2001 From: grungussuss <96586172+Sadboysuss@users.noreply.github.com> Date: Thu, 6 Jun 2024 22:33:09 +0300 Subject: [PATCH 47/81] making installing card readers and airlock electronics into closets easier and more intuitive. (#83664) ## About The Pull Request Before, you would have to weld the closet to perform any actions with its electronics, now it only needs it to be closed and unlocked. ## Why It's Good For The Game I think having to weld the locker before installing electronics didn't make sense, nor was it intuitive as after asking any player how to do it - they would say you can't since no one knew you had to weld it, in part this can be blamed by the examine tips but I think this is much better. ## Changelog :cl: qol: you now don't need to weld a closet to install/uninstall electronics/card readers. /:cl: --- .../objects/structures/crates_lockers/closets.dm | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index acbd7bfa39539..9aef99482a0b1 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -382,7 +382,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) context[SCREENTIP_CONTEXT_RMB] = anchored ? "Unanchor" : "Anchor" screentip_change = TRUE - if(!locked && (welded || !can_weld_shut)) + if(!locked && !opened && (welded || !can_weld_shut)) if(!secure) if(!broken && can_install_electronics && istype(held_item, /obj/item/electronics/airlock)) context[SCREENTIP_CONTEXT_LMB] = "Install Electronics" @@ -644,7 +644,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /// check if we can install airlock electronics in this closet /obj/structure/closet/proc/can_install_airlock_electronics(mob/user) - if(secure || !can_install_electronics || !(welded || !can_weld_shut)) + if(secure || !can_install_electronics || opened) return FALSE if(broken) @@ -659,9 +659,11 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /// check if we can unscrew airlock electronics from this closet /obj/structure/closet/proc/can_unscrew_airlock_electronics(mob/user) - if(!secure || !(welded || !can_weld_shut)) + if(!secure || opened) + return FALSE + if(card_reader_installed) + balloon_alert(user, "attached to reader!") return FALSE - if(locked) balloon_alert(user, "unlock first!") return FALSE @@ -670,7 +672,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /// check if we can install card reader in this closet /obj/structure/closet/proc/can_install_card_reader(mob/user) - if(card_reader_installed || !can_install_electronics || !length(access_choices) || !(welded || !can_weld_shut)) + if(card_reader_installed || !can_install_electronics || !length(access_choices) || opened) return FALSE if(broken) @@ -689,7 +691,7 @@ GLOBAL_LIST_EMPTY(roundstart_station_closets) /// check if we can pry out the card reader from this closet /obj/structure/closet/proc/can_pryout_card_reader(mob/user) - if(!card_reader_installed || !(welded || !can_weld_shut)) + if(!card_reader_installed || opened) return FALSE if(locked) From c6c8d7ec7f9655e87d4e6af0a304dcd80bfa9530 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 7 Jun 2024 07:33:30 +1200 Subject: [PATCH 48/81] Automatic changelog for PR #83664 [ci skip] --- html/changelogs/AutoChangeLog-pr-83664.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83664.yml diff --git a/html/changelogs/AutoChangeLog-pr-83664.yml b/html/changelogs/AutoChangeLog-pr-83664.yml new file mode 100644 index 0000000000000..8a77df37d9566 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83664.yml @@ -0,0 +1,4 @@ +author: "Sadboysuss" +delete-after: True +changes: + - qol: "you now don't need to weld a closet to install/uninstall electronics/card readers." \ No newline at end of file From fb6d892204c1db2917e93a3a51996f36bfaa86f7 Mon Sep 17 00:00:00 2001 From: necromanceranne <40847847+necromanceranne@users.noreply.github.com> Date: Fri, 7 Jun 2024 05:34:05 +1000 Subject: [PATCH 49/81] [NO GBP] Only add the armor plate prefix once. (#83650) ## About The Pull Request Currently, this will add the prefix for every upgrade. We only want to add it once. ## Why It's Good For The Game Oops. This isn't working as intended. ## Changelog :cl: fix: The armor plate component only adds the prefix once. /:cl: --- code/datums/components/armor_plate.dm | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/code/datums/components/armor_plate.dm b/code/datums/components/armor_plate.dm index 7f56f2d74e4eb..9e495ada52fae 100644 --- a/code/datums/components/armor_plate.dm +++ b/code/datums/components/armor_plate.dm @@ -11,6 +11,8 @@ var/upgrade_name /// Adds a prefix to the item, demonstrating that it is upgraded in some way. var/upgrade_prefix = "reinforced" + /// Tracks whether or not we've received an upgrade or not. + var/have_upgraded = FALSE /datum/armor/armor_plate melee = 10 @@ -81,11 +83,11 @@ to_chat(user, span_info("You strengthen [mecha_for_upgrading], improving its resistance against attacks.")) else SEND_SIGNAL(target_for_upgrading, COMSIG_ARMOR_PLATED, amount, maxamount) - if(upgrade_prefix) + if(upgrade_prefix && !have_upgraded) target_for_upgrading.name = "[upgrade_prefix] [target_for_upgrading.name]" + have_upgraded = TRUE to_chat(user, span_info("You strengthen [target_for_upgrading], improving its resistance against attacks.")) - /datum/component/armor_plate/proc/dropplates(datum/source, force) SIGNAL_HANDLER From db5907a41ecd76e028f76e643f5fb37e083de888 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 7 Jun 2024 07:34:24 +1200 Subject: [PATCH 50/81] Automatic changelog for PR #83650 [ci skip] --- html/changelogs/AutoChangeLog-pr-83650.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83650.yml diff --git a/html/changelogs/AutoChangeLog-pr-83650.yml b/html/changelogs/AutoChangeLog-pr-83650.yml new file mode 100644 index 0000000000000..36be92034d2a3 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83650.yml @@ -0,0 +1,4 @@ +author: "necromanceranne" +delete-after: True +changes: + - bugfix: "The armor plate component only adds the prefix once." \ No newline at end of file From f3e2efaf9d55fd8b8ae6e252332f5f51fde04b31 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Fri, 7 Jun 2024 00:21:37 +0000 Subject: [PATCH 51/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-83103.yml | 4 -- html/changelogs/AutoChangeLog-pr-83317.yml | 7 --- html/changelogs/AutoChangeLog-pr-83520.yml | 4 -- html/changelogs/AutoChangeLog-pr-83543.yml | 4 -- html/changelogs/AutoChangeLog-pr-83580.yml | 4 -- html/changelogs/AutoChangeLog-pr-83585.yml | 4 -- html/changelogs/AutoChangeLog-pr-83587.yml | 4 -- html/changelogs/AutoChangeLog-pr-83607.yml | 5 -- html/changelogs/AutoChangeLog-pr-83610.yml | 6 -- html/changelogs/AutoChangeLog-pr-83625.yml | 4 -- html/changelogs/AutoChangeLog-pr-83650.yml | 4 -- html/changelogs/AutoChangeLog-pr-83664.yml | 4 -- html/changelogs/AutoChangeLog-pr-83670.yml | 4 -- html/changelogs/AutoChangeLog-pr-83692.yml | 4 -- html/changelogs/AutoChangeLog-pr-83694.yml | 4 -- html/changelogs/AutoChangeLog-pr-83700.yml | 5 -- html/changelogs/AutoChangeLog-pr-83703.yml | 4 -- html/changelogs/AutoChangeLog-pr-83705.yml | 4 -- html/changelogs/AutoChangeLog-pr-83710.yml | 4 -- html/changelogs/AutoChangeLog-pr-83723.yml | 4 -- html/changelogs/AutoChangeLog-pr-83725.yml | 4 -- html/changelogs/AutoChangeLog-pr-83727.yml | 4 -- html/changelogs/AutoChangeLog-pr-83729.yml | 4 -- html/changelogs/archive/2024-06.yml | 69 ++++++++++++++++++++++ 24 files changed, 69 insertions(+), 99 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-83103.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83317.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83520.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83543.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83580.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83585.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83587.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83607.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83610.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83625.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83650.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83664.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83670.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83692.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83694.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83700.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83703.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83705.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83710.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83723.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83725.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83727.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83729.yml diff --git a/html/changelogs/AutoChangeLog-pr-83103.yml b/html/changelogs/AutoChangeLog-pr-83103.yml deleted file mode 100644 index 3fff3c226022f..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83103.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "RedBaronFlyer" -delete-after: True -changes: - - rscadd: "Janitorial keyrings are now part of every janitor's toolkit instead of just the first one." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83317.yml b/html/changelogs/AutoChangeLog-pr-83317.yml deleted file mode 100644 index 788928563d40c..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83317.yml +++ /dev/null @@ -1,7 +0,0 @@ -author: "ShizCalev" -delete-after: True -changes: - - bugfix: "Syndicate AI can no longer be selected via the station law upload console." - - bugfix: "Non-syndicate borgs can no longer accidentally be slaved to syndicate AI by pulsing their AI wires." - - bugfix: "Syndicate borgs can no longer be slaved to the station AI by pulsing their AI wires." - - bugfix: "Syndicate operatives onboard the station can no longer end up with an objective to destroy their own syndicate AI." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83520.yml b/html/changelogs/AutoChangeLog-pr-83520.yml deleted file mode 100644 index 1d05b20a7fa22..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83520.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - bugfix: "Fixes the brig cell timer adjustment not working correctly on live timers." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83543.yml b/html/changelogs/AutoChangeLog-pr-83543.yml deleted file mode 100644 index 97fbae4260357..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83543.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sadboysuss" -delete-after: True -changes: - - bugfix: "curator whip will no longer disarm when parried" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83580.yml b/html/changelogs/AutoChangeLog-pr-83580.yml deleted file mode 100644 index 9277fb1dbdd5d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83580.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "githubuser4141" -delete-after: True -changes: - - balance: "Antag/Centcom mechs now have top notch un-upgradeable armor out of the box. You can't add armor to centcom or nukie mechs anymore, but their default armor rating is a lot higher." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83585.yml b/html/changelogs/AutoChangeLog-pr-83585.yml deleted file mode 100644 index 763c4c4689b44..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83585.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EuSouAFazer" -delete-after: True -changes: - - qol: "Swabbing the clown's stamp also gives clown cells.\n:cl:" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83587.yml b/html/changelogs/AutoChangeLog-pr-83587.yml deleted file mode 100644 index 22d1ee5b2b99d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83587.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "autolathes don't hang when printing items in areas without apc or if it runs out of materials mid printing" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83607.yml b/html/changelogs/AutoChangeLog-pr-83607.yml deleted file mode 100644 index 157da5e87b1b0..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83607.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - qol: "Coffee types are overall more consistent, causing jittering only from the overdose effect." - - bugfix: "Pumpkin lattes will actually work like coffee." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83610.yml b/html/changelogs/AutoChangeLog-pr-83610.yml deleted file mode 100644 index 40b34b9cff514..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83610.yml +++ /dev/null @@ -1,6 +0,0 @@ -author: "LT3" -delete-after: True -changes: - - bugfix: "Fixed timing issue where tram crossing signals would be out of sync with the moving tram" - - bugfix: "Tram crossing signals consistently show green when safe, blue when broken" - - bugfix: "Tram crossing signals show red instead of yellow when degraded" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83625.yml b/html/changelogs/AutoChangeLog-pr-83625.yml deleted file mode 100644 index a1a93ffa31f71..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83625.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Erol509" -delete-after: True -changes: - - qol: "Cyborgs on AI statpanel now have jules energy format." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83650.yml b/html/changelogs/AutoChangeLog-pr-83650.yml deleted file mode 100644 index 36be92034d2a3..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83650.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "The armor plate component only adds the prefix once." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83664.yml b/html/changelogs/AutoChangeLog-pr-83664.yml deleted file mode 100644 index 8a77df37d9566..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83664.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Sadboysuss" -delete-after: True -changes: - - qol: "you now don't need to weld a closet to install/uninstall electronics/card readers." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83670.yml b/html/changelogs/AutoChangeLog-pr-83670.yml deleted file mode 100644 index 25b009993a562..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83670.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "IsaacExists" -delete-after: True -changes: - - rscadd: "You may choose a color preference for your blindfold with the blindness quirk." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83692.yml b/html/changelogs/AutoChangeLog-pr-83692.yml deleted file mode 100644 index 4dfa490dc3e2d..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83692.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Wayland-Smithy" -delete-after: True -changes: - - bugfix: "Pre-Loaded Syndicate Intellicard AI's no longer appear in PDA messenger." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83694.yml b/html/changelogs/AutoChangeLog-pr-83694.yml deleted file mode 100644 index a82a580ef8e23..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83694.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Whoneedspacee" -delete-after: True -changes: - - bugfix: "Bubblegum can no longer melee you while using his charge abilities." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83700.yml b/html/changelogs/AutoChangeLog-pr-83700.yml deleted file mode 100644 index ec2937bc0be32..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83700.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "necromanceranne" -delete-after: True -changes: - - bugfix: "Drake empowerment for berserker armor now uses valuable drake remains, made from ashdrake hides and bones." - - rscadd: "Drake armor is made use drake remains to construct. (This is a net neutral to the previous recipe)" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83703.yml b/html/changelogs/AutoChangeLog-pr-83703.yml deleted file mode 100644 index fe215399c4886..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83703.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zxaber" -delete-after: True -changes: - - bugfix: "Tool-based flashes (read: from welders) are no longer incorrectly locked at flash level 1. Wear proper PPE!" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83705.yml b/html/changelogs/AutoChangeLog-pr-83705.yml deleted file mode 100644 index 6f559c14e3cde..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83705.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Absolucy" -delete-after: True -changes: - - bugfix: "When implanting functional wings into a new body, they will actually be able to use said wings now." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83710.yml b/html/changelogs/AutoChangeLog-pr-83710.yml deleted file mode 100644 index a02f0e991cdc1..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83710.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "san7890" -delete-after: True -changes: - - bugfix: "Using the 'ESC' key on your keyboard to unbind a key in the keybindings preferences menu should now work as expected. This should also be fixed for people in a variety of other spots too." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83723.yml b/html/changelogs/AutoChangeLog-pr-83723.yml deleted file mode 100644 index 0f5e6c311c5dc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83723.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "EEASAS" -delete-after: True -changes: - - bugfix: "fixed the mis-rotated disposals pipe on birdshot" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83725.yml b/html/changelogs/AutoChangeLog-pr-83725.yml deleted file mode 100644 index 2f0fa7f196361..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83725.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - bugfix: "RLD glowsticks actually glow again." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83727.yml b/html/changelogs/AutoChangeLog-pr-83727.yml deleted file mode 100644 index 43106a2e857dd..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83727.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - bugfix: "COMSIG_ATOM_POST_DIR_CHANGE should ACTUALLY work now" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83729.yml b/html/changelogs/AutoChangeLog-pr-83729.yml deleted file mode 100644 index af3a1e7123f19..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83729.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Pickle-Coding" -delete-after: True -changes: - - bugfix: "Fixes paradox clones using a different voice from the owner." \ No newline at end of file diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml index d3c188fd73c68..7238a63a67e1a 100644 --- a/html/changelogs/archive/2024-06.yml +++ b/html/changelogs/archive/2024-06.yml @@ -263,3 +263,72 @@ mc-oofert: - balance: cult stun gets weaker when they get red eyes and later more when they have halos +2024-06-07: + 00-Steven: + - bugfix: RLD glowsticks actually glow again. + Absolucy: + - bugfix: When implanting functional wings into a new body, they will actually be + able to use said wings now. + EEASAS: + - bugfix: fixed the mis-rotated disposals pipe on birdshot + Erol509: + - qol: Cyborgs on AI statpanel now have jules energy format. + EuSouAFazer: + - qol: 'Swabbing the clown''s stamp also gives clown cells. + + :cl:' + IsaacExists: + - rscadd: You may choose a color preference for your blindfold with the blindness + quirk. + LT3: + - bugfix: Fixed timing issue where tram crossing signals would be out of sync with + the moving tram + - bugfix: Tram crossing signals consistently show green when safe, blue when broken + - bugfix: Tram crossing signals show red instead of yellow when degraded + Pickle-Coding: + - bugfix: Fixes the brig cell timer adjustment not working correctly on live timers. + - bugfix: Fixes paradox clones using a different voice from the owner. + RedBaronFlyer: + - rscadd: Janitorial keyrings are now part of every janitor's toolkit instead of + just the first one. + Sadboysuss: + - bugfix: curator whip will no longer disarm when parried + - qol: you now don't need to weld a closet to install/uninstall electronics/card + readers. + ShizCalev: + - bugfix: Syndicate AI can no longer be selected via the station law upload console. + - bugfix: Non-syndicate borgs can no longer accidentally be slaved to syndicate + AI by pulsing their AI wires. + - bugfix: Syndicate borgs can no longer be slaved to the station AI by pulsing their + AI wires. + - bugfix: Syndicate operatives onboard the station can no longer end up with an + objective to destroy their own syndicate AI. + SyncIt21: + - bugfix: autolathes don't hang when printing items in areas without apc or if it + runs out of materials mid printing + Wayland-Smithy: + - bugfix: Pre-Loaded Syndicate Intellicard AI's no longer appear in PDA messenger. + Whoneedspacee: + - bugfix: Bubblegum can no longer melee you while using his charge abilities. + githubuser4141: + - balance: Antag/Centcom mechs now have top notch un-upgradeable armor out of the + box. You can't add armor to centcom or nukie mechs anymore, but their default + armor rating is a lot higher. + necromanceranne: + - bugfix: The armor plate component only adds the prefix once. + - bugfix: Drake empowerment for berserker armor now uses valuable drake remains, + made from ashdrake hides and bones. + - rscadd: Drake armor is made use drake remains to construct. (This is a net neutral + to the previous recipe) + - qol: Coffee types are overall more consistent, causing jittering only from the + overdose effect. + - bugfix: Pumpkin lattes will actually work like coffee. + nikothedude: + - bugfix: COMSIG_ATOM_POST_DIR_CHANGE should ACTUALLY work now + san7890: + - bugfix: Using the 'ESC' key on your keyboard to unbind a key in the keybindings + preferences menu should now work as expected. This should also be fixed for + people in a variety of other spots too. + zxaber: + - bugfix: 'Tool-based flashes (read: from welders) are no longer incorrectly locked + at flash level 1. Wear proper PPE!' From 79ff783c667e32100178f64a7d2d1e2e2008f308 Mon Sep 17 00:00:00 2001 From: MrMelbert <51863163+MrMelbert@users.noreply.github.com> Date: Thu, 6 Jun 2024 19:25:25 -0500 Subject: [PATCH 52/81] Fix actionspeed modifiers with IDs being broken (#83758) ## About The Pull Request #78124 added an init arg to these which 99% of actionspeed modifiers don't pass, so it's passed as null, so it sets id = null, so any preset ids get nulled out, meaning actionspeed modifiers intended on overriding each other don't. ## Changelog :cl: Melbert fix: Fix some modifiers to do after speed (sanity, midas gun) stacking when they shouldn't /:cl: --- code/modules/actionspeed/_actionspeed_modifier.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/actionspeed/_actionspeed_modifier.dm b/code/modules/actionspeed/_actionspeed_modifier.dm index 761bfc3ff74a4..36b9b9c860dec 100644 --- a/code/modules/actionspeed/_actionspeed_modifier.dm +++ b/code/modules/actionspeed/_actionspeed_modifier.dm @@ -40,7 +40,8 @@ can next move /datum/actionspeed_modifier/New(init_id) . = ..() - id = init_id + if(init_id) + id = init_id if(!id) id = "[type]" //We turn the path into a string. From e364cf5740833b215565da51f9edfda3f1dc1489 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:25:46 +1200 Subject: [PATCH 53/81] Automatic changelog for PR #83758 [ci skip] --- html/changelogs/AutoChangeLog-pr-83758.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83758.yml diff --git a/html/changelogs/AutoChangeLog-pr-83758.yml b/html/changelogs/AutoChangeLog-pr-83758.yml new file mode 100644 index 0000000000000..749dba8eaa20b --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83758.yml @@ -0,0 +1,4 @@ +author: "Melbert" +delete-after: True +changes: + - bugfix: "Fix some modifiers to do after speed (sanity, midas gun) stacking when they shouldn't" \ No newline at end of file From 8925d03775b9bf9c9ad8fa6e9dfd0439a45c519e Mon Sep 17 00:00:00 2001 From: thegrb93 Date: Fri, 7 Jun 2024 03:09:47 -0400 Subject: [PATCH 54/81] Fix borg emag modules stuck in inventory/screen after losing emag status (#83734) ## About The Pull Request Checks that held modules exist in new module list after rebuilding modules before putting them back in held modules. Fixes emag modules stuck in inventory/screen after losing emag status Also fixes jank fail to install piercing hypospray upgrade ## Why It's Good For The Game Fixes buges ## Changelog :cl: fix: Borg emag module jank when no longer emagged fix: Borg piercing hypospray fail message /:cl: --------- Co-authored-by: LemonInTheDark <58055496+LemonInTheDark@users.noreply.github.com> --- code/_onclick/hud/robot.dm | 6 +++--- code/game/objects/items/robot/robot_upgrades.dm | 2 +- .../modules/mob/living/silicon/robot/robot_model.dm | 13 +++++++------ 3 files changed, 11 insertions(+), 10 deletions(-) diff --git a/code/_onclick/hud/robot.dm b/code/_onclick/hud/robot.dm index 88d5dada28154..e2e534443691a 100644 --- a/code/_onclick/hud/robot.dm +++ b/code/_onclick/hud/robot.dm @@ -197,13 +197,13 @@ if(!R.client) return + //Module is not currently active + screenmob.client.screen -= R.model.get_inactive_modules() + if(!R.shown_robot_modules || !screenmob.hud_used.hud_shown) //Modules display is hidden screenmob.client.screen -= module_store_icon //"store" icon - for(var/atom/A in R.model.get_inactive_modules()) - //Module is not currently active - screenmob.client.screen -= A R.shown_robot_modules = 0 screenmob.client.screen -= R.robot_modules_background return diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm index 959894b31638a..3c42e65e29c87 100644 --- a/code/game/objects/items/robot/robot_upgrades.dm +++ b/code/game/objects/items/robot/robot_upgrades.dm @@ -400,7 +400,7 @@ found_hypo = TRUE if(!found_hypo) - to_chat(user, span_warning("This unit is already equipped with a piercing hypospray upgrade!")) //check to see if we already have this module + to_chat(user, span_warning("There are no installed hypospray modules to upgrade with piercing!")) //check to see if any hyposprays were upgraded return FALSE /obj/item/borg/upgrade/piercing_hypospray/deactivate(mob/living/silicon/robot/borg, mob/living/user = usr) diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index 5ba061233d442..a46389e11b2be 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -82,6 +82,8 @@ for(var/module in get_usable_modules()) if(!(module in cyborg.held_items)) . += module + if(!cyborg.emagged) + . += emag_modules /obj/item/robot_model/proc/add_module(obj/item/added_module, nonstandard, requires_rebuild) if(isstack(added_module)) @@ -121,16 +123,15 @@ var/active_module = cyborg.module_active cyborg.drop_all_held_items() modules = list() - for(var/obj/item/module in basic_modules) + for(var/obj/item/module as anything in basic_modules) add_module(module, FALSE, FALSE) if(cyborg.emagged) - for(var/obj/item/module in emag_modules) + for(var/obj/item/module as anything in emag_modules) add_module(module, FALSE, FALSE) - for(var/obj/item/module in added_modules) + for(var/obj/item/module as anything in added_modules) add_module(module, FALSE, FALSE) - for(var/module in held_modules) - if(module) - cyborg.equip_module_to_slot(module, held_modules.Find(module)) + for(var/obj/item/module as anything in held_modules & modules) + cyborg.equip_module_to_slot(module, held_modules.Find(module)) if(active_module) cyborg.select_module(held_modules.Find(active_module)) if(cyborg.hud_used) From a6efd3b3e63ffbc20dcb255f794bbb42732584a6 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:10:05 +1200 Subject: [PATCH 55/81] Automatic changelog for PR #83734 [ci skip] --- html/changelogs/AutoChangeLog-pr-83734.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83734.yml diff --git a/html/changelogs/AutoChangeLog-pr-83734.yml b/html/changelogs/AutoChangeLog-pr-83734.yml new file mode 100644 index 0000000000000..b5fd85f6ded56 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83734.yml @@ -0,0 +1,5 @@ +author: "thegrb93" +delete-after: True +changes: + - bugfix: "Borg emag module jank when no longer emagged" + - bugfix: "Borg piercing hypospray fail message" \ No newline at end of file From d91650ea39fbb74b60577c2383b82edd9969afc3 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 7 Jun 2024 22:50:33 +0530 Subject: [PATCH 56/81] Alt right click refactor (#83736) --- code/_onclick/click.dm | 20 +-------- code/_onclick/click_alt.dm | 43 ++++++++++++++++++- code/game/objects/items/cards_ids.dm | 10 ++--- code/modules/clothing/neck/_neck.dm | 8 ++-- code/modules/clothing/under/_under.dm | 10 +---- .../projectiles/guns/ballistic/shotgun.dm | 3 +- .../chemistry/machinery/chem_mass_spec.dm | 7 +-- 7 files changed, 53 insertions(+), 48 deletions(-) diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 3c99364542c5f..ff0da9caa5ed0 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -94,7 +94,7 @@ return if(LAZYACCESS(modifiers, ALT_CLICK)) // alt and alt-gr (rightalt) if(LAZYACCESS(modifiers, RIGHT_CLICK)) - alt_click_on_secondary(A) + base_click_alt_secondary(A) else base_click_alt(A) return @@ -386,24 +386,6 @@ A.CtrlClick(src) return - -///The base proc of when something is right clicked on when alt is held - generally use alt_click_secondary instead -/atom/proc/alt_click_on_secondary(atom/A) - . = SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON_SECONDARY, A) - if(. & COMSIG_MOB_CANCEL_CLICKON) - return - A.alt_click_secondary(src) - -///The base proc of when something is right clicked on when alt is held -/atom/proc/alt_click_secondary(mob/user) - if(!user.can_interact_with(src)) - return FALSE - if(SEND_SIGNAL(src, COMSIG_CLICK_ALT_SECONDARY, user) & COMPONENT_CANCEL_CLICK_ALT_SECONDARY) - return - if(isobserver(user) && user.client && check_rights_for(user.client, R_DEBUG)) - user.client.toggle_tag_datum(src) - return - /mob/proc/TurfAdjacent(turf/tile) return tile.Adjacent(src) diff --git a/code/_onclick/click_alt.dm b/code/_onclick/click_alt.dm index dfda35ebda9c8..957f55ab21793 100644 --- a/code/_onclick/click_alt.dm +++ b/code/_onclick/click_alt.dm @@ -1,5 +1,5 @@ /** - * ### Base proc for alt click interaction. + * ### Base proc for alt click interaction left click. * * If you wish to add custom `click_alt` behavior for a single type, use that proc. */ @@ -53,7 +53,6 @@ client.loot_panel.open(tile) - /** * ## Custom alt click interaction * Override this to change default alt click behavior. Return `CLICK_ACTION_SUCCESS`, `CLICK_ACTION_BLOCKING` or `NONE`. @@ -86,6 +85,46 @@ return NONE +/** + * ### Base proc for alt click interaction right click. + * + * If you wish to add custom `click_alt_secondary` behavior for a single type, use that proc. + */ +/mob/proc/base_click_alt_secondary(atom/target) + SHOULD_NOT_OVERRIDE(TRUE) + + //Hook on the mob to intercept the click + if(SEND_SIGNAL(src, COMSIG_MOB_ALTCLICKON_SECONDARY, target) & COMSIG_MOB_CANCEL_CLICKON) + return + + var/can_use_click_action = FALSE + if(isturf(target)) + // Turfs are special because they can't be used with can_perform_action + can_use_click_action = can_perform_turf_action(target) + else + can_use_click_action = can_perform_action(target, target.interaction_flags_click | SILENT_ADJACENCY) + if(!can_use_click_action) + return + + //Hook on the atom to intercept the click + if(SEND_SIGNAL(target, COMSIG_CLICK_ALT_SECONDARY, src) & COMPONENT_CANCEL_CLICK_ALT_SECONDARY) + return + if(isobserver(src) && client && check_rights_for(client, R_DEBUG)) + client.toggle_tag_datum(src) + return + target.click_alt_secondary(src) + +/** + * ## Custom alt click secondary interaction + * Override this to change default alt right click behavior. + * + * ### Guard clauses + * Consider adding `interaction_flags_click` before adding unique guard clauses. + **/ +/atom/proc/click_alt_secondary(mob/user) + SHOULD_CALL_PARENT(FALSE) + return NONE + /// Helper proc to validate turfs. Used because can_perform_action does not support turfs. /mob/proc/can_perform_turf_action(turf/target) if(!CanReach(target)) // No error message for parity with SILENT_ADJACENCY diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm index fe03aaaf01e0d..880e619da0a8a 100644 --- a/code/game/objects/items/cards_ids.dm +++ b/code/game/objects/items/cards_ids.dm @@ -56,6 +56,7 @@ icon_state = "card_grey" worn_icon_state = "nothing" slot_flags = ITEM_SLOT_ID + interaction_flags_click = FORBID_TELEKINESIS_REACH armor_type = /datum/armor/card_id resistance_flags = FIRE_PROOF | ACID_PROOF @@ -633,9 +634,6 @@ /obj/item/card/id/proc/alt_click_can_use_id(mob/living/user) if(!isliving(user)) return FALSE - if(!user.can_perform_action(src, FORBID_TELEKINESIS_REACH)) - return FALSE - return TRUE /// Attempts to set a new bank account on the ID card. @@ -706,13 +704,11 @@ registered_account.bank_card_talk(span_warning("ERROR: The linked account requires [difference] more credit\s to perform that withdrawal."), TRUE) return CLICK_ACTION_BLOCKING -/obj/item/card/id/alt_click_secondary(mob/user) - . = ..() +/obj/item/card/id/click_alt_secondary(mob/user) if(!alt_click_can_use_id(user)) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + return if(!registered_account || registered_account.replaceable) set_new_account(user) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/card/id/proc/pay_debt(user) var/amount_to_pay = tgui_input_number(user, "How much do you want to pay? (Max: [registered_account.account_balance] cr)", "Debt Payment", max_value = min(registered_account.account_balance, registered_account.account_debt)) diff --git a/code/modules/clothing/neck/_neck.dm b/code/modules/clothing/neck/_neck.dm index 2cac09685796f..7a3c0f1150de4 100644 --- a/code/modules/clothing/neck/_neck.dm +++ b/code/modules/clothing/neck/_neck.dm @@ -3,6 +3,7 @@ icon = 'icons/obj/clothing/neck.dmi' body_parts_covered = NECK slot_flags = ITEM_SLOT_NECK + interaction_flags_click = NEED_DEXTERITY strip_delay = 40 equip_delay_other = 40 @@ -103,11 +104,8 @@ user.update_clothing(ITEM_SLOT_NECK) return CLICK_ACTION_SUCCESS -/obj/item/clothing/neck/tie/alt_click_secondary(mob/user) - . = ..() - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return - alternate_worn_layer = alternate_worn_layer == initial(alternate_worn_layer) ? NONE : initial(alternate_worn_layer) +/obj/item/clothing/neck/tie/click_alt_secondary(mob/user) + alternate_worn_layer = (alternate_worn_layer == initial(alternate_worn_layer) ? NONE : initial(alternate_worn_layer)) user.update_clothing(ITEM_SLOT_NECK) balloon_alert(user, "wearing [alternate_worn_layer == initial(alternate_worn_layer) ? "below" : "above"] suits") diff --git a/code/modules/clothing/under/_under.dm b/code/modules/clothing/under/_under.dm index fd8512c3eb83f..40f8068aef56d 100644 --- a/code/modules/clothing/under/_under.dm +++ b/code/modules/clothing/under/_under.dm @@ -6,6 +6,7 @@ righthand_file = 'icons/mob/inhands/clothing/suits_righthand.dmi' body_parts_covered = CHEST|GROIN|LEGS|ARMS slot_flags = ITEM_SLOT_ICLOTHING + interaction_flags_click = NEED_DEXTERITY armor_type = /datum/armor/clothing_under equip_sound = 'sound/items/equip/jumpsuit_equip.ogg' drop_sound = 'sound/items/handling/cloth_drop.ogg' @@ -378,17 +379,10 @@ rolldown() return CLICK_ACTION_SUCCESS -/obj/item/clothing/under/alt_click_secondary(mob/user) - . = ..() - if(.) - return - +/obj/item/clothing/under/click_alt_secondary(mob/user) if(!LAZYLEN(attached_accessories)) balloon_alert(user, "no accessories to remove!") return - if(!user.can_perform_action(src, NEED_DEXTERITY)) - return - pop_accessory(user) /obj/item/clothing/under/verb/jumpsuit_adjust() diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 85f3283ca43d1..a06f6954bf374 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -239,14 +239,13 @@ update_appearance() return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN -/obj/item/gun/ballistic/shotgun/bulldog/alt_click_secondary(mob/user) +/obj/item/gun/ballistic/shotgun/bulldog/click_alt_secondary(mob/user) if(secondary_magazine) var/obj/item/ammo_box/magazine/old_mag = secondary_magazine secondary_magazine = null user.put_in_hands(old_mag) update_appearance() playsound(src, load_empty_sound, load_sound_volume, load_sound_vary) - return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN /obj/item/gun/ballistic/shotgun/bulldog/proc/toggle_magazine() var/primary_magazine = magazine diff --git a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm index e11910a13afce..e43d32c661bd9 100644 --- a/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm +++ b/code/modules/reagents/chemistry/machinery/chem_mass_spec.dm @@ -434,13 +434,10 @@ replace_beaker(user, TRUE) return CLICK_ACTION_SUCCESS -/obj/machinery/chem_mass_spec/alt_click_secondary(mob/living/user) - . = ..() - if(!can_interact(user)) - return +/obj/machinery/chem_mass_spec/click_alt_secondary(mob/living/user) if(processing_reagents) balloon_alert(user, "still processing!") - return ..() + return replace_beaker(user, FALSE) /obj/machinery/chem_mass_spec/process(seconds_per_tick) From da242e6fdb874e358d522971acfa0fc147bc8c86 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:20:52 +1200 Subject: [PATCH 57/81] Automatic changelog for PR #83736 [ci skip] --- html/changelogs/AutoChangeLog-pr-83736.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83736.yml diff --git a/html/changelogs/AutoChangeLog-pr-83736.yml b/html/changelogs/AutoChangeLog-pr-83736.yml new file mode 100644 index 0000000000000..8ab2ca51d56d4 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83736.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - refactor: "alt right click has been refactored. report bugs on github" \ No newline at end of file From 331f479e51a467e747807dd7b57ee9d674672317 Mon Sep 17 00:00:00 2001 From: MichiRecRoom <1008889+LikeLakers2@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:30:38 -0400 Subject: [PATCH 58/81] Change the pAI display face selection to a radial (#83770) ## About The Pull Request This PR changes the pAI's face display selection from a tgui input list, to a radial menu, with the actual faces displayed on the radial. ![image](https://github.com/tgstation/tgstation/assets/1008889/c89c9cf4-c3f3-4be9-9b79-08c1176687b4) This PR also removes part of the comment for `/mob/living/silicon/pai/proc/change_image()` that is no longer applicable. ## Why It's Good For The Game The radial menu makes pAI face display selection clearer, because players now see what the face looks like, rather than having to guess what a face might look like from the... frankly, very vague names given. Seriously, what is `Null` supposed to be? What is `Face` supposed to be?! ## Changelog :cl: MichiRecRoom qol: Personal AI's face display selection is now a radial menu. As a bonus, now you can see what the faces look like before selecting them. /:cl: --- code/modules/pai/software.dm | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/code/modules/pai/software.dm b/code/modules/pai/software.dm index 9876df5a2646a..ab69e69388ccd 100644 --- a/code/modules/pai/software.dm +++ b/code/modules/pai/software.dm @@ -131,12 +131,17 @@ /** * Changes the image displayed on the pAI. * - * @param {mob} user - The user who is changing the image. - * * @returns {boolean} - TRUE if the image was changed, FALSE otherwise. */ /mob/living/silicon/pai/proc/change_image() - var/new_image = tgui_input_list(src, "Select your new display image", "Display Image", possible_overlays) + var/list/possible_choices = list() + for(var/face_option in possible_overlays) + var/datum/radial_menu_choice/choice = new + choice.name = face_option + choice.image = image(icon = card.icon, icon_state = "pai-[face_option]") + possible_choices[face_option] += choice + var/atom/anchor = get_atom_on_turf(src) + var/new_image = show_radial_menu(src, anchor, possible_choices, custom_check = CALLBACK(src, PROC_REF(check_menu), anchor), radius = 40, require_near = TRUE) if(isnull(new_image)) return FALSE card.emotion_icon = new_image From 103fb7c8c400c784a88e840c759a1acdb51c22f8 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:30:57 +1200 Subject: [PATCH 59/81] Automatic changelog for PR #83770 [ci skip] --- html/changelogs/AutoChangeLog-pr-83770.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83770.yml diff --git a/html/changelogs/AutoChangeLog-pr-83770.yml b/html/changelogs/AutoChangeLog-pr-83770.yml new file mode 100644 index 0000000000000..262c93db0ef15 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83770.yml @@ -0,0 +1,4 @@ +author: "MichiRecRoom" +delete-after: True +changes: + - qol: "Personal AI's face display selection is now a radial menu. As a bonus, now you can see what the faces look like before selecting them." \ No newline at end of file From 08ae5a6a9e7f9bcc369405e3b98802e7a42a0d95 Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Fri, 7 Jun 2024 23:02:22 +0530 Subject: [PATCH 60/81] Fixes techfab print runtime for non apc areas (#83768) ## About The Pull Request Same problem for techfabs as mentioned in #83587 ## Changelog :cl: fix: techfabs don't runtime & hang when printing in no apc areas /:cl: --- code/modules/research/machinery/_production.dm | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/code/modules/research/machinery/_production.dm b/code/modules/research/machinery/_production.dm index cc6a45a5f1f13..16ccedaf778b8 100644 --- a/code/modules/research/machinery/_production.dm +++ b/code/modules/research/machinery/_production.dm @@ -384,11 +384,14 @@ if(!directly_use_energy(charge_per_item)) // provide the wait time until lathe is ready var/area/my_area = get_area(src) var/obj/machinery/power/apc/my_apc = my_area.apc - var/charging_wait = my_apc.time_to_charge(charge_per_item) - if(!isnull(charging_wait)) - say("Unable to continue production, APC overload. Wait [DisplayTimeText(charging_wait, round_seconds_to = 1)] and try again.") + if(!QDELETED(my_apc)) + var/charging_wait = my_apc.time_to_charge(charge_per_item) + if(!isnull(charging_wait)) + say("Unable to continue production, APC overload. Wait [DisplayTimeText(charging_wait, round_seconds_to = 1)] and try again.") + else + say("Unable to continue production, power grid overload.") else - say("Unable to continue production, power grid overload.") + say("Unable to continue production, no APC in area.") finalize_build() return From 260ec880e0ccf6866058b36224836daf469a14ed Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:33:19 +1200 Subject: [PATCH 61/81] Automatic changelog for PR #83768 [ci skip] --- html/changelogs/AutoChangeLog-pr-83768.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83768.yml diff --git a/html/changelogs/AutoChangeLog-pr-83768.yml b/html/changelogs/AutoChangeLog-pr-83768.yml new file mode 100644 index 0000000000000..dd0a446972c64 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83768.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - bugfix: "techfabs don't runtime & hang when printing in no apc areas" \ No newline at end of file From 20c3b0eb3bed748ac67680eedcf08701eb23cd2e Mon Sep 17 00:00:00 2001 From: EnterTheJake <102721711+EnterTheJake@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:35:39 +0200 Subject: [PATCH 62/81] [NO GBP] Post-Rust Heretic's Rework adjustments. (#83765) ## About The Pull Request Fixes antimagic, not preventing the disgust builtup from standing on rusted tiles, makes rust walkers more expensive to summon. ## Why It's Good For The Game I'm very happy with the end result of my Rust heretic rework; but they came up a tad stronger than i wanted them to be. Carlac already changed the Vomit stun to knockdown, but i wanted to add a couple of things myself. Having anti magic now makes you fully immune to the effects of rusted tiles, not just the spells. Rust walkers summoning ritual now requires titanium instead of iron sheets. As of right now, they are way too easy to spam, Titanium is a bit harder to come by than iron so that'll do for now. I was planning to set a limit to how many you can summon at the time, but i'd rather wait a few months to see how rust behaves before i add more nerfs. ## Changelog :cl: balance: Rust walkers' summoning ritual now requires 5 sheets of Titanium instead of Iron. fix: Magic resistance grants complete immunity from the passive disgust buildup from standing on Rusted turfs. /:cl: --- code/datums/elements/rust.dm | 2 ++ .../modules/antagonists/heretic/knowledge/side_rust_cosmos.dm | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/code/datums/elements/rust.dm b/code/datums/elements/rust.dm index 396307197c49d..265e23c5a3171 100644 --- a/code/datums/elements/rust.dm +++ b/code/datums/elements/rust.dm @@ -109,6 +109,8 @@ var/mob/living/victim = entered if(IS_HERETIC(victim)) return + if(victim.can_block_magic(MAGIC_RESISTANCE)) + return victim.apply_status_effect(/datum/status_effect/rust_corruption) /datum/element/rust/heretic/proc/on_exited(turf/source, atom/movable/gone) diff --git a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm index 671e01603c5c7..56999243b5de3 100644 --- a/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm +++ b/code/modules/antagonists/heretic/knowledge/side_rust_cosmos.dm @@ -76,7 +76,7 @@ /datum/heretic_knowledge/summon/rusty name = "Rusted Ritual" - desc = "Allows you to transmute a pool of vomit, some cable coil, and 5 sheets of iron into a Rust Walker. \ + desc = "Allows you to transmute a pool of vomit, some cable coil, and 5 sheets of titanium into a Rust Walker. \ Rust Walkers excel at spreading rust and are moderately strong in combat." gain_text = "I combined my knowledge of creation with my desire for corruption. The Marshal knew my name, and the Rusted Hills echoed out." next_knowledge = list( @@ -85,7 +85,7 @@ ) required_atoms = list( /obj/effect/decal/cleanable/vomit = 1, - /obj/item/stack/sheet/iron = 5, + /obj/item/stack/sheet/mineral/titanium = 5, /obj/item/stack/cable_coil = 15, ) mob_to_summon = /mob/living/basic/heretic_summon/rust_walker From 94bfcaf4f45eec95b11936c9c67fb5c20abf3d77 Mon Sep 17 00:00:00 2001 From: projectkepler-RU <99981766+projectkepler-ru@users.noreply.github.com> Date: Sat, 8 Jun 2024 00:37:04 +0700 Subject: [PATCH 63/81] Fix smoking pipe sprite typo (#83759) ## About The Pull Request closes #83755 there was a typographical error in both of the item ## Why It's Good For The Game it closes #83755 ## Changelog :cl: fix: smoking pipe not showing sprite when lit /:cl: --- code/game/objects/items/cigs_lighters.dm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/code/game/objects/items/cigs_lighters.dm b/code/game/objects/items/cigs_lighters.dm index 1401b057dab14..37cfb70240d67 100644 --- a/code/game/objects/items/cigs_lighters.dm +++ b/code/game/objects/items/cigs_lighters.dm @@ -701,7 +701,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "smoking pipe" desc = "A pipe, for smoking. Probably made of meerschaum or something." icon_state = "pipeoff" - icon_on = "pipeff" //Note - these are in masks.dmi + icon_on = "pipeoff" //Note - these are in masks.dmi icon_off = "pipeoff" inhand_icon_state = null inhand_icon_on = null @@ -772,7 +772,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM name = "corn cob pipe" desc = "A nicotine delivery system popularized by folksy backwoodsmen and kept popular in the modern age and beyond by space hipsters. Can be loaded with objects." icon_state = "cobpipeoff" - icon_on = "cobpipeff" //Note - these are in masks.dmi + icon_on = "cobpipeoff" //Note - these are in masks.dmi icon_off = "cobpipeoff" inhand_icon_on = null inhand_icon_off = null From 62526218c28b886e50d9c26a81914270083a303f Mon Sep 17 00:00:00 2001 From: Kian <157846764+sylvia-from-fulp-station@users.noreply.github.com> Date: Sat, 8 Jun 2024 03:38:51 +1000 Subject: [PATCH 64/81] adds final destination deathmatch map (#83757) ## About The Pull Request https://github.com/tgstation/tgstation/pull/82929 I spent hours working on this; mapping, setting classes, testing, balancing. It feels like shit to see pr closed. This is the same map but without the removal of mech madness in the pr ![Photoshop_NFdOZPhR1L](https://github.com/tgstation/tgstation/assets/157846764/cb2979f6-ee40-4f22-b2d7-457b95a056af) nuke op has a bulldog instead ## Why It's Good For The Game its a deathmatch map; there are many like it but this one is mine. The classes represent a variety of characters you'd find aboard space station 13, albeit cartoonishly powerful and with more gear than you could reasonably use. Have some honourable showdowns at peak performance or a chaotic loot fest; no gear is restricted. ## Changelog :cl: add: final destination deathmatch map, loadouts fix: indestructible light tile emits light /:cl: Co-authored-by: sylvia --- _maps/deathmatch/finaldestination.dmm | 1254 +++++++++++++++++ code/game/turfs/open/_open.dm | 3 + .../modules/deathmatch/deathmatch_loadouts.dm | 201 +++ code/modules/deathmatch/deathmatch_maps.dm | 19 + 4 files changed, 1477 insertions(+) create mode 100644 _maps/deathmatch/finaldestination.dmm diff --git a/_maps/deathmatch/finaldestination.dmm b/_maps/deathmatch/finaldestination.dmm new file mode 100644 index 0000000000000..7fef94cd57a16 --- /dev/null +++ b/_maps/deathmatch/finaldestination.dmm @@ -0,0 +1,1254 @@ +//MAP CONVERTED BY dmm2tgm.py THIS HEADER COMMENT PREVENTS RECONVERSION, DO NOT REMOVE +"ae" = ( +/obj/effect/turf_decal/siding/yellow/end, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"bF" = ( +/obj/effect/turf_decal/siding/blue/corner{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"bV" = ( +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"cu" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 6 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"cW" = ( +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"eb" = ( +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"eN" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"fp" = ( +/obj/effect/turf_decal/siding/dark_green/end{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"gs" = ( +/obj/effect/turf_decal/siding/blue/end{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"hk" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing{ + dir = 1 + }, +/turf/open/chasm, +/area/deathmatch) +"jb" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"jl" = ( +/obj/effect/turf_decal/siding/blue, +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"kR" = ( +/turf/open/chasm, +/area/deathmatch) +"kS" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"lq" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"lD" = ( +/obj/effect/turf_decal/siding/dark_red/corner, +/turf/open/indestructible/large, +/area/deathmatch) +"lJ" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 8 + }, +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"ok" = ( +/obj/effect/turf_decal/siding/dark_red/end{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"os" = ( +/obj/effect/turf_decal/siding/dark_green, +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"ou" = ( +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"oE" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 1 + }, +/obj/effect/turf_decal/siding/dark_red, +/turf/open/indestructible/large, +/area/deathmatch) +"oX" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"pg" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"pE" = ( +/obj/effect/turf_decal/siding/dark_green, +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"qg" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"qm" = ( +/obj/effect/turf_decal/siding/yellow, +/turf/open/indestructible/large, +/area/deathmatch) +"ry" = ( +/obj/effect/turf_decal/siding/blue/corner{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"rS" = ( +/obj/effect/turf_decal/siding/dark_red/end, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"sb" = ( +/obj/effect/turf_decal/siding/yellow/end{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"sL" = ( +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/yellow{ + dir = 5 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"tB" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing{ + dir = 8 + }, +/turf/open/chasm, +/area/deathmatch) +"tF" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"vn" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"vz" = ( +/obj/effect/turf_decal/siding/blue/corner, +/obj/effect/turf_decal/siding/blue/corner{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"vF" = ( +/obj/effect/turf_decal/siding/dark_red, +/turf/open/indestructible/large, +/area/deathmatch) +"vV" = ( +/obj/effect/turf_decal/siding/blue/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/blue/corner{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"wl" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"xc" = ( +/obj/structure/lattice/catwalk/mining, +/turf/open/chasm, +/area/deathmatch) +"xq" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"xv" = ( +/obj/effect/turf_decal/siding/dark_red/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/dark_red/corner, +/turf/open/indestructible/large, +/area/deathmatch) +"xQ" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 10 + }, +/obj/effect/turf_decal/siding/blue/corner{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"yJ" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_red{ + dir = 8 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"zB" = ( +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/yellow{ + dir = 10 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"AS" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Bz" = ( +/obj/effect/turf_decal/siding/blue/end{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"BM" = ( +/obj/effect/turf_decal/siding/dark_red, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Cj" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Cw" = ( +/obj/effect/turf_decal/siding/dark_red/corner{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_red/corner, +/turf/open/indestructible/large, +/area/deathmatch) +"CE" = ( +/obj/effect/turf_decal/siding/dark_red, +/obj/effect/turf_decal/siding/dark_red{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"CS" = ( +/obj/effect/turf_decal/siding/yellow, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Dc" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 1 + }, +/obj/effect/turf_decal/siding/yellow, +/turf/open/indestructible/large, +/area/deathmatch) +"Df" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 10 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Ei" = ( +/obj/effect/turf_decal/siding/dark_red/corner, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Es" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Ev" = ( +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Fd" = ( +/turf/open/indestructible/light, +/area/deathmatch) +"FB" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing{ + dir = 4 + }, +/turf/open/chasm, +/area/deathmatch) +"Ge" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 4 + }, +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Hg" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Hm" = ( +/obj/effect/turf_decal/siding/dark_green, +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"HM" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_red{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Ij" = ( +/obj/effect/turf_decal/siding/dark_green/end{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"IP" = ( +/obj/effect/turf_decal/siding/dark_green/corner, +/obj/effect/turf_decal/siding/dark_green{ + dir = 9 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Jq" = ( +/obj/effect/turf_decal/siding/blue, +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Jw" = ( +/obj/effect/turf_decal/siding/yellow, +/obj/effect/turf_decal/siding/yellow{ + dir = 1 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"JS" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 5 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Kn" = ( +/obj/effect/turf_decal/siding/blue, +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Ks" = ( +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"KH" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"KT" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"LD" = ( +/obj/structure/lattice/catwalk/mining, +/obj/structure/railing, +/turf/open/chasm, +/area/deathmatch) +"LY" = ( +/obj/effect/turf_decal/siding/blue/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/blue{ + dir = 5 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"NE" = ( +/obj/effect/turf_decal/siding/dark_red/corner{ + dir = 1 + }, +/obj/effect/turf_decal/siding/dark_red{ + dir = 6 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"NN" = ( +/obj/effect/turf_decal/siding/dark_red{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Pg" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Qn" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 4 + }, +/obj/effect/turf_decal/siding/dark_green{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Qy" = ( +/obj/effect/turf_decal/siding/yellow/corner, +/obj/effect/turf_decal/siding/yellow/corner{ + dir = 8 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"QA" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"QR" = ( +/obj/effect/turf_decal/siding/yellow, +/obj/effect/turf_decal/siding/yellow{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"QS" = ( +/obj/effect/turf_decal/siding/dark_red, +/obj/effect/turf_decal/siding/dark_red{ + dir = 1 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"TA" = ( +/obj/effect/turf_decal/siding/yellow, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"TB" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 1 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Uc" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/obj/effect/turf_decal/siding/yellow{ + dir = 4 + }, +/obj/effect/landmark/deathmatch_player_spawn, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Vh" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Vn" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 6 + }, +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 1 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"VH" = ( +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 8 + }, +/obj/effect/turf_decal/siding/dark_green/corner{ + dir = 1 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"VK" = ( +/obj/effect/turf_decal/siding/dark_red, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Wr" = ( +/obj/effect/turf_decal/siding/dark_green{ + dir = 9 + }, +/obj/effect/light_emitter/thunderdome, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"Wz" = ( +/obj/effect/turf_decal/siding/dark_red/corner, +/obj/effect/turf_decal/siding/dark_red{ + dir = 9 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"XR" = ( +/obj/effect/turf_decal/siding/blue{ + dir = 8 + }, +/obj/effect/turf_decal/siding/blue{ + dir = 4 + }, +/turf/open/indestructible/large, +/area/deathmatch) +"Yd" = ( +/obj/effect/turf_decal/siding/yellow{ + dir = 8 + }, +/obj/effect/turf_decal/siding/yellow{ + dir = 4 + }, +/turf/open/indestructible/dark/smooth_large, +/area/deathmatch) +"YI" = ( +/obj/structure/lattice, +/turf/open/chasm, +/area/deathmatch) + +(1,1,1) = {" +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +"} +(2,1,1) = {" +kR +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +kR +kR +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +kR +"} +(3,1,1) = {" +kR +Fd +Wz +HM +HM +HM +HM +yJ +HM +HM +rS +Fd +Fd +gs +vn +vn +eN +vn +vn +vn +vn +xQ +Fd +kR +"} +(4,1,1) = {" +kR +Fd +CE +lD +NN +NN +NN +NN +NN +NN +Cw +NN +QA +vz +QA +QA +QA +QA +QA +QA +ry +jl +Fd +kR +"} +(5,1,1) = {" +kR +Fd +CE +vF +Fd +FB +FB +xc +FB +Fd +oE +Ei +bF +Jq +Fd +FB +xc +FB +FB +Fd +wl +jl +Fd +kR +"} +(6,1,1) = {" +kR +Fd +CE +vF +LD +kR +kR +YI +kR +hk +oE +VK +oX +Jq +LD +kR +YI +kR +kR +hk +wl +jl +Fd +kR +"} +(7,1,1) = {" +kR +Fd +CE +vF +LD +kR +kR +YI +kR +hk +oE +BM +TB +Jq +LD +kR +YI +kR +kR +hk +wl +jl +Fd +kR +"} +(8,1,1) = {" +kR +Fd +QS +vF +xc +YI +YI +YI +YI +xc +oE +BM +TB +Jq +xc +YI +YI +YI +YI +xc +wl +Kn +Fd +kR +"} +(9,1,1) = {" +kR +Fd +CE +vF +LD +kR +kR +YI +kR +hk +oE +VK +oX +Jq +LD +kR +YI +kR +kR +hk +wl +jl +Fd +kR +"} +(10,1,1) = {" +kR +Fd +CE +vF +Fd +tB +tB +xc +tB +Fd +oE +VK +oX +Jq +Fd +tB +xc +tB +tB +Fd +wl +jl +Fd +kR +"} +(11,1,1) = {" +kR +Fd +ok +xv +lJ +lJ +lJ +lJ +lJ +lJ +NE +VK +oX +LY +XR +XR +XR +XR +XR +XR +vV +Bz +Fd +kR +"} +(12,1,1) = {" +kR +kR +Fd +vF +Ei +Cj +KH +KH +Cj +Cj +Cj +cu +JS +lq +lq +lq +jb +jb +lq +bF +wl +Fd +kR +kR +"} +(13,1,1) = {" +kR +kR +Fd +qm +Ks +Vh +KT +KT +Vh +Vh +Vh +Df +Wr +qg +qg +qg +xq +xq +qg +eb +pg +Fd +kR +kR +"} +(14,1,1) = {" +kR +Fd +sb +Qy +Ge +Ge +Ge +Ge +Ge +Ge +zB +CS +Pg +IP +Qn +Qn +Qn +Qn +Qn +Qn +ou +fp +Fd +kR +"} +(15,1,1) = {" +kR +Fd +QR +qm +Fd +FB +FB +xc +FB +Fd +Dc +CS +Pg +pE +Fd +FB +xc +FB +FB +Fd +pg +os +Fd +kR +"} +(16,1,1) = {" +kR +Fd +QR +qm +LD +kR +kR +YI +kR +hk +Dc +CS +Pg +pE +LD +kR +YI +kR +kR +hk +pg +os +Fd +kR +"} +(17,1,1) = {" +kR +Fd +Jw +qm +xc +YI +YI +YI +YI +xc +Dc +TA +Es +pE +xc +YI +YI +YI +YI +xc +pg +Hm +Fd +kR +"} +(18,1,1) = {" +kR +Fd +QR +qm +LD +kR +kR +YI +kR +hk +Dc +TA +Es +pE +LD +kR +YI +kR +kR +hk +pg +os +Fd +kR +"} +(19,1,1) = {" +kR +Fd +QR +qm +LD +kR +kR +YI +kR +hk +Dc +CS +Pg +pE +LD +kR +YI +kR +kR +hk +pg +os +Fd +kR +"} +(20,1,1) = {" +kR +Fd +QR +qm +Fd +tB +tB +xc +tB +Fd +Dc +Ks +eb +pE +Fd +tB +xc +tB +tB +Fd +pg +os +Fd +kR +"} +(21,1,1) = {" +kR +Fd +QR +Ev +Hg +Hg +Hg +Hg +Hg +Hg +bV +Hg +AS +VH +AS +AS +AS +AS +AS +AS +cW +os +Fd +kR +"} +(22,1,1) = {" +kR +Fd +sL +Yd +Yd +Yd +Yd +Uc +Yd +Yd +ae +Fd +Fd +Ij +kS +kS +tF +kS +kS +kS +kS +Vn +Fd +kR +"} +(23,1,1) = {" +kR +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +kR +kR +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +Fd +kR +"} +(24,1,1) = {" +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +kR +"} diff --git a/code/game/turfs/open/_open.dm b/code/game/turfs/open/_open.dm index b61fffd944e94..8270e3d791a90 100644 --- a/code/game/turfs/open/_open.dm +++ b/code/game/turfs/open/_open.dm @@ -157,6 +157,9 @@ /turf/open/indestructible/light icon_state = "light_on-1" + light_range = 3 + light_color = LIGHT_COLOR_CYAN + light_on = TRUE /turf/open/indestructible/permalube icon_state = "darkfull" diff --git a/code/modules/deathmatch/deathmatch_loadouts.dm b/code/modules/deathmatch/deathmatch_loadouts.dm index ae5f22975a031..9e86bf9befbb7 100644 --- a/code/modules/deathmatch/deathmatch_loadouts.dm +++ b/code/modules/deathmatch/deathmatch_loadouts.dm @@ -543,3 +543,204 @@ granted_spells = list( /datum/action/cooldown/spell/conjure/simian, ) + +/datum/outfit/deathmatch_loadout/head_of_security + name = "Deathmatch: Head of Security" + display_name = "Head of Security" + desc = "Finally, nobody to stop the power from going to your head." + + head = /datum/outfit/job/hos::head + ears = /datum/outfit/job/hos::ears + uniform = /obj/item/clothing/under/rank/security/head_of_security/alt + shoes = /datum/outfit/job/hos::shoes + neck = /datum/outfit/job/hos::neck + glasses = /datum/outfit/job/hos::glasses + suit = /obj/item/clothing/suit/armor/hos/hos_formal + suit_store = /obj/item/gun/ballistic/shotgun/automatic/combat/compact + gloves = /obj/item/clothing/gloves/tackler/combat + belt = /obj/item/gun/energy/e_gun/hos + r_hand = /obj/item/melee/baton/security/loaded + l_hand = /obj/item/shield/riot/tele + l_pocket = /obj/item/grenade/flashbang + r_pocket = /obj/item/restraints/legcuffs/bola/energy + +/datum/outfit/deathmatch_loadout/captain + name = "Deathmatch: Captain" + display_name = "Captain" + desc = "Draw your sword and show the syndicate scum no quarter." + + head = /obj/item/clothing/head/hats/caphat/parade + ears = /obj/item/radio/headset/heads/captain/alt + uniform = /obj/item/clothing/under/rank/captain + suit = /obj/item/clothing/suit/armor/vest/capcarapace/captains_formal + suit_store = /obj/item/gun/energy/e_gun + shoes = /obj/item/clothing/shoes/laceup + neck = /obj/item/bedsheet/captain + glasses = /obj/item/clothing/glasses/sunglasses + gloves = /obj/item/clothing/gloves/captain + belt = /obj/item/storage/belt/sabre + l_hand = /obj/item/gun/energy/laser/captain + r_pocket = /obj/item/assembly/flash + l_pocket = /obj/item/melee/baton/telescopic + +/datum/outfit/deathmatch_loadout/traitor + name = "Deathmatch: Traitor" + display_name = "Traitor" + desc = "The classic; energy sword & energy bow, donning a reflector trenchcoat (stolen)." + + head = /obj/item/clothing/head/chameleon + uniform = /obj/item/clothing/under/chameleon + mask = /obj/item/clothing/mask/chameleon + suit = /obj/item/clothing/suit/hooded/ablative + shoes = /obj/item/clothing/shoes/chameleon/noslip + glasses = /obj/item/clothing/glasses/thermal/syndi + gloves = /obj/item/clothing/gloves/combat + suit_store = /obj/item/gun/energy/recharge/ebow + l_hand = /obj/item/melee/energy/sword + r_pocket = /obj/item/reagent_containers/hypospray/medipen/stimulants + l_pocket = /obj/item/soap/syndie + belt = /obj/item/gun/ballistic/revolver/syndicate + +/datum/outfit/deathmatch_loadout/nukie + name = "Deathmatch: Nuclear Operative" + display_name = "Nuclear Operative" + desc = "Gear afforded to Lone Operatives. Your mission is simple." + + uniform = /obj/item/clothing/under/syndicate/tacticool + back = /obj/item/mod/control/pre_equipped/nuclear + r_hand = /obj/item/gun/ballistic/shotgun/bulldog/unrestricted + belt = /obj/item/gun/ballistic/automatic/pistol/clandestine + r_pocket = /obj/item/reagent_containers/hypospray/medipen/stimulants + l_pocket = /obj/item/grenade/syndieminibomb + implants = list(/obj/item/implant/explosive) + + backpack_contents = list( + /obj/item/ammo_box/c10mm, + /obj/item/ammo_box/magazine/m12g = 2, + /obj/item/pen/edagger, + /obj/item/reagent_containers/hypospray/medipen/atropine, + ) + +/datum/outfit/deathmatch_loadout/pete + name = "Deathmatch: Cuban Pete" + display_name = "Disciple of Pete" + desc = "You took a lesson from Cuban Pete." + + back = /obj/item/storage/backpack/santabag + head = /obj/item/clothing/head/collectable/petehat + uniform = /obj/item/clothing/under/pants/camo + suit = /obj/item/clothing/suit/costume/poncho + belt = /obj/item/storage/belt/grenade/full + shoes = /obj/item/clothing/shoes/workboots + l_hand = /obj/item/reagent_containers/cup/glass/bottle/rum + r_hand = /obj/item/sbeacondrop/bomb + l_pocket = /obj/item/grenade/syndieminibomb + r_pocket = /obj/item/grenade/syndieminibomb + implants = list(/obj/item/implanter/explosive_macro) + backpack_contents = list( + /obj/item/assembly/signaler = 10, + ) + +/datum/outfit/deathmatch_loadout/tider + name = "Deathmatch: Tider" + display_name = "Tider" + desc = "A very high power level Assistant." + + back = /obj/item/melee/baton/security/cattleprod + r_hand = /obj/item/fireaxe + uniform = /obj/item/clothing/under/color/grey/ancient + mask = /obj/item/clothing/mask/gas + shoes = /obj/item/clothing/shoes/sneakers/black + gloves = /obj/item/clothing/gloves/cut + l_pocket = /obj/item/reagent_containers/hypospray/medipen/methamphetamine + r_pocket = /obj/item/stock_parts/cell/high + belt = /obj/item/storage/belt/utility/full + +/datum/outfit/deathmatch_loadout/abductor + name = "Deathmatch: Abductor" + display_name = "Abductor" + desc = "We come in peace." + + species_override = /datum/species/abductor + uniform = /obj/item/clothing/under/abductor + head = /obj/item/clothing/head/helmet/abductor + suit = /obj/item/clothing/suit/armor/abductor/vest + l_pocket = /obj/item/reagent_containers/hypospray/medipen/atropine + r_pocket = /obj/item/grenade/gluon + l_hand = /obj/item/gun/energy/alien + r_hand = /obj/item/gun/energy/alien + belt = /obj/item/gun/energy/shrink_ray + +/datum/outfit/deathmatch_loadout/battler/clown/upgraded + name = "Deathmatch: Clown (Syndicate Gear)" + display_name = "Clown" + desc = "They were bound to show up sooner or later." + + shoes = /obj/item/clothing/shoes/clown_shoes/combat + r_hand = /obj/item/pneumatic_cannon/pie/selfcharge + l_hand = /obj/item/bikehorn/golden + box = /obj/item/storage/box/hug/reverse_revolver + + backpack_contents = list( + /obj/item/paperplane/syndicate = 1, + /obj/item/restraints/legcuffs/bola/tactical = 1, + /obj/item/restraints/legcuffs/beartrap = 1, + /obj/item/food/grown/banana = 1, + /obj/item/food/pie/cream = 1, + /obj/item/dnainjector/clumsymut, + /obj/item/sbeacondrop/clownbomb, + ) + +/datum/outfit/deathmatch_loadout/mime + name = "Deathmatch: Mime" + display_name = "Mime" + desc = "..." + + uniform = /datum/outfit/job/mime::uniform + belt = /obj/item/food/baguette/combat + head = /datum/outfit/job/mime::head + shoes = /datum/outfit/job/mime::shoes + mask = /datum/outfit/job/mime::mask + back = /datum/outfit/job/mime::backpack + box = /datum/outfit/job/mime::box + l_pocket = /obj/item/toy/crayon/spraycan/mimecan + r_pocket = /obj/item/food/grown/banana/mime + neck = /datum/outfit/job/mime::neck + gloves = /datum/outfit/job/mime::gloves + + backpack_contents = list( + /obj/item/reagent_containers/cup/glass/bottle/bottleofnothing, + /obj/item/gun/ballistic/automatic/pistol, + /obj/item/suppressor, + /obj/item/ammo_box/c9mm, + /obj/item/food/croissant/throwing = 2, + ) + + granted_spells = list( + /datum/action/cooldown/spell/vow_of_silence, + /datum/action/cooldown/spell/conjure_item/invisible_box, + /datum/action/cooldown/spell/conjure/invisible_chair, + /datum/action/cooldown/spell/conjure/invisible_wall, + /datum/action/cooldown/spell/forcewall/mime, + /datum/action/cooldown/spell/pointed/projectile/finger_guns, + ) + +/datum/outfit/deathmatch_loadout/chef/upgraded + name = "Deathmatch: Master Chef" + display_name = "Chef" + desc = "Let him cook." + + belt = /obj/item/gun/magic/hook + uniform = /obj/item/clothing/under/costume/buttondown/slacks/service + suit = /obj/item/clothing/suit/toggle/chef + suit_store = /obj/item/knife/kitchen + head = /obj/item/clothing/head/utility/chefhat + mask = /obj/item/clothing/mask/fakemoustache/italian + gloves = /obj/item/clothing/gloves/the_sleeping_carp + back = /obj/item/storage/backpack + + backpack_contents = list( + /obj/item/pizzabox/bomb/armed = 3, + /obj/item/knife/butcher, + /obj/item/sharpener, + ) diff --git a/code/modules/deathmatch/deathmatch_maps.dm b/code/modules/deathmatch/deathmatch_maps.dm index b2396915473c6..6a8a245abb795 100644 --- a/code/modules/deathmatch/deathmatch_maps.dm +++ b/code/modules/deathmatch/deathmatch_maps.dm @@ -185,5 +185,24 @@ key = "train" turf_reservation_type = /datum/turf_reservation/indestructible_plating +/datum/lazy_template/deathmatch/finaldestination + name = "Final Destination" + desc = "1v1v1v1, 1 Stock, Final Destination." + max_players = 8 + allowed_loadouts = list( + /datum/outfit/deathmatch_loadout/captain, + /datum/outfit/deathmatch_loadout/head_of_security, + /datum/outfit/deathmatch_loadout/traitor, + /datum/outfit/deathmatch_loadout/nukie, + /datum/outfit/deathmatch_loadout/tider, + /datum/outfit/deathmatch_loadout/abductor, + /datum/outfit/deathmatch_loadout/chef/upgraded, + /datum/outfit/deathmatch_loadout/battler/clown/upgraded, + /datum/outfit/deathmatch_loadout/mime, + /datum/outfit/deathmatch_loadout/pete, + ) + map_name = "finaldestination" + key = "finaldestination" + /datum/turf_reservation/indestructible_plating turf_type = /turf/open/indestructible/plating //a little hacky but i guess it has to be done From 108880a1e65f3899a9b6912afa1ee2c575ba91b5 Mon Sep 17 00:00:00 2001 From: Time-Green <7501474+Time-Green@users.noreply.github.com> Date: Fri, 7 Jun 2024 19:40:05 +0200 Subject: [PATCH 65/81] Sneeze Rework: Projectile Combat Edition (#83361) ## About The Pull Request Reworks sneezing. Instead of a range check that checks if you're facing someone, it is now a skill check https://github.com/tgstation/tgstation/assets/7501474/c11ffa16-9bd2-4ed1-8022-2094360657bc All sneezes shoot projectiles, but depends on the virus if they're infectious. Using the sneeze emote is the only method that doesn't shoot a sneeze ## Why It's Good For The Game I think the invisible infection mechanics are unfun. A lot of station dangers challenge your knowledge and mechanical skill, while viruses are gotten by being around people in a roleplay game. You can get a round seriously ruined if you walk past someone with a sneezing virus and don't immediately rush spaceillin or chemistry, which I don't think is mechanically interesting. Now if you get infected, it's a skill issue. Get good and dodge the sneeze Note that this is just one method of infection. I didn't touch coughing and airborne viruses, which do constant area checks and infect everyone around. I plan to, but not now. I'll probably make coughing do a cone or something, and ignore the airborne viruses since they can't be modified and are generally less broken ## Changelog :cl: balance: You can now dodge sneezes balance: Infectious simple diseases that use sneezes now infect with sneezes and have lowered airborn transmission balance: Damageless attacks, projectiles, hugs etc no longer drain shields /:cl: - [x] Make sneezes shoot to your cursor so you can either intentionally sneeze on people or sneeze away from people if you react fast --------- Co-authored-by: MrMelbert <51863163+MrMelbert@users.noreply.github.com> --- code/datums/components/shielded.dm | 6 ++ code/datums/diseases/_disease.dm | 1 - .../diseases/advance/symptoms/sneeze.dm | 5 +- code/datums/diseases/cold.dm | 6 +- code/datums/diseases/cold9.dm | 4 +- code/datums/diseases/dna_spread.dm | 2 +- code/datums/diseases/fake_gbs.dm | 2 +- code/datums/diseases/flu.dm | 6 +- code/datums/diseases/fluspanish.dm | 6 +- code/datums/diseases/wizarditis.dm | 2 +- code/datums/status_effects/debuffs/debuffs.dm | 5 +- code/game/objects/effects/cursor_catcher.dm | 4 +- code/modules/events/fake_virus.dm | 2 +- .../carbon/alien/special/alien_embryo.dm | 4 +- code/modules/mob/living/sneeze.dm | 75 ++++++++++++++++++ .../reagents/drinks/drink_reagents.dm | 2 +- .../chemistry/reagents/toxin_reagents.dm | 2 +- icons/obj/weapons/guns/projectiles.dmi | Bin 139544 -> 139639 bytes tgstation.dme | 1 + 19 files changed, 109 insertions(+), 26 deletions(-) create mode 100644 code/modules/mob/living/sneeze.dm diff --git a/code/datums/components/shielded.dm b/code/datums/components/shielded.dm index f35ad2ceec0c4..da83c4ad2d29d 100644 --- a/code/datums/components/shielded.dm +++ b/code/datums/components/shielded.dm @@ -28,6 +28,9 @@ var/show_charge_as_alpha = FALSE /// The item we use for recharging var/recharge_path + /// Whether or not we lose a charge when hit by 0 damage items or projectiles + var/lose_charge_on_damageless = FALSE + /// The cooldown tracking when we were last hit COOLDOWN_DECLARE(recently_hit_cd) /// The cooldown tracking when we last replenished a charge @@ -172,6 +175,9 @@ if(lose_multiple_charges) // if the shield has health like damage we'll lose charges equal to the damage of the hit charge_loss = damage + else if(!lose_charge_on_damageless && !damage) + charge_loss = 0 + adjust_charge(-charge_loss) INVOKE_ASYNC(src, PROC_REF(actually_run_hit_callback), owner, attack_text, current_charges) diff --git a/code/datums/diseases/_disease.dm b/code/datums/diseases/_disease.dm index d66bc85bb55ae..639637af1d7e9 100644 --- a/code/datums/diseases/_disease.dm +++ b/code/datums/diseases/_disease.dm @@ -288,7 +288,6 @@ return FALSE end = Temp - /datum/disease/proc/cure(add_resistance = TRUE) if(severity == DISEASE_SEVERITY_UNCURABLE) //aw man :( return diff --git a/code/datums/diseases/advance/symptoms/sneeze.dm b/code/datums/diseases/advance/symptoms/sneeze.dm index a35e700f7b4ef..0e54bfad385e0 100644 --- a/code/datums/diseases/advance/symptoms/sneeze.dm +++ b/code/datums/diseases/advance/symptoms/sneeze.dm @@ -53,15 +53,14 @@ if(!suppress_warning) affected_mob.emote("sniff") else - active_disease.airborne_spread(spread_range, force_spread = TRUE, require_facing = TRUE) + if(affected_mob.can_spread_airborne_diseases()) //don't spread germs if they covered their mouth + affected_mob.infectious_sneeze(active_disease, TRUE, range = spread_range) if(cartoon_sneezing) //Yeah, this can fling you around even if you have a space suit helmet on. It's, uh, bluespace snot, yeah. - affected_mob.emote("sneeze") to_chat(affected_mob, span_userdanger("You are launched violently backwards by an all-mighty sneeze!")) var/sneeze_distance = rand(2,4) //twice as far as a normal baseball bat strike will fling you var/turf/target = get_ranged_target_turf(affected_mob, REVERSE_DIR(affected_mob.dir), sneeze_distance) affected_mob.throw_at(target, sneeze_distance, rand(1,4)) //with the wounds update, sneezing at 7 speed was causing peoples bones to spontaneously explode, turning cartoonish sneezing into a nightmarishly lethal GBS 2.0 outbreak else if(COOLDOWN_FINISHED(src, sneeze_cooldown) || !COOLDOWN_FINISHED(src, sneeze_cooldown) && prob(60) && !off_cooldown_sneezed) - affected_mob.emote("sneeze") COOLDOWN_START(src, sneeze_cooldown, 5 SECONDS) if(!off_cooldown_sneezed && !COOLDOWN_FINISHED(src, sneeze_cooldown)) off_cooldown_sneezed = TRUE diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm index f7bf6cf4b18a7..3b361e53c236c 100644 --- a/code/datums/diseases/cold.dm +++ b/code/datums/diseases/cold.dm @@ -6,7 +6,7 @@ cures = list(/datum/reagent/medicine/spaceacillin) agent = "XY-rhinovirus" viable_mobtypes = list(/mob/living/carbon/human) - spreading_modifier = 0.5 + spreading_modifier = 0.1 spread_text = "Airborne" severity = DISEASE_SEVERITY_NONTHREAT required_organ = ORGAN_SLOT_LUNGS @@ -20,7 +20,7 @@ switch(stage) if(2) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) @@ -33,7 +33,7 @@ return FALSE if(3) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) diff --git a/code/datums/diseases/cold9.dm b/code/datums/diseases/cold9.dm index 2e55df23b7ec8..97adebcac7026 100644 --- a/code/datums/diseases/cold9.dm +++ b/code/datums/diseases/cold9.dm @@ -20,7 +20,7 @@ if(2) affected_mob.adjust_bodytemperature(-5 * seconds_per_tick) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) @@ -34,7 +34,7 @@ if(3) affected_mob.adjust_bodytemperature(-10 * seconds_per_tick) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) diff --git a/code/datums/diseases/dna_spread.dm b/code/datums/diseases/dna_spread.dm index 6fd926f60d3df..e649a557443f1 100644 --- a/code/datums/diseases/dna_spread.dm +++ b/code/datums/diseases/dna_spread.dm @@ -40,7 +40,7 @@ switch(stage) if(2, 3) //Pretend to be a cold and give time to spread. if(SPT_PROB(4, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.sneeze() if(SPT_PROB(4, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) diff --git a/code/datums/diseases/fake_gbs.dm b/code/datums/diseases/fake_gbs.dm index 655439cdc6cc5..939ab620feff4 100644 --- a/code/datums/diseases/fake_gbs.dm +++ b/code/datums/diseases/fake_gbs.dm @@ -19,7 +19,7 @@ switch(stage) if(2) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.sneeze() if(3) if(SPT_PROB(2.5, seconds_per_tick)) affected_mob.emote("cough") diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm index 9412d2a2a2f63..4ad7bb9b92b59 100644 --- a/code/datums/diseases/flu.dm +++ b/code/datums/diseases/flu.dm @@ -7,7 +7,7 @@ cure_chance = 5 agent = "H13N1 flu virion" viable_mobtypes = list(/mob/living/carbon/human) - spreading_modifier = 0.75 + spreading_modifier = 0.1 desc = "If left untreated the subject will feel quite unwell." severity = DISEASE_SEVERITY_MINOR required_organ = ORGAN_SLOT_LUNGS @@ -20,7 +20,7 @@ switch(stage) if(2) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) @@ -38,7 +38,7 @@ if(3) if(SPT_PROB(0.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(0.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) diff --git a/code/datums/diseases/fluspanish.dm b/code/datums/diseases/fluspanish.dm index 6919884b2fe30..1fa6b49d457ad 100644 --- a/code/datums/diseases/fluspanish.dm +++ b/code/datums/diseases/fluspanish.dm @@ -7,7 +7,7 @@ cure_chance = 5 agent = "1nqu1s1t10n flu virion" viable_mobtypes = list(/mob/living/carbon/human) - spreading_modifier = 0.75 + spreading_modifier = 0.1 desc = "If left untreated the subject will burn to death for being a heretic." severity = DISEASE_SEVERITY_DANGEROUS required_organ = ORGAN_SLOT_LUNGS @@ -21,7 +21,7 @@ if(2) affected_mob.adjust_bodytemperature(5 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(2.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(0.5, seconds_per_tick)) @@ -31,7 +31,7 @@ if(3) affected_mob.adjust_bodytemperature(10 * seconds_per_tick) if(SPT_PROB(2.5, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.infectious_sneeze(src, TRUE) if(SPT_PROB(2.5, seconds_per_tick)) affected_mob.emote("cough") if(SPT_PROB(2.5, seconds_per_tick)) diff --git a/code/datums/diseases/wizarditis.dm b/code/datums/diseases/wizarditis.dm index fe0502387f9e3..21dce839dc697 100644 --- a/code/datums/diseases/wizarditis.dm +++ b/code/datums/diseases/wizarditis.dm @@ -99,7 +99,7 @@ var/datum/action/cooldown/spell/picked = pick(random_spells) picked.Activate(affected_mob) - affected_mob.emote("sneeze") + affected_mob.sneeze() return /datum/disease/wizarditis/proc/spawn_wizard_clothes(chance = 0) diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm index 199840d44ec1b..30fc4a729cd98 100644 --- a/code/datums/status_effects/debuffs/debuffs.dm +++ b/code/datums/status_effects/debuffs/debuffs.dm @@ -775,7 +775,10 @@ span_userdanger(pick("Your lungs hurt!", "It hurts to breathe!")), span_warning(pick("You feel nauseated.", "You feel like you're going to throw up!"))) else - fake_emote = pick("cough", "sniff", "sneeze") + if(prob(40)) + fake_emote = "cough" + else + owner.sneeze() if(fake_emote) owner.emote(fake_emote) diff --git a/code/game/objects/effects/cursor_catcher.dm b/code/game/objects/effects/cursor_catcher.dm index 3229cd44b7083..a8c19e40be80d 100644 --- a/code/game/objects/effects/cursor_catcher.dm +++ b/code/game/objects/effects/cursor_catcher.dm @@ -8,9 +8,9 @@ var/mob/owner /// Client view size of the scoping mob. var/list/view_list - /// Pixel x we send to the scope component. + /// Pixel x relative to the hovered tile we send to the scope component. var/given_x - /// Pixel y we send to the scope component. + /// Pixel y relative to the hovered tile we send to the scope component. var/given_y /// The turf we send to the scope component. var/turf/given_turf diff --git a/code/modules/events/fake_virus.dm b/code/modules/events/fake_virus.dm index ad54347332a82..4b7886b02dad2 100644 --- a/code/modules/events/fake_virus.dm +++ b/code/modules/events/fake_virus.dm @@ -32,4 +32,4 @@ if(prob(25))//1/4 odds to get a spooky message instead of coughing out loud addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), onecoughman, span_warning("[pick("Your head hurts.", "Your head pounds.")]")), rand(3 SECONDS, 15 SECONDS)) else - addtimer(CALLBACK(onecoughman, TYPE_PROC_REF(/mob, emote), pick("cough", "sniff", "sneeze")), rand(3 SECONDS, 15 SECONDS))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time + addtimer(CALLBACK(onecoughman, TYPE_PROC_REF(/mob, emote), pick("cough", "sniff")), rand(3 SECONDS, 15 SECONDS))//deliver the message with a slightly randomized time interval so there arent multiple people coughing at the exact same time diff --git a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm index c7c4b1ed06f3e..6d1ad16c8b1c8 100644 --- a/code/modules/mob/living/carbon/alien/special/alien_embryo.dm +++ b/code/modules/mob/living/carbon/alien/special/alien_embryo.dm @@ -33,7 +33,7 @@ switch(stage) if(3, 4) if(SPT_PROB(1, seconds_per_tick)) - owner.emote("sneeze") + owner.sneeze() if(SPT_PROB(1, seconds_per_tick)) owner.emote("cough") if(SPT_PROB(1, seconds_per_tick)) @@ -42,7 +42,7 @@ to_chat(owner, span_danger("Mucous runs down the back of your throat.")) if(5) if(SPT_PROB(1, seconds_per_tick)) - owner.emote("sneeze") + owner.sneeze() if(SPT_PROB(1, seconds_per_tick)) owner.emote("cough") if(SPT_PROB(2, seconds_per_tick)) diff --git a/code/modules/mob/living/sneeze.dm b/code/modules/mob/living/sneeze.dm new file mode 100644 index 0000000000000..b2cf76c25a6b0 --- /dev/null +++ b/code/modules/mob/living/sneeze.dm @@ -0,0 +1,75 @@ +/// How many degrees, up and down, can our sneeze deviate from our facing direction? +#define SNEEZE_CONE 60 + +/// Launch a sneeze that can infect with a disease +/mob/living/proc/infectious_sneeze(datum/disease/disease, force, range = 4, count = 4, charge_time = 0.5 SECONDS, obj/projectile/sneezoid = /obj/projectile/sneeze) + sneeze(range, count, charge_time, sneezoid, on_sneeze_hit_callback = CALLBACK(src, PROC_REF(try_sneeze_infect), disease.Copy(), force)) + +/// Try and infect following a sneeze hit. force to always infect +/mob/living/proc/try_sneeze_infect(datum/disease/disease, force, mob/living/target) + target.contract_airborne_disease(disease) + +/// Inhale and start the sneeze timer. on_sneeze_callback can be used to do custom sneezes, on_sneeze_hit_callback for special effects, but probably usually making it infect +/mob/living/proc/sneeze(range = 4, count = 3, charge_time = 0.5 SECONDS, obj/projectile/sneezoid = /obj/projectile/sneeze, on_sneeze_callback = null, on_sneeze_hit_callback = null) + if(charge_time) + emote("inhale") + + clear_fullscreen("sneezer", 0) + var/atom/movable/screen/fullscreen/cursor_catcher/catcher = overlay_fullscreen("sneezer", /atom/movable/screen/fullscreen/cursor_catcher, FALSE) + if(client) + catcher.assign_to_mob(src) + var/callback = on_sneeze_callback || CALLBACK(src, PROC_REF(launch_sneeze), range, count, sneezoid, on_sneeze_hit_callback, catcher) + addtimer(callback, charge_time) + +/// Shoot the sneeze projectile +/mob/living/proc/launch_sneeze(range, count, obj/projectile/sneezoid, datum/callback/on_sneeze_hit_callback, atom/movable/screen/fullscreen/cursor_catcher/catcher) + emote("sneeze") + + var/angle = dir2angle(dir) + + if(catcher && catcher.given_turf) + catcher.calculate_params() + /// Take the target and subtract self for relative grid position. Then take the pixel x on the tile and divide by the tiles pixel size, and add 0.5 so it's fired from the center + var/sneeze_x = catcher.given_turf.x - x + catcher.given_x / world.icon_size - 0.5 + var/sneeze_y = catcher.given_turf.y - y + catcher.given_y / world.icon_size - 0.5 + angle = ATAN2(sneeze_y, sneeze_x) + + // Check if we're within the sneeze cone, otherwise just sneeze straight + if(abs(closer_angle_difference(angle, dir2angle(dir) - SNEEZE_CONE)) + abs(closer_angle_difference(angle, dir2angle(dir) + SNEEZE_CONE)) > 2 * SNEEZE_CONE) + angle = dir2angle(dir) + + clear_fullscreen("sneezer", 0) + + for(var/i in 0 to count) + var/obj/projectile/sneezium = new sneezoid(get_turf(src), on_sneeze_hit_callback) + sneezium.range = range + sneezium.firer = src + sneezium.fire(angle) + +/// Sneeze projectile launched by sneezing. gross +/obj/projectile/sneeze + name = "sneeze" + icon_state = "sneeze" + + suppressed = SUPPRESSED_VERY + range = 4 + speed = 4 + spread = 40 + damage_type = BRUTE + damage = 0 + + /// Call this when we hit something + var/datum/callback/sneezie_callback + +/obj/projectile/sneeze/Initialize(mapload, callback) + . = ..() + + sneezie_callback = callback + +/obj/projectile/sneeze/on_hit(atom/target, blocked, pierce_hit) + . = ..() + + if(isliving(target)) + sneezie_callback?.Invoke(target) //you've been sneezered + +#undef SNEEZE_CONE diff --git a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm index ec0c316c45825..d3070474558d7 100644 --- a/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/drinks/drink_reagents.dm @@ -1066,7 +1066,7 @@ affected_mob.update_transform(newsize/current_size) current_size = newsize if(SPT_PROB(23, seconds_per_tick)) - affected_mob.emote("sneeze") + affected_mob.sneeze() /datum/reagent/consumable/red_queen/on_mob_end_metabolize(mob/living/affected_mob) . = ..() diff --git a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm index bcdee284bd78b..15508aa98eecd 100644 --- a/code/modules/reagents/chemistry/reagents/toxin_reagents.dm +++ b/code/modules/reagents/chemistry/reagents/toxin_reagents.dm @@ -604,7 +604,7 @@ if(2) affected_mob.emote("cough") if(3) - affected_mob.emote("sneeze") + affected_mob.sneeze() if(4) if(prob(75)) to_chat(affected_mob, span_danger("You scratch at an itch.")) diff --git a/icons/obj/weapons/guns/projectiles.dmi b/icons/obj/weapons/guns/projectiles.dmi index b4056f661b8d30482dad2dc04f02656781d2b1e7..120a4c12cd3d9b36a65253ec66e1cc39457998e0 100644 GIT binary patch delta 23788 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 Q0s)^pw~ck)X*q`dAJ-z2hX4Qo delta 23721 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 diff --git a/tgstation.dme b/tgstation.dme index 2d6dbda22bc66..ab21c37773105 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -4618,6 +4618,7 @@ #include "code\modules\mob\living\login.dm" #include "code\modules\mob\living\logout.dm" #include "code\modules\mob\living\navigation.dm" +#include "code\modules\mob\living\sneeze.dm" #include "code\modules\mob\living\status_procs.dm" #include "code\modules\mob\living\taste.dm" #include "code\modules\mob\living\ventcrawling.dm" From 6187b64ef999926df704193e00fb479cf6fd4475 Mon Sep 17 00:00:00 2001 From: Rhials <28870487+Rhials@users.noreply.github.com> Date: Fri, 7 Jun 2024 13:41:33 -0400 Subject: [PATCH 66/81] [NO GBP] Only filled graves will provide a mood modifier (#83752) ## About The Pull Request Only the "filled" subtype of graves will provide a mood debuff (buff if you're a coroner). This means that graves that spawn with loot/remains, such as the two featured on the icebox coroner graveyard or the ones in the Elephant Graveyard Lavaland ruin, will impact your mood. The unfilled graves at the icebox chapel/morgue will not affect mood, nor will recently created ones. ![image](https://github.com/tgstation/tgstation/assets/28870487/2722e454-0b73-48f8-bcb5-e12f682eec23) ## Why It's Good For The Game It makes a bit more sense. You shouldn't be beating yourself up over graverobbing when you aren't actually disturbing anyone's grave, especially when it lines up with what the actual mood event text says. Closes #83704. ## Changelog :cl: Rhials fix: Only filled graves will impact your mood. /:cl: --- .../mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm index 19dbc76a32f76..3bb1fb48e599a 100644 --- a/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm +++ b/code/modules/mapfluff/ruins/lavalandruin_code/elephantgraveyard.dm @@ -160,6 +160,8 @@ var/first_open = FALSE /// was a shovel used to close this grave var/dug_closed = FALSE + /// do we have a mood effect tied to accessing this type of grave? + var/affect_mood = FALSE /obj/structure/closet/crate/grave/add_context(atom/source, list/context, obj/item/held_item, mob/user) if(isnull(held_item)) @@ -180,6 +182,9 @@ . = ..() . += span_notice("It can be [EXAMINE_HINT((opened ? "closed" : "dug open"))] with a shovel.") +/obj/structure/closet/crate/grave/filled + affect_mood = TRUE + /obj/structure/closet/crate/grave/filled/PopulateContents() //GRAVEROBBING IS NOW A FEATURE ..() new /obj/effect/decal/remains/human(src) @@ -252,7 +257,7 @@ if(opened) dug_closed = TRUE close(user) - else if(open(user, force = TRUE)) + else if(open(user, force = TRUE) && affect_mood) if(HAS_MIND_TRAIT(user, TRAIT_MORBID)) user.add_mood_event("morbid_graverobbing", /datum/mood_event/morbid_graverobbing) else From dd9504d4c2cc6ae1a5b3b28662d80876fe53038b Mon Sep 17 00:00:00 2001 From: lizelive Date: Fri, 7 Jun 2024 10:42:46 -0700 Subject: [PATCH 67/81] remove human requirement for invisible_wall (#83751) mime borg is hilarious ## About The Pull Request remove human requirement for invisible_wall ## Why It's Good For The Game mime borg is hilarious ## Changelog :cl: balance: remove human requirement for invisible wall /:cl: --- code/modules/spells/spell_types/conjure/invisible_wall.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/spells/spell_types/conjure/invisible_wall.dm b/code/modules/spells/spell_types/conjure/invisible_wall.dm index a61db7cf74e19..d2812912f0fc2 100644 --- a/code/modules/spells/spell_types/conjure/invisible_wall.dm +++ b/code/modules/spells/spell_types/conjure/invisible_wall.dm @@ -15,7 +15,7 @@ invocation_self_message = span_notice("You form a wall in front of yourself.") invocation_type = INVOCATION_EMOTE - spell_requirements = SPELL_REQUIRES_HUMAN|SPELL_REQUIRES_MIME_VOW + spell_requirements = SPELL_REQUIRES_MIME_VOW antimagic_flags = NONE spell_max_level = 1 From 522adb35729c99c2206faace5b9c2a5ea11bc15e Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:44:52 +1200 Subject: [PATCH 68/81] Automatic changelog for PR #83765 [ci skip] --- html/changelogs/AutoChangeLog-pr-83765.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83765.yml diff --git a/html/changelogs/AutoChangeLog-pr-83765.yml b/html/changelogs/AutoChangeLog-pr-83765.yml new file mode 100644 index 0000000000000..d8b3ec6094c96 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83765.yml @@ -0,0 +1,5 @@ +author: "EnterTheJake" +delete-after: True +changes: + - balance: "Rust walkers' summoning ritual now requires 5 sheets of Titanium instead of Iron." + - bugfix: "Magic resistance grants complete immunity from the passive disgust buildup from standing on Rusted turfs." \ No newline at end of file From 144d5ba41669e07c4b0eb3c00b65fe09f19a6ac7 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:47:01 +1200 Subject: [PATCH 69/81] Automatic changelog for PR #83759 [ci skip] --- html/changelogs/AutoChangeLog-pr-83759.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83759.yml diff --git a/html/changelogs/AutoChangeLog-pr-83759.yml b/html/changelogs/AutoChangeLog-pr-83759.yml new file mode 100644 index 0000000000000..476baef853f30 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83759.yml @@ -0,0 +1,4 @@ +author: "projectkepler-ru" +delete-after: True +changes: + - bugfix: "smoking pipe not showing sprite when lit" \ No newline at end of file From 3763a0a7d977d7381b77de34359f75e1dba23da3 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 05:51:10 +1200 Subject: [PATCH 70/81] Automatic changelog for PR #83752 [ci skip] --- html/changelogs/AutoChangeLog-pr-83752.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83752.yml diff --git a/html/changelogs/AutoChangeLog-pr-83752.yml b/html/changelogs/AutoChangeLog-pr-83752.yml new file mode 100644 index 0000000000000..0bbc484dd59f9 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83752.yml @@ -0,0 +1,4 @@ +author: "Rhials" +delete-after: True +changes: + - bugfix: "Only filled graves will impact your mood." \ No newline at end of file From ed7a03c33dddd5ac56d7e7e6c1fcfb368687345a Mon Sep 17 00:00:00 2001 From: nikothedude <59709059+nikothedude@users.noreply.github.com> Date: Fri, 7 Jun 2024 14:35:54 -0400 Subject: [PATCH 71/81] Adds a random martial arts modifier to deathmatch + Adds a blacklisted map framework to modifiers (#83465) ## About The Pull Request Title. Uses pickweight, to ensure rare martial arts stay rare. Common: * Carp * CQC Uncommon: * EVIL boxing LEGENDARY: * Wrestling * UNNERFED PLASMA FIST * Psychotic brawling (bath salts, rare because its a meme) Does not work on meat tower. ## Why It's Good For The Game Variety is good! Also, theres only one way to get martial arts in DM and thats meat tower. There is ALSO very little way to get evil boxing, mushpunch, plasmafist, etc. This allows people to go absolutely nuts in death match, and I think thats a good thing. ## Changelog :cl: add: New deathmatch modifier: "Random martial arts" /:cl: --- code/modules/deathmatch/deathmatch_lobby.dm | 15 +++-- .../modules/deathmatch/deathmatch_modifier.dm | 62 ++++++++++++++++--- 2 files changed, 64 insertions(+), 13 deletions(-) diff --git a/code/modules/deathmatch/deathmatch_lobby.dm b/code/modules/deathmatch/deathmatch_lobby.dm index 918808126c69c..028653a2f2124 100644 --- a/code/modules/deathmatch/deathmatch_lobby.dm +++ b/code/modules/deathmatch/deathmatch_lobby.dm @@ -491,12 +491,10 @@ return TRUE var/datum/deathmatch_modifier/chosen_modifier = GLOB.deathmatch_game.modifiers[modpath] if(modpath in modifiers) - chosen_modifier.unselect(src) - modifiers -= modpath + unselect_modifier(chosen_modifier) return TRUE if(chosen_modifier.selectable(src)) - chosen_modifier.on_select(src) - modifiers += modpath + select_modifier(chosen_modifier) return TRUE if ("admin") // Admin functions @@ -511,6 +509,15 @@ return FALSE +/// Selects the passed modifier. +/datum/deathmatch_lobby/proc/select_modifier(datum/deathmatch_modifier/modifier) + modifier.on_select(src) + modifiers += modifier.type + +/// Deselects the passed modifier. +/datum/deathmatch_lobby/proc/unselect_modifier(datum/deathmatch_modifier/modifier) + modifier.unselect(src) + modifiers -= modifier.type /datum/deathmatch_lobby/ui_close(mob/user) . = ..() diff --git a/code/modules/deathmatch/deathmatch_modifier.dm b/code/modules/deathmatch/deathmatch_modifier.dm index ec5c20cf919b1..dadca49d70a4f 100644 --- a/code/modules/deathmatch/deathmatch_modifier.dm +++ b/code/modules/deathmatch/deathmatch_modifier.dm @@ -1,14 +1,16 @@ ///Deathmatch modifiers are little options the host can choose to spice the match a bit. /datum/deathmatch_modifier - ///The name of the modifier + /// The name of the modifier var/name = "Unnamed Modifier" - ///A small description/tooltip shown in the UI + /// A small description/tooltip shown in the UI var/description = "What the heck does this do?" - ///The color of the button shown in the UI + /// The color of the button shown in the UI var/color = "blue" - ///A list of modifiers this is incompatible with. - var/list/blacklisted_modifiers - ///Is this trait exempted from the "Random Modifiers" modifier. + /// A lazylist of modifier typepaths this is incompatible with. + var/list/datum/deathmatch_modifier/blacklisted_modifiers + /// A lazylist of map typepaths this is incomptable with. + var/list/datum/lazy_template/deathmatch/blacklisted_maps + /// Is this trait exempted from the "Random Modifiers" modifier. var/random_exempted = FALSE ///Whether or not this modifier can be selected, for both host and player-selected modifiers. @@ -18,11 +20,20 @@ return FALSE if(length(lobby.modifiers & blacklisted_modifiers)) return FALSE + if (map_incompatible(lobby.map)) + return FALSE for(var/modpath in lobby.modifiers) if(src in GLOB.deathmatch_game.modifiers[modpath].blacklisted_modifiers) return FALSE return TRUE +/// Returns TRUE if map.type is in our blacklisted maps, FALSE otherwise. +/datum/deathmatch_modifier/proc/map_incompatible(datum/lazy_template/deathmatch/map) + if (map?.type in blacklisted_maps) + return TRUE + + return FALSE + ///Called when selecting the deathmatch modifier. /datum/deathmatch_modifier/proc/on_select(datum/deathmatch_lobby/lobby) return @@ -31,9 +42,12 @@ /datum/deathmatch_modifier/proc/unselect(datum/deathmatch_lobby/lobby) return -///Called when the host chooses to change map. +///Called when the host chooses to change map. Returns FALSE if the new map is incompatible, TRUE otherwise. /datum/deathmatch_modifier/proc/on_map_changed(datum/deathmatch_lobby/lobby) - return + if (map_incompatible(lobby.map)) + lobby.unselect_modifier(src) + return FALSE + return TRUE ///Called as the game is about to start. /datum/deathmatch_modifier/proc/on_start_game(datum/deathmatch_lobby/lobby) @@ -533,7 +547,7 @@ /datum/deathmatch_modifier/any_loadout/on_map_changed(datum/deathmatch_lobby/lobby) if(lobby.loadouts == GLOB.deathmatch_game.loadouts) //This arena already allows any loadout for some reason. - lobby.modifiers -= type + lobby.unselect_modifier(src) else lobby.loadouts = GLOB.deathmatch_game.loadouts @@ -554,3 +568,33 @@ return SSquirks.AssignQuirks(player, player.client) + +/datum/deathmatch_modifier/martial_artistry + name = "Random martial arts" + description = "Everyone learns a random martial art!" + blacklisted_maps = list(/datum/lazy_template/deathmatch/meatower) + // krav maga excluded because its too common and too simple, mushpunch excluded because its horrible and not even funny + var/static/list/weighted_martial_arts = list( + // common + /datum/martial_art/cqc = 30, + /datum/martial_art/the_sleeping_carp = 30, + // uncommon + /datum/martial_art/boxing/evil = 20, + // LEGENDARY + /datum/martial_art/plasma_fist = 5, + /datum/martial_art/wrestling = 5, // wrestling is kinda strong ngl + /datum/martial_art/psychotic_brawling = 5, // a complete meme. sometimes you just get hardstunned. sometimes you punch someone across the room + ) + +/datum/deathmatch_modifier/martial_artistry/apply(mob/living/carbon/player, datum/deathmatch_lobby/lobby) + . = ..() + + var/datum/martial_art/picked_art_path = pick_weight(weighted_martial_arts) + var/datum/martial_art/instantiated_art = new picked_art_path() + + if (istype(instantiated_art, /datum/martial_art/boxing)) + player.mind.adjust_experience(/datum/skill/athletics, SKILL_EXP_LEGENDARY) + + instantiated_art.teach(player) + + to_chat(player, span_revenboldnotice("Your martial art is [uppertext(instantiated_art.name)]!")) From a8495fd6823fd2f93bb5bd98fb449634d1fc64e0 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 07:11:43 +1200 Subject: [PATCH 72/81] Automatic changelog for PR #83465 [ci skip] --- html/changelogs/AutoChangeLog-pr-83465.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83465.yml diff --git a/html/changelogs/AutoChangeLog-pr-83465.yml b/html/changelogs/AutoChangeLog-pr-83465.yml new file mode 100644 index 0000000000000..ee31673c09daf --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83465.yml @@ -0,0 +1,4 @@ +author: "nikothedude" +delete-after: True +changes: + - rscadd: "New deathmatch modifier: \"Random martial arts\"" \ No newline at end of file From f5287e740b0fbf7b1cc584ecf461e8b867233141 Mon Sep 17 00:00:00 2001 From: Da Cool Boss <142358580+DaCoolBoss@users.noreply.github.com> Date: Fri, 7 Jun 2024 20:16:28 +0100 Subject: [PATCH 73/81] Fixes space ruin blacklist (#83748) ## About The Pull Request Removed double entries, added ruins that weren't included, fixed typos & outdated names. ## Why It's Good For The Game Now you can ban any ruin in the game from generating in your server, and it will work. ## Changelog :cl: fix: Fixed entries in config file 'spaceruinsblacklist.txt'. /:cl: --- config/spaceruinblacklist.txt | 15 ++++----------- 1 file changed, 4 insertions(+), 11 deletions(-) diff --git a/config/spaceruinblacklist.txt b/config/spaceruinblacklist.txt index dcff6527bae80..c33d85b54abc9 100644 --- a/config/spaceruinblacklist.txt +++ b/config/spaceruinblacklist.txt @@ -14,7 +14,6 @@ #_maps/RandomRuins/SpaceRuins/asteroid5.dmm #_maps/RandomRuins/SpaceRuins/asteroid6.dmm #_maps/RandomRuins/SpaceRuins/atmosasteroidruin.dmm -#_maps/RandomRuins/SpaceRuins/atmosasteroidruin.dmm #_maps/RandomRuins/SpaceRuins/bigderelict1.dmm #_maps/RandomRuins/SpaceRuins/botanical_haven.dmm #_maps/RandomRuins/SpaceRuins/bus.dmm @@ -23,7 +22,7 @@ #_maps/RandomRuins/SpaceRuins/clownplanet.dmm #_maps/RandomRuins/SpaceRuins/crashedclownship.dmm #_maps/RandomRuins/SpaceRuins/crashedship.dmm -#_maps/RandomRuins/SpaceRuins/dangerous_research.dmm +#_maps/RandomRuins/SpaceRuins/cyborg_mothership.dmm #_maps/RandomRuins/SpaceRuins/dangerous_research.dmm #_maps/RandomRuins/SpaceRuins/deepstorage.dmm #_maps/RandomRuins/SpaceRuins/derelict_construction.dmm @@ -40,23 +39,22 @@ #_maps/RandomRuins/SpaceRuins/emptyshell.dmm #_maps/RandomRuins/SpaceRuins/fasttravel.dmm #_maps/RandomRuins/SpaceRuins/forgottenship.dmm -#_maps/RandomRuins/SpaceRuins/forgottenship.dmm #_maps/RandomRuins/SpaceRuins/garbagetruck1.dmm #_maps/RandomRuins/SpaceRuins/garbagetruck2.dmm #_maps/RandomRuins/SpaceRuins/garbagetruck3.dmm #_maps/RandomRuins/SpaceRuins/garbagetruck4.dmm #_maps/RandomRuins/SpaceRuins/gondolaasteroid.dmm #_maps/RandomRuins/SpaceRuins/hellfactory.dmm -#_maps/RandomRuins/SpaceRuins/hellfactory.dmm -#_maps/RandomRuins/SpaceRuins/hilbertshoteltestingsite.dmm +#_maps/RandomRuins/SpaceRuins/hilbertsresearchfacility.dmm #_maps/RandomRuins/SpaceRuins/infested_frigate.dmm #_maps/RandomRuins/SpaceRuins/intactemptyship.dmm #_maps/RandomRuins/SpaceRuins/interdyne.dmm #_maps/RandomRuins/SpaceRuins/listeningstation.dmm +#_maps/RandomRuins/SpaceRuins/meatderelict.dmm #_maps/RandomRuins/SpaceRuins/meateor.dmm #_maps/RandomRuins/SpaceRuins/mechtransport.dmm #_maps/RandomRuins/SpaceRuins/mimesvsclowns.dmm -#_maps/RandomRuins/SpaceRuins/mrow_thats_right +#_maps/RandomRuins/SpaceRuins/mrow_thats_right.dmm #_maps/RandomRuins/SpaceRuins/old_infiltrator.dmm #_maps/RandomRuins/SpaceRuins/oldAIsat.dmm #_maps/RandomRuins/SpaceRuins/oldstation.dmm @@ -66,23 +64,18 @@ #_maps/RandomRuins/SpaceRuins/phonebooth.dmm #_maps/RandomRuins/SpaceRuins/pod_crash.dmm #_maps/RandomRuins/SpaceRuins/prey_pod.dmm -#_maps/RandomRuins/SpaceRuins/prey_pod.dmm #_maps/RandomRuins/SpaceRuins/prison_shuttle.dmm #_maps/RandomRuins/SpaceRuins/russian_derelict.dmm #_maps/RandomRuins/SpaceRuins/shuttlerelic.dmm #_maps/RandomRuins/SpaceRuins/space_billboard.dmm -#_maps/RandomRuins/SpaceRuins/space_billboard.dmm #_maps/RandomRuins/SpaceRuins/space_ghost_restaurant.dmm #_maps/RandomRuins/SpaceRuins/spacehotel.dmm #_maps/RandomRuins/SpaceRuins/spinwardsmoothies.dmm -#_maps/RandomRuins/SpaceRuins/spinwardsmoothies.dmm -#_maps/RandomRuins/SpaceRuins/the_faceoff.dmm #_maps/RandomRuins/SpaceRuins/the_faceoff.dmm #_maps/RandomRuins/SpaceRuins/the_outlet.dmm #_maps/RandomRuins/SpaceRuins/thelizardsgas.dmm #_maps/RandomRuins/SpaceRuins/transit_booth.dmm #_maps/RandomRuins/SpaceRuins/travelers_rest.dmm -#_maps/RandomRuins/SpaceRuins/travelers_rest.dmm #_maps/RandomRuins/SpaceRuins/turretedoutpost.dmm #_maps/RandomRuins/SpaceRuins/vaporwave.dmm #_maps/RandomRuins/SpaceRuins/way_home.dmm From fe629442af267db1f87de00fe0cae198ad7f97a9 Mon Sep 17 00:00:00 2001 From: zxaber <37497534+zxaber@users.noreply.github.com> Date: Fri, 7 Jun 2024 12:30:39 -0700 Subject: [PATCH 74/81] Fixes borg chargers constantly (abet slowly) draining borg cells. (#83743) ## About The Pull Request - Adds in checks for the borg consumables resupplying to stop drawing power once supplies are full. Specifically, the `respawn_consumables()` proc will run attempting to stock everything it can, and will return TRUE if any item required stocking. ## Why It's Good For The Game Certain borg tools are still supplied by the borg chargers directly at a power cost because material costs just don't make sense. These did not have a check in place for if the various resources were full, meaning every process cycle a bit of the borg's cell would be used attempting to restock things. Since it's a percentage of the cell's current charge, a filled bluespace cell could have a surprising power leak. Now that borg chargers pull directly from the SMES units, borgs don't recharge if the powernet is empty (regardless of local APC charge). But borg consumables restocking carries on, which causes borgs to slowly drain. So I have added some checks to stop the drain if nothing was actually done. ## Changelog :cl: fix: Fixed borg chargers (especially unpowered ones) constantly draining a borg's cell. /:cl: --- .../modules/mob/living/silicon/robot/robot.dm | 4 +- .../mob/living/silicon/robot/robot_model.dm | 42 +++++++++++++++---- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/code/modules/mob/living/silicon/robot/robot.dm b/code/modules/mob/living/silicon/robot/robot.dm index 3fa78b9dda155..6fefbb05f7c0d 100644 --- a/code/modules/mob/living/silicon/robot/robot.dm +++ b/code/modules/mob/living/silicon/robot/robot.dm @@ -952,7 +952,9 @@ SIGNAL_HANDLER if(model) - model.respawn_consumable(src, cell.use(cell.charge * 0.005)) + if(cell.charge) + if(model.respawn_consumable(src, cell.charge * 0.005)) + cell.use(cell.charge * 0.005) if(sendmats) model.restock_consumable() if(repairs) diff --git a/code/modules/mob/living/silicon/robot/robot_model.dm b/code/modules/mob/living/silicon/robot/robot_model.dm index a46389e11b2be..1721d6ec2c102 100644 --- a/code/modules/mob/living/silicon/robot/robot_model.dm +++ b/code/modules/mob/living/silicon/robot/robot_model.dm @@ -137,29 +137,43 @@ if(cyborg.hud_used) cyborg.hud_used.update_robot_modules_display() + +///Restocks things that don't take mats, generally at a power cost. Returns True if anything was restocked/replaced, and False otherwise. /obj/item/robot_model/proc/respawn_consumable(mob/living/silicon/robot/cyborg, coeff = 1) SHOULD_CALL_PARENT(TRUE) + ///If anything was actually replaced/refilled/recharged. If not, we won't draw power. + . = FALSE + for(var/datum/robot_energy_storage/storage_datum in storages) if(storage_datum.renewable == FALSE) continue - storage_datum.energy = min(storage_datum.max_energy, storage_datum.energy + coeff * storage_datum.recharge_rate) + if(storage_datum.energy < storage_datum.max_energy) + . = TRUE + storage_datum.energy = min(storage_datum.max_energy, storage_datum.energy + coeff * storage_datum.recharge_rate) for(var/obj/item/module in get_usable_modules()) if(istype(module, /obj/item/assembly/flash)) var/obj/item/assembly/flash/flash = module + if(flash.burnt_out) + . = TRUE flash.times_used = 0 flash.burnt_out = FALSE flash.update_appearance() else if(istype(module, /obj/item/melee/baton/security)) var/obj/item/melee/baton/security/baton = module - baton.cell?.charge = baton.cell.maxcharge + if(baton.cell?.charge < baton.cell.maxcharge) + . = TRUE //if sec borgs ever make a mainstream return, we should probably do this differntly. + baton.cell?.charge = baton.cell.maxcharge else if(istype(module, /obj/item/gun/energy)) var/obj/item/gun/energy/gun = module if(!gun.chambered) + . = TRUE gun.recharge_newshot() //try to reload a new shot. - cyborg.toner = cyborg.tonermax + if(cyborg.toner < cyborg.tonermax) + . = TRUE + cyborg.toner = cyborg.tonermax /** * Refills consumables that require materials, rather than being given for free. @@ -350,6 +364,7 @@ if(!soap) return if(soap.uses < initial(soap.uses)) + . = TRUE soap.uses += ROUND_UP(initial(soap.uses) / 100) * coeff /obj/item/robot_model/engineering @@ -627,20 +642,29 @@ ..() var/obj/item/lightreplacer/light_replacer = locate(/obj/item/lightreplacer) in basic_modules if(light_replacer) - light_replacer.Charge(cyborg, coeff) + if(light_replacer.uses < light_replacer.max_uses) + . = TRUE + light_replacer.Charge(cyborg, coeff) var/obj/item/reagent_containers/spray/cyborg_drying/drying_agent = locate(/obj/item/reagent_containers/spray/cyborg_drying) in basic_modules if(drying_agent) - drying_agent.reagents.add_reagent(/datum/reagent/drying_agent, 5 * coeff) + var/datum/reagents/anti_water = drying_agent.reagents + if(anti_water.total_volume < anti_water.maximum_volume) + . = TRUE + drying_agent.reagents.add_reagent(/datum/reagent/drying_agent, 5 * coeff) var/obj/item/reagent_containers/spray/cyborg_lube/lube = locate(/obj/item/reagent_containers/spray/cyborg_lube) in emag_modules if(lube) - lube.reagents.add_reagent(/datum/reagent/lube, 2 * coeff) + var/datum/reagents/anti_friction = lube.reagents + if(anti_friction.total_volume < anti_friction.maximum_volume) + . = TRUE + lube.reagents.add_reagent(/datum/reagent/lube, 2 * coeff) var/obj/item/soap/nanotrasen/cyborg/soap = locate(/obj/item/soap/nanotrasen/cyborg) in basic_modules if(!soap) return if(soap.uses < initial(soap.uses)) + . = TRUE soap.uses += ROUND_UP(initial(soap.uses) / 100) * coeff /obj/item/robot_model/medical @@ -760,6 +784,7 @@ var/obj/item/gun/energy/e_gun/advtaser/cyborg/taser = locate(/obj/item/gun/energy/e_gun/advtaser/cyborg) in basic_modules if(taser) if(taser.cell.charge < taser.cell.maxcharge) + . = TRUE var/obj/item/ammo_casing/energy/shot = taser.ammo_type[taser.select] taser.cell.give(shot.e_cost * coeff) taser.update_appearance() @@ -811,7 +836,10 @@ ..() var/obj/item/reagent_containers/enzyme = locate(/obj/item/reagent_containers/condiment/enzyme) in basic_modules if(enzyme) - enzyme.reagents.add_reagent(/datum/reagent/consumable/enzyme, 2 * coeff) + var/datum/reagents/spicyketchup = enzyme.reagents + if(spicyketchup.total_volume < spicyketchup.maximum_volume) + . = TRUE + enzyme.reagents.add_reagent(/datum/reagent/consumable/enzyme, 2 * coeff) /obj/item/robot_model/syndicate name = "Syndicate Assault" From 2eaa3dfa1f738e9b4347593dabdfc80e730d24c4 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 07:41:29 +1200 Subject: [PATCH 75/81] Automatic changelog for PR #83748 [ci skip] --- html/changelogs/AutoChangeLog-pr-83748.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83748.yml diff --git a/html/changelogs/AutoChangeLog-pr-83748.yml b/html/changelogs/AutoChangeLog-pr-83748.yml new file mode 100644 index 0000000000000..92c5e34b3c828 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83748.yml @@ -0,0 +1,4 @@ +author: "DaCoolBoss" +delete-after: True +changes: + - bugfix: "Fixed entries in config file 'spaceruinsblacklist.txt'." \ No newline at end of file From ecf02f9cf782284674c97b2a81a2e31bda67e661 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 07:44:25 +1200 Subject: [PATCH 76/81] Automatic changelog for PR #83743 [ci skip] --- html/changelogs/AutoChangeLog-pr-83743.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83743.yml diff --git a/html/changelogs/AutoChangeLog-pr-83743.yml b/html/changelogs/AutoChangeLog-pr-83743.yml new file mode 100644 index 0000000000000..0a58a1f301ac6 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83743.yml @@ -0,0 +1,4 @@ +author: "zxaber" +delete-after: True +changes: + - bugfix: "Fixed borg chargers (especially unpowered ones) constantly draining a borg's cell." \ No newline at end of file From 9a01bf57db185407c0b2e20c21ecd92fdb2c97ce Mon Sep 17 00:00:00 2001 From: SyncIt21 <110812394+SyncIt21@users.noreply.github.com> Date: Sat, 8 Jun 2024 01:27:18 +0530 Subject: [PATCH 77/81] Fix wrench screentip typo for smart fridge (#83767) ## About The Pull Request - Fixes #83766 ## Changelog :cl: spellcheck: Corrected wrench contextual screentip typo for smart fridge /:cl: --------- Co-authored-by: Afevis --- code/modules/food_and_drinks/machinery/smartfridge.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/food_and_drinks/machinery/smartfridge.dm b/code/modules/food_and_drinks/machinery/smartfridge.dm index de458bb218736..8a6b3258a0ef7 100644 --- a/code/modules/food_and_drinks/machinery/smartfridge.dm +++ b/code/modules/food_and_drinks/machinery/smartfridge.dm @@ -173,7 +173,7 @@ tool_tip_set = TRUE else if(held_item.tool_behaviour == TOOL_WRENCH) - context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Un" : ""]anchore" + context[SCREENTIP_CONTEXT_LMB] = "[anchored ? "Una" : "A"]nchor" tool_tip_set = TRUE return tool_tip_set ? CONTEXTUAL_SCREENTIP_SET : NONE From 5fe708c4662940c096ff7d672489836195a5b563 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 07:57:43 +1200 Subject: [PATCH 78/81] Automatic changelog for PR #83767 [ci skip] --- html/changelogs/AutoChangeLog-pr-83767.yml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83767.yml diff --git a/html/changelogs/AutoChangeLog-pr-83767.yml b/html/changelogs/AutoChangeLog-pr-83767.yml new file mode 100644 index 0000000000000..8594c6fbffbdc --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83767.yml @@ -0,0 +1,4 @@ +author: "SyncIt21" +delete-after: True +changes: + - spellcheck: "Corrected wrench contextual screentip typo for smart fridge" \ No newline at end of file From dd71e81f6504fe38fccda8fe8b58925ebc407496 Mon Sep 17 00:00:00 2001 From: _0Steven <42909981+00-Steven@users.noreply.github.com> Date: Fri, 7 Jun 2024 23:22:02 +0200 Subject: [PATCH 79/81] Wall button refactor and qol (#83774) ## About The Pull Request Originally this started as me getting annoyed at buttons dropping both of their items when you try to remove one, but looking at the code I decided to just go ahead and update it to the newer procs. This should hopefully also make it easier to split it off into wall and table buttons to replace those wall-buttons-on-tables in preparation for the wallening, though I'll have to wait on doing that for a bit more. I normally like doing detailed pr bodies for refactors, but I'm honestly kinda tired, so I'm leaving out the parts where I display the new code and only explain what's changed. Right so, the biggest part of this pr is moving the item interaction and deconstruction code to the newer systems, so let's start with that. ### Begone `attackby(...)` Previously, buttons still used a big old `attackby(...)` proc: https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L107-L143 Some of which even handles wrench interaction, which we have `wrench_act(...)` for nowadays. So, first order of business! Remove that, move it to `wrench_act(...)`, and add feedback for the button needing to be opened and emptied. Then create two new procs for the leftover assembly and airlock electronics interactions, `assembly_act(...)` and `airlock_electronics_act(...)`, add feedback for those items already being in the button, and put those procs in `item_interaction(...)`. Finally, we're left with the following: https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L140-L143 Which we move to `base_item_interaction(...)`, as it must be ran after any and all other item interactions. ### Update `screwdriver_act(...)` Buttons _did_ use `screwdriver_act(...)` already, but this didn't actually return the proper item interaction flags, so we update it to return those. ### Deconstruction fuckery So rather than deconstructing properly when being wrenched, we'd just make a wallframe item, call `qdel(...)`, and call it a day: https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L128-L138 On top of that, we would just flat out `QDEL_NULL(...)` our internal items when destroyed. https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L62-L65 This leads to the situations where: 1. We don't actually care about `NO_DEBRIS_AFTER_DECONSTRUCTION`, and drop our frame anyways. 2. Destroying our button in any way would flat out delete its contents, which uh. Isn't great. So to resolve this, we move the wallframe creation and fingerprint transferring to `on_deconstruction(...)`, make `dump_inventory_contents(...)` reset our variables for good measure, then make deconstructing it with a wrench actually call `deconstruct(TRUE)`. This resolves the fuckery. ### Other unused deconstruction fuckery Oh hey look, unused code: https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L239-L251 I believe this would, theoretically, be registered to be called by `find_and_hang_on_wall(...)` during `Initialize(...)`, and then called when the wall it's on is destroyed. But, it _isn't_, and importantly? We no longer need to! Because the code for this defaults to `deconstruct(...)` and, hey, look, we already set up our deconstruction behaviour, and what we want here is essentially the same! So we just remove it. ### Cleaning up `interact(...)` We want to make our item removal and button pressing interactions a bit nicer, which requires dealing with `interact(...)` but ooooh boyyy what a mess: https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L189-L237 This is what actually handles pressing our button! And reskinning it. And removing our items. That's not great. Time to change it. First off, we have a bunch of other stuff that wants to just press the button, but really calls `attack_hand(...)` so it can in turn call `interact(...)` so it can in turn press the button. That's especially not great. So we move this part to a new proc `attempt_press(...)`, and instead make all the other things that want to press stuff call that instead, skipping by all the stuff we _don't_ want. This is somewhat nicer. Then, we want to be able to individually remove our internal items, so we split removing those off into their own new procs too, `remove_assembly(...)` and `remove_airlock_electronics(...)`. We leave the reskinning in there mostly as-is, as we don't need it in other places and it's too small to bother, but just add a balloon alert onto it. ### Left-click right-click item removal priority We don't have an `interact_secondary(...)`, but it doesn't really matter given `attack_hand_secondary(...)` works perfectly fine for our purposes. So we construct a new `attack_hand_secondary(...)` that's almost identical to `interact(...)` but with the airlock electronics and assembly removal priorities swapped and reskinning removed, and have it forward to the normal chain when item removal isn't necessary. This lets us take out the airlock electronics or assembly device individually using left-click and right-click, but due to it just being priorities lets us take out both in turn with left-click if we do want to. ### Sound nitpicks When working with buttons, I'd notice it'd play the pickup sound when removing an assembly device, but not play any sound when putting one in. https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L109-L118 So we just make these `transferItemToLoc(...)` procs not silent by setting `silent = FALSE`, and that feels much nicer. Sadly airlock electronics do not have such sounds, but that is outside of the scope of this pr. ### Allowing renaming for sanity's sake To let us replicate roundstart buttons, or for that matter avoid having six identically named buttons, we set the `UNIQUE_RENAME` flag. However, this would let people rename buttons they don't have access to, so instead we set or remove `UNIQUE_RENAME` on `on_set_panel_open(...)`, so it's only possible to rename while the button is opened. This stops people without access from abusing this. ### Added screentips Most of this is relatively normal, we just register context during init and have a bigass `add_context(...)` proc. ### Remove single letter variables We had single letter variables in our `attackby(...)` and two of our `setup_device(...)` procs. Each of those have been removed and replace with a slightly saner variable name. ### Replace boolean `0` with `FALSE` One of our vars, `initialized_button`, is set to `0`, while its purpose is entirely boolean. https://github.com/tgstation/tgstation/blob/db5907a41ecd76e028f76e643f5fb37e083de888/code/game/machinery/buttons.dm#L24 So we just replace it with `FALSE` for clarity's sake. ### Code reorganization Because the file was getting long, I decided it'd be best to split it up into grouped segments, in order: - Initialization - Appearance - Interaction - Deconstruction - Information - Mapping Presets Where Interaction is grouped (without labels) into item and hand interaction. This is for posterity, when I or someone else comes back later to kick this fucker in the shins for table buttons. I believe that's all. If not I probably forgot. ## Why It's Good For The Game Overall, it tends to be better when we actually use the tool act type procs and destruction procs. Having it only play the item sound when you take it out feels a bit off. Screentips are nice. It's nice when destroyed objects don't just miraculously disintegrate their contained items. As for renaming: Allowing renaming is necessary to allow players to replicate the starting gamestate after destruction, as a lot of roundstart buttons are named. In addition, it's nice to not just have six identically named buttons when constructing them. We avoid people renaming buttons they don't have access to by only setting the flag when the panel is opened, which can only be done by people with access. And adjusting item removal: Attempting to remove an item dropping both items at once is awkward, given one will probably end up dropping on the floor, and not uncommonly you'll want to change out only one of them in the first place. But just making it pick one first and then the other is awkward on its own, if you want to just swap the second item out. Making it so left click prioritizes the airlock electronics and right click prioritizes the assembly device, moving on to the other one when unavailable, should avoid that issue while resolving the former. ## Changelog :cl: refactor: Refactored wall button code, please report any issues. fix: Wall buttons actually drop their contents when destroyed. sound: Putting items into wall buttons actually plays a sound. This matters for assembly devices, but airlock electronics do not have a sound. qol: Added screentips to wall buttons. qol: You can now take out the airlock electronics or assembly device out of wall buttons individually. Left click prioritises the board, right click prioritises the device. qol: Wall buttons are renamable with a pen when opened. qol: Attempting to wrench deconstruct a wall button or put in airlock electronics or an assembly device when you can't actually gives feedback. /:cl: --------- Co-authored-by: Afevis --- code/game/machinery/buttons.dm | 342 ++++++++++++++++++++++----------- 1 file changed, 234 insertions(+), 108 deletions(-) diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm index 32e56e2fca920..6570d022a49a9 100644 --- a/code/game/machinery/buttons.dm +++ b/code/game/machinery/buttons.dm @@ -21,7 +21,7 @@ var/obj/item/electronics/airlock/board var/device_type = null var/id = null - var/initialized_button = 0 + var/initialized_button = FALSE var/silicon_access_disabled = FALSE /obj/machinery/button/indestructible @@ -36,6 +36,10 @@ fire = 90 acid = 70 +/** + * INITIALIZATION + */ + /obj/machinery/button/Initialize(mapload, ndir = 0, built = 0) . = ..() if(built) @@ -58,11 +62,23 @@ setup_device() find_and_hang_on_wall() + register_context() -/obj/machinery/button/Destroy() - QDEL_NULL(device) - QDEL_NULL(board) - return ..() +/obj/machinery/button/proc/setup_device() + if(id && istype(device, /obj/item/assembly/control)) + var/obj/item/assembly/control/control_device = device + control_device.id = id + initialized_button = TRUE + +/obj/machinery/button/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) + if(id) + id = "[port.shuttle_id]_[id]" + setup_device() + + +/** + * APPEARANCE + */ /obj/machinery/button/update_icon_state() icon_state = "[base_icon_state][skin]" @@ -94,53 +110,93 @@ if(!(machine_stat & (NOPOWER|BROKEN)) && !panel_open) . += emissive_appearance(icon, "[base_icon_state]-light-mask", src, alpha = src.alpha) +/obj/machinery/button/on_set_panel_open(old_value) + if(panel_open) // Only allow renaming while the panel is open + obj_flags |= UNIQUE_RENAME + else + obj_flags &= ~UNIQUE_RENAME + + +/** + * INTERACTION + */ + +/obj/machinery/button/item_interaction(mob/living/user, obj/item/tool, list/modifiers) + if(!panel_open) + return NONE + + if(isassembly(tool)) + return assembly_act(user, tool) + else if(istype(tool, /obj/item/electronics/airlock)) + return airlock_electronics_act(user, tool) + +/obj/machinery/button/proc/assembly_act(mob/living/user, obj/item/assembly/new_device) + if(device) + to_chat(user, span_warning("The button already contains a device!")) + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(new_device, src, silent = FALSE)) + to_chat(user, span_warning("\The [new_device] is stuck to you!")) + return ITEM_INTERACT_BLOCKING + + device = new_device + to_chat(user, span_notice("You add \the [new_device] to the button.")) + + update_appearance() + return ITEM_INTERACT_SUCCESS + +/obj/machinery/button/proc/airlock_electronics_act(mob/living/user, obj/item/electronics/airlock/new_board) + if(board) + to_chat(user, span_warning("The button already contains a board!")) + return ITEM_INTERACT_BLOCKING + if(!user.transferItemToLoc(new_board, src, silent = FALSE)) + to_chat(user, span_warning("\The [new_board] is stuck to you!")) + return ITEM_INTERACT_BLOCKING + + board = new_board + if(board.one_access) + req_one_access = board.accesses + else + req_access = board.accesses + to_chat(user, span_notice("You add \the [new_board] to the button.")) + + update_appearance() + return ITEM_INTERACT_SUCCESS + /obj/machinery/button/screwdriver_act(mob/living/user, obj/item/tool) if(panel_open || allowed(user)) default_deconstruction_screwdriver(user, "[base_icon_state][skin]-open", "[base_icon_state][skin]", tool) update_appearance() - else - balloon_alert(user, "access denied") - flick_overlay_view("[base_icon_state]-overlay-error", 1 SECONDS) + return ITEM_INTERACT_SUCCESS - return TRUE + balloon_alert(user, "access denied") + flick_overlay_view("[base_icon_state]-overlay-error", 1 SECONDS) + return ITEM_INTERACT_BLOCKING -/obj/machinery/button/attackby(obj/item/W, mob/living/user, params) - if(panel_open) - if(!device && isassembly(W)) - if(!user.transferItemToLoc(W, src)) - to_chat(user, span_warning("\The [W] is stuck to you!")) - return - device = W - to_chat(user, span_notice("You add [W] to the button.")) - - if(!board && istype(W, /obj/item/electronics/airlock)) - if(!user.transferItemToLoc(W, src)) - to_chat(user, span_warning("\The [W] is stuck to you!")) - return - board = W - if(board.one_access) - req_one_access = board.accesses - else - req_access = board.accesses - balloon_alert(user, "electronics added") - to_chat(user, span_notice("You add [W] to the button.")) - - if(!device && !board && W.tool_behaviour == TOOL_WRENCH) - to_chat(user, span_notice("You start unsecuring the button frame...")) - W.play_tool_sound(src) - if(W.use_tool(src, user, 40)) - to_chat(user, span_notice("You unsecure the button frame.")) - transfer_fingerprints_to(new /obj/item/wallframe/button(get_turf(src))) - playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) - qdel(src) +/obj/machinery/button/wrench_act(mob/living/user, obj/item/tool) + if(!panel_open) + balloon_alert(user, "open button first!") + return ITEM_INTERACT_BLOCKING - update_appearance() - return + if(device || board) + balloon_alert(user, "empty button first!") + return ITEM_INTERACT_BLOCKING + + to_chat(user, span_notice("You start unsecuring the button frame...")) + if(tool.use_tool(src, user, 40, volume=50)) + to_chat(user, span_notice("You unsecure the button frame.")) + playsound(loc, 'sound/items/deconstruct.ogg', 50, TRUE) + deconstruct(TRUE) + + return ITEM_INTERACT_SUCCESS + +/obj/machinery/button/base_item_interaction(mob/living/user, obj/item/tool, list/modifiers) + . = ..() + if(.) + return . + // This is in here so it's called only after every other item interaction. + if(!user.combat_mode && !(tool.item_flags & NOBLUDGEON) && !panel_open) + return attempt_press(user) ? ITEM_INTERACT_SUCCESS : ITEM_INTERACT_BLOCKING - if(!user.combat_mode && !(W.item_flags & NOBLUDGEON)) - return attack_hand(user) - else - return ..() /obj/machinery/button/emag_act(mob/user, obj/item/card/emag/emag_card) . = ..() @@ -157,98 +213,168 @@ balloon_alert(user, "access overridden") return TRUE + /obj/machinery/button/attack_ai(mob/user) if(!silicon_access_disabled && !panel_open) - return attack_hand(user) + return attempt_press(user) /obj/machinery/button/attack_robot(mob/user) return attack_ai(user) -/obj/machinery/button/examine(mob/user) +/obj/machinery/button/interact(mob/user) . = ..() + if(.) + return + if(!initialized_button) + setup_device() + add_fingerprint(user) + if(!panel_open) + attempt_press(user) return - if(device) - . += span_notice("There is \a [device] inside, which could be removed with an empty hand.") - if(board) - . += span_notice("There is \a [board] inside, which could be removed with an empty hand.") - if(!board && !device) - . += span_notice("There is nothing currently installed in \the [src].") -/obj/machinery/button/proc/setup_device() - if(id && istype(device, /obj/item/assembly/control)) - var/obj/item/assembly/control/A = device - A.id = id - initialized_button = 1 + if(board) + remove_airlock_electronics(user) + return + if(device) + remove_assembly(user) + return -/obj/machinery/button/connect_to_shuttle(mapload, obj/docking_port/mobile/port, obj/docking_port/stationary/dock) - if(id) - id = "[port.shuttle_id]_[id]" - setup_device() + if(can_alter_skin) + if(skin == "") + skin = "-warning" + to_chat(user, span_notice("You change the button frame's front panel to warning lines.")) + else + skin = "" + to_chat(user, span_notice("You change the button frame's front panel to default.")) + update_appearance(UPDATE_ICON) + balloon_alert(user, "style swapped") -/obj/machinery/button/interact(mob/user) - . = ..() - if(.) - return +/obj/machinery/button/attack_hand_secondary(mob/user, list/modifiers) if(!initialized_button) setup_device() add_fingerprint(user) - if(panel_open) - if(device || board) - if(device) - user.put_in_hands(device) - device = null - if(board) - user.put_in_hands(board) - req_access = list() - req_one_access = list() - board = null - update_appearance(UPDATE_ICON) - balloon_alert(user, "electronics removed") - to_chat(user, span_notice("You remove electronics from the button frame.")) - - else if(can_alter_skin) - if(skin == "") - skin = "-warning" - to_chat(user, span_notice("You change the button frame's front panel to warning lines.")) - else - skin = "" - to_chat(user, span_notice("You change the button frame's front panel to default.")) - update_appearance(UPDATE_ICON) - balloon_alert(user, "swapped style") - return + if(!panel_open) + return SECONDARY_ATTACK_CALL_NORMAL + + if(device) + remove_assembly(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + if(board) + remove_airlock_electronics(user) + return SECONDARY_ATTACK_CANCEL_ATTACK_CHAIN + + return ..() + +/obj/machinery/button/proc/remove_assembly(mob/user) + user.put_in_hands(device) + to_chat(user, span_notice("You remove \the [device] from the button frame.")) + device = null + update_appearance(UPDATE_ICON) + +/obj/machinery/button/proc/remove_airlock_electronics(mob/user) + user.put_in_hands(board) + to_chat(user, span_notice("You remove the board from the button frame.")) + req_access = list() + req_one_access = list() + board = null + update_appearance(UPDATE_ICON) + +/obj/machinery/button/proc/attempt_press(mob/user) if((machine_stat & (NOPOWER|BROKEN))) - return + return FALSE if(device && device.next_activate > world.time) - return + return FALSE if(!allowed(user)) balloon_alert(user, "access denied") flick_overlay_view("[base_icon_state]-overlay-error", 1 SECONDS) - return + return FALSE use_energy(5 JOULES) flick_overlay_view("[base_icon_state]-overlay-success", 1 SECONDS) if(device) device.pulsed(user) - SEND_GLOBAL_SIGNAL(COMSIG_GLOB_BUTTON_PRESSED,src) + SEND_GLOBAL_SIGNAL(COMSIG_GLOB_BUTTON_PRESSED, src) + return TRUE + /** - * Called when the mounted button's wall is knocked down. + * DECONSTRUCTION */ -/obj/machinery/button/proc/knock_down() + +/obj/machinery/button/on_deconstruction(disassembled) + var/obj/item/wallframe/button/dropped_frame = new /obj/item/wallframe/button(drop_location()) + transfer_fingerprints_to(dropped_frame) + +/obj/machinery/button/dump_inventory_contents(list/subset) + . = ..() + device = null + board = null + req_access = list() + req_one_access = list() + + +/** + * INFORMATION + */ + +/obj/machinery/button/examine(mob/user) + . = ..() + if(!panel_open) + return if(device) - device.forceMove(get_turf(src)) - device = null + . += span_notice("There is \a [device] inside, which could be removed with an empty hand.") if(board) - board.forceMove(get_turf(src)) - req_access = list() - req_one_access = list() - board = null - qdel(src) + . += span_notice("There is \a [board] inside, which could be removed with an empty hand.") + if(isnull(board) && isnull(device)) + . += span_notice("There is nothing currently installed in \the [src].") + +/obj/machinery/button/add_context(atom/source, list/context, obj/item/held_item, mob/living/user) + if(panel_open) + if(isnull(held_item)) + if(board && device) + context[SCREENTIP_CONTEXT_LMB] = "Remove Board" + context[SCREENTIP_CONTEXT_RMB] = "Remove Device" + return CONTEXTUAL_SCREENTIP_SET + else if(board) + context[SCREENTIP_CONTEXT_LMB] = "Remove Board" + return CONTEXTUAL_SCREENTIP_SET + else if(device) + context[SCREENTIP_CONTEXT_LMB] = "Remove Device" + return CONTEXTUAL_SCREENTIP_SET + else if(can_alter_skin) + context[SCREENTIP_CONTEXT_LMB] = "Swap Style" + return CONTEXTUAL_SCREENTIP_SET + else if(isassembly(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "Install Device" + return CONTEXTUAL_SCREENTIP_SET + else if(istype(held_item, /obj/item/electronics/airlock)) + context[SCREENTIP_CONTEXT_LMB] = "Install Board" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_WRENCH) + context[SCREENTIP_CONTEXT_LMB] = "Deconstruct Button" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Close Button" + return CONTEXTUAL_SCREENTIP_SET + else + if(isnull(held_item)) + context[SCREENTIP_CONTEXT_LMB] = "Press Button" + return CONTEXTUAL_SCREENTIP_SET + else if(held_item.tool_behaviour == TOOL_SCREWDRIVER) + context[SCREENTIP_CONTEXT_LMB] = "Open Button" + return CONTEXTUAL_SCREENTIP_SET + + return NONE + + +/** + * MAPPING PRESETS + */ /obj/machinery/button/door name = "door button" @@ -265,13 +391,13 @@ MAPPING_DIRECTIONAL_HELPERS(/obj/machinery/button/door, 24) /obj/machinery/button/door/setup_device() if(!device) if(normaldoorcontrol) - var/obj/item/assembly/control/airlock/A = new(src) - A.specialfunctions = specialfunctions - device = A + var/obj/item/assembly/control/airlock/airlock_device = new(src) + airlock_device.specialfunctions = specialfunctions + device = airlock_device else - var/obj/item/assembly/control/C = new(src) - C.sync_doors = sync_doors - device = C + var/obj/item/assembly/control/control_device = new(src) + control_device.sync_doors = sync_doors + device = control_device ..() /obj/machinery/button/door/incinerator_vent_ordmix From 77efe41882dd7764d6c7a8c4ae0f974780fcad83 Mon Sep 17 00:00:00 2001 From: orange man <61334995+comfyorange@users.noreply.github.com> Date: Sat, 8 Jun 2024 09:23:10 +1200 Subject: [PATCH 80/81] Automatic changelog for PR #83774 [ci skip] --- html/changelogs/AutoChangeLog-pr-83774.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 html/changelogs/AutoChangeLog-pr-83774.yml diff --git a/html/changelogs/AutoChangeLog-pr-83774.yml b/html/changelogs/AutoChangeLog-pr-83774.yml new file mode 100644 index 0000000000000..897cb86f5e733 --- /dev/null +++ b/html/changelogs/AutoChangeLog-pr-83774.yml @@ -0,0 +1,10 @@ +author: "00-Steven" +delete-after: True +changes: + - refactor: "Refactored wall button code, please report any issues." + - bugfix: "Wall buttons actually drop their contents when destroyed." + - sound: "Putting items into wall buttons actually plays a sound. This matters for assembly devices, but airlock electronics do not have a sound." + - qol: "Added screentips to wall buttons." + - qol: "You can now take out the airlock electronics or assembly device out of wall buttons individually. Left click prioritises the board, right click prioritises the device." + - qol: "Wall buttons are renamable with a pen when opened." + - qol: "Attempting to wrench deconstruct a wall button or put in airlock electronics or an assembly device when you can't actually gives feedback." \ No newline at end of file From d01c4beb84b37604b99df83a06d25ead48926727 Mon Sep 17 00:00:00 2001 From: Changelogs Date: Sat, 8 Jun 2024 00:24:29 +0000 Subject: [PATCH 81/81] Automatic changelog compile [ci skip] --- html/changelogs/AutoChangeLog-pr-83465.yml | 4 --- html/changelogs/AutoChangeLog-pr-83734.yml | 5 --- html/changelogs/AutoChangeLog-pr-83736.yml | 4 --- html/changelogs/AutoChangeLog-pr-83743.yml | 4 --- html/changelogs/AutoChangeLog-pr-83748.yml | 4 --- html/changelogs/AutoChangeLog-pr-83752.yml | 4 --- html/changelogs/AutoChangeLog-pr-83758.yml | 4 --- html/changelogs/AutoChangeLog-pr-83759.yml | 4 --- html/changelogs/AutoChangeLog-pr-83765.yml | 5 --- html/changelogs/AutoChangeLog-pr-83767.yml | 4 --- html/changelogs/AutoChangeLog-pr-83768.yml | 4 --- html/changelogs/AutoChangeLog-pr-83770.yml | 4 --- html/changelogs/AutoChangeLog-pr-83774.yml | 10 ------ html/changelogs/archive/2024-06.yml | 42 ++++++++++++++++++++++ 14 files changed, 42 insertions(+), 60 deletions(-) delete mode 100644 html/changelogs/AutoChangeLog-pr-83465.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83734.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83736.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83743.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83748.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83752.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83758.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83759.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83765.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83767.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83768.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83770.yml delete mode 100644 html/changelogs/AutoChangeLog-pr-83774.yml diff --git a/html/changelogs/AutoChangeLog-pr-83465.yml b/html/changelogs/AutoChangeLog-pr-83465.yml deleted file mode 100644 index ee31673c09daf..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83465.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "nikothedude" -delete-after: True -changes: - - rscadd: "New deathmatch modifier: \"Random martial arts\"" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83734.yml b/html/changelogs/AutoChangeLog-pr-83734.yml deleted file mode 100644 index b5fd85f6ded56..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83734.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "thegrb93" -delete-after: True -changes: - - bugfix: "Borg emag module jank when no longer emagged" - - bugfix: "Borg piercing hypospray fail message" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83736.yml b/html/changelogs/AutoChangeLog-pr-83736.yml deleted file mode 100644 index 8ab2ca51d56d4..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83736.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - refactor: "alt right click has been refactored. report bugs on github" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83743.yml b/html/changelogs/AutoChangeLog-pr-83743.yml deleted file mode 100644 index 0a58a1f301ac6..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83743.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "zxaber" -delete-after: True -changes: - - bugfix: "Fixed borg chargers (especially unpowered ones) constantly draining a borg's cell." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83748.yml b/html/changelogs/AutoChangeLog-pr-83748.yml deleted file mode 100644 index 92c5e34b3c828..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83748.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "DaCoolBoss" -delete-after: True -changes: - - bugfix: "Fixed entries in config file 'spaceruinsblacklist.txt'." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83752.yml b/html/changelogs/AutoChangeLog-pr-83752.yml deleted file mode 100644 index 0bbc484dd59f9..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83752.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Rhials" -delete-after: True -changes: - - bugfix: "Only filled graves will impact your mood." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83758.yml b/html/changelogs/AutoChangeLog-pr-83758.yml deleted file mode 100644 index 749dba8eaa20b..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83758.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "Melbert" -delete-after: True -changes: - - bugfix: "Fix some modifiers to do after speed (sanity, midas gun) stacking when they shouldn't" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83759.yml b/html/changelogs/AutoChangeLog-pr-83759.yml deleted file mode 100644 index 476baef853f30..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83759.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "projectkepler-ru" -delete-after: True -changes: - - bugfix: "smoking pipe not showing sprite when lit" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83765.yml b/html/changelogs/AutoChangeLog-pr-83765.yml deleted file mode 100644 index d8b3ec6094c96..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83765.yml +++ /dev/null @@ -1,5 +0,0 @@ -author: "EnterTheJake" -delete-after: True -changes: - - balance: "Rust walkers' summoning ritual now requires 5 sheets of Titanium instead of Iron." - - bugfix: "Magic resistance grants complete immunity from the passive disgust buildup from standing on Rusted turfs." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83767.yml b/html/changelogs/AutoChangeLog-pr-83767.yml deleted file mode 100644 index 8594c6fbffbdc..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83767.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - spellcheck: "Corrected wrench contextual screentip typo for smart fridge" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83768.yml b/html/changelogs/AutoChangeLog-pr-83768.yml deleted file mode 100644 index dd0a446972c64..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83768.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "SyncIt21" -delete-after: True -changes: - - bugfix: "techfabs don't runtime & hang when printing in no apc areas" \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83770.yml b/html/changelogs/AutoChangeLog-pr-83770.yml deleted file mode 100644 index 262c93db0ef15..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83770.yml +++ /dev/null @@ -1,4 +0,0 @@ -author: "MichiRecRoom" -delete-after: True -changes: - - qol: "Personal AI's face display selection is now a radial menu. As a bonus, now you can see what the faces look like before selecting them." \ No newline at end of file diff --git a/html/changelogs/AutoChangeLog-pr-83774.yml b/html/changelogs/AutoChangeLog-pr-83774.yml deleted file mode 100644 index 897cb86f5e733..0000000000000 --- a/html/changelogs/AutoChangeLog-pr-83774.yml +++ /dev/null @@ -1,10 +0,0 @@ -author: "00-Steven" -delete-after: True -changes: - - refactor: "Refactored wall button code, please report any issues." - - bugfix: "Wall buttons actually drop their contents when destroyed." - - sound: "Putting items into wall buttons actually plays a sound. This matters for assembly devices, but airlock electronics do not have a sound." - - qol: "Added screentips to wall buttons." - - qol: "You can now take out the airlock electronics or assembly device out of wall buttons individually. Left click prioritises the board, right click prioritises the device." - - qol: "Wall buttons are renamable with a pen when opened." - - qol: "Attempting to wrench deconstruct a wall button or put in airlock electronics or an assembly device when you can't actually gives feedback." \ No newline at end of file diff --git a/html/changelogs/archive/2024-06.yml b/html/changelogs/archive/2024-06.yml index 7238a63a67e1a..60046e053bd8e 100644 --- a/html/changelogs/archive/2024-06.yml +++ b/html/changelogs/archive/2024-06.yml @@ -332,3 +332,45 @@ zxaber: - bugfix: 'Tool-based flashes (read: from welders) are no longer incorrectly locked at flash level 1. Wear proper PPE!' +2024-06-08: + 00-Steven: + - refactor: Refactored wall button code, please report any issues. + - bugfix: Wall buttons actually drop their contents when destroyed. + - sound: Putting items into wall buttons actually plays a sound. This matters for + assembly devices, but airlock electronics do not have a sound. + - qol: Added screentips to wall buttons. + - qol: You can now take out the airlock electronics or assembly device out of wall + buttons individually. Left click prioritises the board, right click prioritises + the device. + - qol: Wall buttons are renamable with a pen when opened. + - qol: Attempting to wrench deconstruct a wall button or put in airlock electronics + or an assembly device when you can't actually gives feedback. + DaCoolBoss: + - bugfix: Fixed entries in config file 'spaceruinsblacklist.txt'. + EnterTheJake: + - balance: Rust walkers' summoning ritual now requires 5 sheets of Titanium instead + of Iron. + - bugfix: Magic resistance grants complete immunity from the passive disgust buildup + from standing on Rusted turfs. + Melbert: + - bugfix: Fix some modifiers to do after speed (sanity, midas gun) stacking when + they shouldn't + MichiRecRoom: + - qol: Personal AI's face display selection is now a radial menu. As a bonus, now + you can see what the faces look like before selecting them. + Rhials: + - bugfix: Only filled graves will impact your mood. + SyncIt21: + - spellcheck: Corrected wrench contextual screentip typo for smart fridge + - refactor: alt right click has been refactored. report bugs on github + - bugfix: techfabs don't runtime & hang when printing in no apc areas + nikothedude: + - rscadd: 'New deathmatch modifier: "Random martial arts"' + projectkepler-ru: + - bugfix: smoking pipe not showing sprite when lit + thegrb93: + - bugfix: Borg emag module jank when no longer emagged + - bugfix: Borg piercing hypospray fail message + zxaber: + - bugfix: Fixed borg chargers (especially unpowered ones) constantly draining a + borg's cell.