From a1237910c5e5919b2a3742b6628ff45d3a9982a0 Mon Sep 17 00:00:00 2001 From: lzk <124214523+lzk228@users.noreply.github.com> Date: Wed, 18 Sep 2024 09:37:35 +0200 Subject: [PATCH 01/40] Fix bagel vox box (#32208) Fix vox box on bagel --- Resources/Maps/bagel.yml | 48 ++++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/Resources/Maps/bagel.yml b/Resources/Maps/bagel.yml index 7505068a50a1..d661e097c364 100644 --- a/Resources/Maps/bagel.yml +++ b/Resources/Maps/bagel.yml @@ -154188,12 +154188,36 @@ entities: parent: 60 - proto: WindoorSecure entities: + - uid: 2538 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 13.5,-11.5 + parent: 60 + - type: DeviceLinkSink + invokeCounter: 1 + - type: DeviceLinkSource + linkedPorts: + 3481: + - DoorStatus: DoorBolt - uid: 3269 components: - type: Transform rot: -1.5707963267948966 rad pos: 23.5,-46.5 parent: 60 + - uid: 3481 + components: + - type: Transform + rot: 1.5707963267948966 rad + pos: 14.5,-13.5 + parent: 60 + - type: DeviceLinkSink + invokeCounter: 1 + - type: DeviceLinkSource + linkedPorts: + 2538: + - DoorStatus: DoorBolt - uid: 3911 components: - type: Transform @@ -154249,30 +154273,6 @@ entities: rot: -1.5707963267948966 rad pos: -23.5,-9.5 parent: 60 - - uid: 2538 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 14.5,-13.5 - parent: 60 - - type: DeviceLinkSink - invokeCounter: 1 - - type: DeviceLinkSource - linkedPorts: - 3481: - - DoorStatus: DoorBolt - - uid: 3481 - components: - - type: Transform - rot: 1.5707963267948966 rad - pos: 13.5,-11.5 - parent: 60 - - type: DeviceLinkSink - invokeCounter: 1 - - type: DeviceLinkSource - linkedPorts: - 2538: - - DoorStatus: DoorBolt - uid: 12188 components: - type: Transform From 8322b1c2d15640a2c81c4746200e857c056005d3 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 18 Sep 2024 15:28:09 +0200 Subject: [PATCH 02/40] New publish workflow for Robust.Cdn (#32222) This uses multiple API requests to directly send the publish to the CDN server, no more GitHub artifacts. Faster, less moving parts. Needs Robust.Cdn 2.2.0 --- .github/workflows/publish.yml | 18 +------- Tools/publish_multi_request.py | 78 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 17 deletions(-) create mode 100644 Tools/publish_multi_request.py diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 16cb5017d6a1..d08ae1350208 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -41,21 +41,10 @@ jobs: - name: Package client run: dotnet run --project Content.Packaging client --no-wipe-release - - name: Upload build artifact - id: artifact-upload-step - uses: actions/upload-artifact@v4 - with: - name: build - path: release/*.zip - compression-level: 0 - retention-days: 0 - - name: Publish version - run: Tools/publish_github_artifact.py + run: Tools/publish_multi_request.py env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} PUBLISH_TOKEN: ${{ secrets.PUBLISH_TOKEN }} - ARTIFACT_ID: ${{ steps.artifact-upload-step.outputs.artifact-id }} GITHUB_REPOSITORY: ${{ vars.GITHUB_REPOSITORY }} - name: Publish changelog (Discord) @@ -68,8 +57,3 @@ jobs: run: Tools/actions_changelog_rss.py env: CHANGELOG_RSS_KEY: ${{ secrets.CHANGELOG_RSS_KEY }} - - - uses: geekyeggo/delete-artifact@v5 - if: always() - with: - name: build diff --git a/Tools/publish_multi_request.py b/Tools/publish_multi_request.py new file mode 100644 index 000000000000..a63359afd6c4 --- /dev/null +++ b/Tools/publish_multi_request.py @@ -0,0 +1,78 @@ +#!/usr/bin/env python3 + +import requests +import os +import subprocess +from typing import Iterable + +PUBLISH_TOKEN = os.environ["PUBLISH_TOKEN"] +VERSION = os.environ["GITHUB_SHA"] + +RELEASE_DIR = "release" + +# +# CONFIGURATION PARAMETERS +# Forks should change these to publish to their own infrastructure. +# +ROBUST_CDN_URL = "https://wizards.cdn.spacestation14.com/" +FORK_ID = "wizards" + +def main(): + session = requests.Session() + session.headers = { + "Authorization": f"Bearer {PUBLISH_TOKEN}", + } + + print(f"Starting publish on Robust.Cdn for version {VERSION}") + + data = { + "version": VERSION, + "engineVersion": get_engine_version(), + } + headers = { + "Content-Type": "application/json" + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/start", json=data, headers=headers) + resp.raise_for_status() + print("Publish successfully started, adding files...") + + for file in get_files_to_publish(): + print(f"Publishing {file}") + with open(file, "rb") as f: + headers = { + "Content-Type": "application/octet-stream", + "Robust-Cdn-Publish-File": os.path.basename(file), + "Robust-Cdn-Publish-Version": VERSION + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/file", data=f, headers=headers) + + resp.raise_for_status() + + print("Successfully pushed files, finishing publish...") + + data = { + "version": VERSION + } + headers = { + "Content-Type": "application/json" + } + resp = session.post(f"{ROBUST_CDN_URL}fork/{FORK_ID}/publish/finish", json=data, headers=headers) + resp.raise_for_status() + + print("SUCCESS!") + + +def get_files_to_publish() -> Iterable[str]: + for file in os.listdir(RELEASE_DIR): + yield os.path.join(RELEASE_DIR, file) + + +def get_engine_version() -> str: + proc = subprocess.run(["git", "describe","--tags", "--abbrev=0"], stdout=subprocess.PIPE, cwd="RobustToolbox", check=True, encoding="UTF-8") + tag = proc.stdout.strip() + assert tag.startswith("v") + return tag[1:] # Cut off v prefix. + + +if __name__ == '__main__': + main() From b55366cf9be9f23ec8d8f17c590cb62c57f92d54 Mon Sep 17 00:00:00 2001 From: Pieter-Jan Briers Date: Wed, 18 Sep 2024 16:09:25 +0200 Subject: [PATCH 03/40] chmod +x publish_multi_request.py (#32274) Fuck. --- Tools/publish_multi_request.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 Tools/publish_multi_request.py diff --git a/Tools/publish_multi_request.py b/Tools/publish_multi_request.py old mode 100644 new mode 100755 From 489938cdb14755b93181aa0de8899363e075c5d3 Mon Sep 17 00:00:00 2001 From: AsnDen <75905158+AsnDen@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:54:00 +0300 Subject: [PATCH 04/40] ghost-role-information-silicon-rules (#32275) changes missing ghost-role-information-rules-default-silicon to ghost-role-information-silicon-rules --- Resources/Prototypes/Entities/Mobs/Player/silicon.yml | 4 ++-- .../Devices/Syndicate_Gadgets/reinforcement_teleporter.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml index 493cfdf6cb63..15878a4017d0 100644 --- a/Resources/Prototypes/Entities/Mobs/Player/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/Player/silicon.yml @@ -462,7 +462,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-assault-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostTakeoverAvailable @@ -495,7 +495,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-saboteur-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostTakeoverAvailable diff --git a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml index 1a7a02e73372..71f98d81c96d 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/Syndicate_Gadgets/reinforcement_teleporter.yml @@ -100,7 +100,7 @@ - type: GhostRole name: ghost-role-information-syndicate-cyborg-assault-name description: ghost-role-information-syndicate-cyborg-description - rules: ghost-role-information-rules-default-silicon + rules: ghost-role-information-silicon-rules raffle: settings: default - type: GhostRoleMobSpawner From ed83593948ef9863e0be8c5b900d1a116c4854ab Mon Sep 17 00:00:00 2001 From: Calecute <34964590+Calecute@users.noreply.github.com> Date: Wed, 18 Sep 2024 12:15:34 -0300 Subject: [PATCH 05/40] Fix guidebook cakebatter recipe (#32276) Bugfix: Add 5 milk to cake batter recipe in the guidebook to correctly reflect new recipe --- Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml index 3eb9c2ca2f2b..7e5e20139b09 100644 --- a/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml +++ b/Resources/ServerInfo/Guidebook/Service/FoodRecipes.xml @@ -13,7 +13,7 @@ WARNING: This is not an automatically generated list, things here may become out - Tortila Dough = 15 Cornmeal, 10 Water - Tofu = 5 Enzyme (Catalyst), 30 Soy Milk - Pie Dough = 2 Eggs (12u), 15 Flour, 5 Table Salt -- Cake Batter = 2 Eggs(12u), 15 flour, 5 Sugar +- Cake Batter = 2 Eggs(12u), 15 flour, 5 Sugar, 5 Milk - Vegan Cake Batter = 15 Soy Milk, 15 Flour, 5 Sugar - Butter = 30 Milk, 5 Table Salt (Catalyst) - Cheese Wheel = 5 Enzyme (Catalyst), 40 Milk From 697f4f5ef94696f54a527103a8ee001d73161afc Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 15:16:42 +0000 Subject: [PATCH 06/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 11609a0efc96..ed88f5c696d2 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Plykiya - changes: - - message: You can now drop food and drinks to stop consuming it. - type: Fix - id: 6891 - time: '2024-07-09T23:12:40.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29854 - author: Boaz1111 changes: - message: Guitars can now be worn in the suit storage slot @@ -3917,3 +3910,10 @@ id: 7390 time: '2024-09-17T22:09:55.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31951 +- author: Calecute + changes: + - message: Corrected cake batter recipe in guidebook + type: Fix + id: 7391 + time: '2024-09-18T15:15:34.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32276 From 9fad1ab14ece4ea2139dedb9a185532b8ed520e1 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:10:53 +0300 Subject: [PATCH 07/40] Wires ui tooltip localization (#32284) * Wires ui tooltip localization * Corrections after review --- Content.Client/Wires/UI/WiresMenu.cs | 9 +-------- .../Locale/en-US/wires/components/wires-component.ftl | 6 ++++++ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/Content.Client/Wires/UI/WiresMenu.cs b/Content.Client/Wires/UI/WiresMenu.cs index eccc548297cd..77fc3accceb3 100644 --- a/Content.Client/Wires/UI/WiresMenu.cs +++ b/Content.Client/Wires/UI/WiresMenu.cs @@ -584,17 +584,10 @@ public StatusLight(StatusLightData data, IResourceCache resourceCache) private sealed class HelpPopup : Popup { - private const string Text = "Click on the gold contacts with a multitool in hand to pulse their wire.\n" + - "Click on the wires with a pair of wirecutters in hand to cut/mend them.\n\n" + - "The lights at the top show the state of the machine, " + - "messing with wires will probably do stuff to them.\n" + - "Wire layouts are different each round, " + - "but consistent between machines of the same type."; - public HelpPopup() { var label = new RichTextLabel(); - label.SetMessage(Text); + label.SetMessage(Loc.GetString("wires-menu-help-popup")); AddChild(new PanelContainer { StyleClasses = {ExamineSystem.StyleClassEntityTooltip}, diff --git a/Resources/Locale/en-US/wires/components/wires-component.ftl b/Resources/Locale/en-US/wires/components/wires-component.ftl index be27c270bb4d..e98e5c21cab2 100644 --- a/Resources/Locale/en-US/wires/components/wires-component.ftl +++ b/Resources/Locale/en-US/wires/components/wires-component.ftl @@ -10,3 +10,9 @@ wires-component-ui-on-receive-message-cannot-mend-uncut-wire = You can't mend a wires-menu-name-label = Wires wires-menu-dead-beef-text = DEAD-BEEF +wires-menu-help-popup = + Click on the gold contacts with a multitool in hand to pulse their wire. + Click on the wires with a pair of wirecutters in hand to cut/mend them. + + The lights at the top show the state of the machine, messing with wires will probably do stuff to them. + Wire layouts are different each round, but consistent between machines of the same type. From 6d4177567eb921f30ffad8588a77068dc0bb96ca Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:16:47 +0300 Subject: [PATCH 08/40] Localization of the shuttle call sender (#32286) --- Content.Server/RoundEnd/RoundEndSystem.cs | 6 +++--- Resources/Locale/en-US/round-end/round-end-system.ftl | 1 + 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/Content.Server/RoundEnd/RoundEndSystem.cs b/Content.Server/RoundEnd/RoundEndSystem.cs index 82bdb78816f0..bb5934f3f08d 100644 --- a/Content.Server/RoundEnd/RoundEndSystem.cs +++ b/Content.Server/RoundEnd/RoundEndSystem.cs @@ -125,7 +125,7 @@ public bool IsRoundEndRequested() return _countdownTokenSource != null; } - public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") + public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") { var duration = DefaultCountdownDuration; @@ -143,7 +143,7 @@ public void RequestRoundEnd(EntityUid? requester = null, bool checkCooldown = tr RequestRoundEnd(duration, requester, checkCooldown, text, name); } - public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "Station") + public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, bool checkCooldown = true, string text = "round-end-system-shuttle-called-announcement", string name = "round-end-system-shuttle-sender-announcement") { if (_gameTicker.RunLevel != GameRunLevel.InRound) return; @@ -183,7 +183,7 @@ public void RequestRoundEnd(TimeSpan countdownTime, EntityUid? requester = null, _chatSystem.DispatchGlobalAnnouncement(Loc.GetString(text, ("time", time), ("units", Loc.GetString(units))), - name, + Loc.GetString(name), false, null, Color.Gold); diff --git a/Resources/Locale/en-US/round-end/round-end-system.ftl b/Resources/Locale/en-US/round-end/round-end-system.ftl index f86851506bc5..30069f717139 100644 --- a/Resources/Locale/en-US/round-end/round-end-system.ftl +++ b/Resources/Locale/en-US/round-end/round-end-system.ftl @@ -4,6 +4,7 @@ round-end-system-shuttle-called-announcement = An emergency shuttle has been sen round-end-system-shuttle-already-called-announcement = An emergency shuttle has already been sent. round-end-system-shuttle-auto-called-announcement = An automatic crew shift change shuttle has been sent. ETA: {$time} {$units}. Recall the shuttle to extend the shift. round-end-system-shuttle-recalled-announcement = The emergency shuttle has been recalled. +round-end-system-shuttle-sender-announcement = Station round-end-system-round-restart-eta-announcement = Restarting the round in {$time} {$units}... eta-units-minutes = minutes From 55b7e3ce0e5216e06db64f6d4c4408a20f48c8c3 Mon Sep 17 00:00:00 2001 From: Skarletto <122584947+Skarletto@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:51:11 -0400 Subject: [PATCH 09/40] change jamjar glasses description (#32215) nerds only please --- Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml index 368cefe9cb4e..467bbf873f23 100644 --- a/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml +++ b/Resources/Prototypes/Entities/Clothing/Eyes/glasses.yml @@ -100,7 +100,7 @@ parent: ClothingEyesBase id: ClothingEyesGlassesJamjar name: jamjar glasses - description: Also known as Virginity Protectors. + description: These retro glasses remind you of a simpler time. components: - type: Sprite sprite: Clothing/Eyes/Glasses/jamjar.rsi From 58119bc3f769cad480b3daaf3dbc5335d8a9c1a9 Mon Sep 17 00:00:00 2001 From: beck-thompson <107373427+beck-thompson@users.noreply.github.com> Date: Wed, 18 Sep 2024 14:58:58 -0700 Subject: [PATCH 10/40] Fix recycler eating materials (Salvage mains rejoice) (#32144) first commit --- Resources/Prototypes/Entities/Structures/Machines/recycler.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml index 8bbbad6c0d19..f62923fe2af3 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/recycler.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/recycler.yml @@ -85,6 +85,7 @@ volume: -3 cutOffSound: false - type: MaterialStorage + insertOnInteract: false - type: Conveyor - type: Rotatable - type: Repairable From 64aab9e41dbef39cd1100dc5eca02e6167fc6572 Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 22:00:05 +0000 Subject: [PATCH 11/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index ed88f5c696d2..9879e7f9a325 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Boaz1111 - changes: - - message: Guitars can now be worn in the suit storage slot - type: Add - id: 6892 - time: '2024-07-09T23:28:10.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29048 - author: Winkarst-cpu changes: - message: Fixed popup spam when trying to open borg's UI while the borg is locked. @@ -3917,3 +3910,10 @@ id: 7391 time: '2024-09-18T15:15:34.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32276 +- author: Beck Thompson + changes: + - message: Recycler no longer allows basic materials to be inserted into it. + type: Fix + id: 7392 + time: '2024-09-18T21:58:59.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32144 From ba24ebfb4f9e887d08b885424241e3365ff43104 Mon Sep 17 00:00:00 2001 From: chavonadelal <156101927+chavonadelal@users.noreply.github.com> Date: Thu, 19 Sep 2024 01:21:53 +0300 Subject: [PATCH 12/40] Localization cooldown/remaining string in alerts (#32282) Cooldown localization --- Content.Client/Actions/UI/ActionAlertTooltip.cs | 2 +- Resources/Locale/en-US/actions/ui/actionslot.ftl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Content.Client/Actions/UI/ActionAlertTooltip.cs b/Content.Client/Actions/UI/ActionAlertTooltip.cs index f805f6643d2f..2425cdefb916 100644 --- a/Content.Client/Actions/UI/ActionAlertTooltip.cs +++ b/Content.Client/Actions/UI/ActionAlertTooltip.cs @@ -101,7 +101,7 @@ protected override void FrameUpdate(FrameEventArgs args) { var duration = Cooldown.Value.End - Cooldown.Value.Start; - if (!FormattedMessage.TryFromMarkup($"[color=#a10505]{(int) duration.TotalSeconds} sec cooldown ({(int) timeLeft.TotalSeconds + 1} sec remaining)[/color]", out var markup)) + if (!FormattedMessage.TryFromMarkup(Loc.GetString("ui-actionslot-duration", ("duration", (int)duration.TotalSeconds), ("timeLeft", (int)timeLeft.TotalSeconds + 1)), out var markup)) return; _cooldownLabel.SetMessage(markup); diff --git a/Resources/Locale/en-US/actions/ui/actionslot.ftl b/Resources/Locale/en-US/actions/ui/actionslot.ftl index 332054f10e9d..c0deaad248c2 100644 --- a/Resources/Locale/en-US/actions/ui/actionslot.ftl +++ b/Resources/Locale/en-US/actions/ui/actionslot.ftl @@ -1,2 +1,2 @@ ui-actionslot-charges = Uses left: {$charges} - +ui-actionslot-duration = [color=#a10505] {$duration} sec cooldown ({$timeLeft} sec remaining)[/color] From 8a924c84ae57dfe18fe0c27f995b4ea16be6a527 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:36:44 +0000 Subject: [PATCH 13/40] add interaction success/failure events (#32216) * add interaction success/failure events * pro --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- .../Interaction/Events/InteractionFailureEvent.cs | 7 +++++++ .../Interaction/Events/InteractionSuccessEvent.cs | 7 +++++++ Content.Shared/Interaction/InteractionPopupSystem.cs | 7 +++++++ 3 files changed, 21 insertions(+) create mode 100644 Content.Shared/Interaction/Events/InteractionFailureEvent.cs create mode 100644 Content.Shared/Interaction/Events/InteractionSuccessEvent.cs diff --git a/Content.Shared/Interaction/Events/InteractionFailureEvent.cs b/Content.Shared/Interaction/Events/InteractionFailureEvent.cs new file mode 100644 index 000000000000..a820048104d0 --- /dev/null +++ b/Content.Shared/Interaction/Events/InteractionFailureEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Interaction.Events; + +/// +/// Raised on the target when failing to pet/hug something. +/// +[ByRefEvent] +public readonly record struct InteractionFailureEvent(EntityUid User); diff --git a/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs b/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs new file mode 100644 index 000000000000..da4f9e43d7d2 --- /dev/null +++ b/Content.Shared/Interaction/Events/InteractionSuccessEvent.cs @@ -0,0 +1,7 @@ +namespace Content.Shared.Interaction.Events; + +/// +/// Raised on the target when successfully petting/hugging something. +/// +[ByRefEvent] +public readonly record struct InteractionSuccessEvent(EntityUid User); diff --git a/Content.Shared/Interaction/InteractionPopupSystem.cs b/Content.Shared/Interaction/InteractionPopupSystem.cs index 2a742d4211b6..20c079dfd8c8 100644 --- a/Content.Shared/Interaction/InteractionPopupSystem.cs +++ b/Content.Shared/Interaction/InteractionPopupSystem.cs @@ -1,6 +1,7 @@ using Content.Shared.Bed.Sleep; using Content.Shared.IdentityManagement; using Content.Shared.Interaction.Components; +using Content.Shared.Interaction.Events; using Content.Shared.Mobs.Components; using Content.Shared.Mobs.Systems; using Content.Shared.Popups; @@ -100,6 +101,9 @@ private void SharedInteract( if (component.InteractSuccessSpawn != null) Spawn(component.InteractSuccessSpawn, _transform.GetMapCoordinates(uid)); + + var ev = new InteractionSuccessEvent(user); + RaiseLocalEvent(target, ref ev); } else { @@ -111,6 +115,9 @@ private void SharedInteract( if (component.InteractFailureSpawn != null) Spawn(component.InteractFailureSpawn, _transform.GetMapCoordinates(uid)); + + var ev = new InteractionFailureEvent(user); + RaiseLocalEvent(target, ref ev); } if (!string.IsNullOrEmpty(component.MessagePerceivedByOthers)) From 2c9a3020ab866510f2ae19a16707f27e1e239288 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:00:48 +0000 Subject: [PATCH 14/40] make epinephrine adrenaline (#32076) Co-authored-by: deltanedas <@deltanedas:kde.org> --- Resources/Prototypes/Reagents/medicine.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Resources/Prototypes/Reagents/medicine.yml b/Resources/Prototypes/Reagents/medicine.yml index 4dcef67f77dd..105ae1104871 100644 --- a/Resources/Prototypes/Reagents/medicine.yml +++ b/Resources/Prototypes/Reagents/medicine.yml @@ -359,6 +359,10 @@ key: KnockedDown time: 0.75 type: Remove + - !type:GenericStatusEffect + key: Adrenaline # Guess what epinephrine is... + component: IgnoreSlowOnDamage + time: 5 # lingers less than hivemind reagent to give it a niche - type: reagent id: Hyronalin From a8686b359779c3e2b22318a2a9234b02b489d9aa Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 23:01:54 +0000 Subject: [PATCH 15/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 9879e7f9a325..58776aa93c48 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Winkarst-cpu - changes: - - message: Fixed popup spam when trying to open borg's UI while the borg is locked. - type: Fix - id: 6893 - time: '2024-07-09T23:48:56.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29861 - author: Lokachop changes: - message: Scarves now count as warm clothing for the warm clothing cargo bounty. @@ -3917,3 +3910,10 @@ id: 7392 time: '2024-09-18T21:58:59.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32144 +- author: deltanedas + changes: + - message: Epinephrine now adds Adrenaline, because it is. + type: Tweak + id: 7393 + time: '2024-09-18T23:00:48.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/32076 From d4a5bc8d6be87a90ee70db4530efa1a0864f177b Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:55:26 -0700 Subject: [PATCH 16/40] Fix unbuckling others when clicking on the strap entity (#29998) * Add failing unbuckle InteractHand test * Skip trybuckle if strap doesn't have space * Unbuckle others not just user * Fix test failing due to delay * Change to raise event instead of calling OnInteractHand * Add test for buckle and unbuckle on InteractHand * Add tick delay * Remove unneeded tick delay and clean up * Comment code * Cleanup * Swap to fastest checks first * Fix reading empty sequence when there are no buckled entities --- .../Tests/Buckle/BuckleTest.Interact.cs | 108 ++++++++++++++++++ .../Tests/Buckle/BuckleTest.cs | 2 +- .../Buckle/SharedBuckleSystem.Interaction.cs | 26 ++++- 3 files changed, 129 insertions(+), 7 deletions(-) create mode 100644 Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs new file mode 100644 index 000000000000..d9cce764ab7d --- /dev/null +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.Interact.cs @@ -0,0 +1,108 @@ +using Content.Shared.Buckle; +using Content.Shared.Buckle.Components; +using Content.Shared.Interaction; +using Robust.Server.GameObjects; +using Robust.Shared.GameObjects; +using Robust.Shared.Map; + +namespace Content.IntegrationTests.Tests.Buckle; + +public sealed partial class BuckleTest +{ + [Test] + public async Task BuckleInteractUnbuckleOther() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency(); + var buckleSystem = entMan.System(); + + EntityUid user = default; + EntityUid victim = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + victim = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(victim, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle victim to chair + Assert.That(buckleSystem.TryBuckle(victim, user, chair, buckle)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(victim), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle victim + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(victim)); + }); + }); + + await pair.CleanReturnAsync(); + } + + [Test] + public async Task BuckleInteractBuckleUnbuckleSelf() + { + await using var pair = await PoolManager.GetServerClient(); + var server = pair.Server; + + var entMan = server.ResolveDependency(); + + EntityUid user = default; + EntityUid chair = default; + BuckleComponent buckle = null; + StrapComponent strap = null; + + await server.WaitAssertion(() => + { + user = entMan.SpawnEntity(BuckleDummyId, MapCoordinates.Nullspace); + chair = entMan.SpawnEntity(StrapDummyId, MapCoordinates.Nullspace); + + Assert.That(entMan.TryGetComponent(user, out buckle)); + Assert.That(entMan.TryGetComponent(chair, out strap)); + +#pragma warning disable RA0002 + buckle.Delay = TimeSpan.Zero; +#pragma warning restore RA0002 + + // Buckle user to chair + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.EqualTo(chair), "Victim did not get buckled to the chair."); + Assert.That(buckle.Buckled, "Victim is not buckled."); + Assert.That(strap.BuckledEntities, Does.Contain(user), "Chair does not have victim buckled to it."); + }); + + // InteractHand with chair to unbuckle + entMan.EventBus.RaiseLocalEvent(chair, new InteractHandEvent(user, chair)); + Assert.Multiple(() => + { + Assert.That(buckle.BuckledTo, Is.Null); + Assert.That(buckle.Buckled, Is.False); + Assert.That(strap.BuckledEntities, Does.Not.Contain(user)); + }); + }); + + await pair.CleanReturnAsync(); + } +} diff --git a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs index 156f42aac333..1b31fe38c289 100644 --- a/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs +++ b/Content.IntegrationTests/Tests/Buckle/BuckleTest.cs @@ -15,7 +15,7 @@ namespace Content.IntegrationTests.Tests.Buckle [TestFixture] [TestOf(typeof(BuckleComponent))] [TestOf(typeof(StrapComponent))] - public sealed class BuckleTest + public sealed partial class BuckleTest { private const string BuckleDummyId = "BuckleDummy"; private const string StrapDummyId = "StrapDummy"; diff --git a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs index 7677e800fe96..1a15e52a3c43 100644 --- a/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs +++ b/Content.Shared/Buckle/SharedBuckleSystem.Interaction.cs @@ -1,5 +1,5 @@ +using System.Linq; using Content.Shared.Buckle.Components; -using Content.Shared.Cuffs.Components; using Content.Shared.DoAfter; using Content.Shared.DragDrop; using Content.Shared.IdentityManagement; @@ -84,15 +84,29 @@ private void OnStrapInteractHand(EntityUid uid, StrapComponent component, Intera if (!TryComp(args.User, out BuckleComponent? buckle)) return; - if (buckle.BuckledTo == null && component.BuckleOnInteractHand) + // Buckle self + if (buckle.BuckledTo == null && component.BuckleOnInteractHand && StrapHasSpace(uid, buckle, component)) + { TryBuckle(args.User, args.User, uid, buckle, popup: true); - else if (buckle.BuckledTo == uid) - TryUnbuckle(args.User, args.User, buckle, popup: true); - else + args.Handled = true; + return; + } + + // Unbuckle self + if (buckle.BuckledTo == uid && TryUnbuckle(args.User, args.User, buckle, popup: true)) + { + args.Handled = true; return; + } + + // Unbuckle others + if (component.BuckledEntities.TryFirstOrNull(out var buckled) && TryUnbuckle(buckled.Value, args.User)) + { + args.Handled = true; + return; + } // TODO BUCKLE add out bool for whether a pop-up was generated or not. - args.Handled = true; } private void OnBuckleInteractHand(Entity ent, ref InteractHandEvent args) From 7ceb2d250799474c6c627121a0cfde7bf90379d4 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 16:55:53 -0700 Subject: [PATCH 17/40] Add a method to get the first available ItemSlot (#29846) * Add a method to get the first available ItemSlot * Make TryInsertEmpty use TryGetAvailableSlot * Add param doc comments --- .../Containers/ItemSlot/ItemSlotsSystem.cs | 69 ++++++++++++++----- 1 file changed, 53 insertions(+), 16 deletions(-) diff --git a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs index f41fa2b22d2c..f25273f40394 100644 --- a/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs +++ b/Content.Shared/Containers/ItemSlot/ItemSlotsSystem.cs @@ -359,39 +359,76 @@ public bool TryInsertFromHand(EntityUid uid, ItemSlot slot, EntityUid user, Hand /// Useful for predicted interactions /// /// False if failed to insert item - public bool TryInsertEmpty(Entity ent, EntityUid item, EntityUid? user, bool excludeUserAudio = false) + public bool TryInsertEmpty(Entity ent, + EntityUid item, + EntityUid? user, + bool excludeUserAudio = false) { + if (!Resolve(ent, ref ent.Comp, false)) + return false; + + TryComp(user, out HandsComponent? handsComp); + + if (!TryGetAvailableSlot(ent, + item, + user == null ? null : (user.Value, handsComp), + out var itemSlot, + emptyOnly: true)) + return false; + + if (user != null && !_handsSystem.TryDrop(user.Value, item, handsComp: handsComp)) + return false; + + Insert(ent, itemSlot, item, user, excludeUserAudio: excludeUserAudio); + return true; + } + + /// + /// Tries to get any slot that the can be inserted into. + /// + /// Entity that is being inserted into. + /// Entity being inserted into . + /// Entity inserting into . + /// The ItemSlot on to insert into. + /// True only returns slots that are empty. + /// False returns any slot that is able to receive . + /// True when a slot is found. Otherwise, false. + public bool TryGetAvailableSlot(Entity ent, + EntityUid item, + Entity? userEnt, + [NotNullWhen(true)] out ItemSlot? itemSlot, + bool emptyOnly = false) + { + itemSlot = null; + + if (userEnt is { } user + && Resolve(user, ref user.Comp) + && _handsSystem.IsHolding(user, item)) + { + if (!_handsSystem.CanDrop(user, item, user.Comp)) + return false; + } + if (!Resolve(ent, ref ent.Comp, false)) return false; var slots = new List(); foreach (var slot in ent.Comp.Slots.Values) { - if (slot.ContainerSlot?.ContainedEntity != null) + if (emptyOnly && slot.ContainerSlot?.ContainedEntity != null) continue; - if (CanInsert(ent, item, user, slot)) + if (CanInsert(ent, item, userEnt, slot)) slots.Add(slot); } if (slots.Count == 0) return false; - if (user != null && _handsSystem.IsHolding(user.Value, item)) - { - if (!_handsSystem.TryDrop(user.Value, item)) - return false; - } - slots.Sort(SortEmpty); - foreach (var slot in slots) - { - if (TryInsert(ent, slot, item, user, excludeUserAudio: excludeUserAudio)) - return true; - } - - return false; + itemSlot = slots[0]; + return true; } private static int SortEmpty(ItemSlot a, ItemSlot b) From e6e166405d1008db374363d41d78459330d9f19f Mon Sep 17 00:00:00 2001 From: PJBot Date: Wed, 18 Sep 2024 23:56:32 +0000 Subject: [PATCH 18/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 58776aa93c48..8190ecd8fe4f 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Lokachop - changes: - - message: Scarves now count as warm clothing for the warm clothing cargo bounty. - type: Tweak - id: 6894 - time: '2024-07-10T05:26:33.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29779 - author: Aquif changes: - message: It is now possible to "lock" admin faxes such that they cannot be edited @@ -3917,3 +3910,11 @@ id: 7393 time: '2024-09-18T23:00:48.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/32076 +- author: ShadowCommander + changes: + - message: Fixed clicking on chairs and beds with an entity buckled to them not + unbuckling them. + type: Fix + id: 7394 + time: '2024-09-18T23:55:26.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29998 From 84062da1289b760ee8714239322ae07b74e6187c Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:58:10 +0000 Subject: [PATCH 19/40] let FlashArea be called from shared (#30343) * let FlashArea be called from shared * untroll --------- Co-authored-by: deltanedas <@deltanedas:kde.org> Co-authored-by: metalgearsloth --- Content.Client/Flash/FlashOverlay.cs | 4 +++- Content.Server/Flash/FlashSystem.cs | 2 +- Content.Shared/Flash/SharedFlashSystem.cs | 13 +++++++++---- 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/Content.Client/Flash/FlashOverlay.cs b/Content.Client/Flash/FlashOverlay.cs index 046be2aa6214..8e41c382dd7e 100644 --- a/Content.Client/Flash/FlashOverlay.cs +++ b/Content.Client/Flash/FlashOverlay.cs @@ -16,6 +16,7 @@ public sealed class FlashOverlay : Overlay [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IGameTiming _timing = default!; + private readonly SharedFlashSystem _flash; private readonly StatusEffectsSystem _statusSys; public override OverlaySpace Space => OverlaySpace.WorldSpace; @@ -27,6 +28,7 @@ public FlashOverlay() { IoCManager.InjectDependencies(this); _shader = _prototypeManager.Index("FlashedEffect").InstanceUnique(); + _flash = _entityManager.System(); _statusSys = _entityManager.System(); } @@ -41,7 +43,7 @@ protected override void FrameUpdate(FrameEventArgs args) || !_entityManager.TryGetComponent(playerEntity, out var status)) return; - if (!_statusSys.TryGetTime(playerEntity.Value, SharedFlashSystem.FlashedKey, out var time, status)) + if (!_statusSys.TryGetTime(playerEntity.Value, _flash.FlashedKey, out var time, status)) return; var curTime = _timing.CurTime; diff --git a/Content.Server/Flash/FlashSystem.cs b/Content.Server/Flash/FlashSystem.cs index ccb58e94f814..fb449a372cd4 100644 --- a/Content.Server/Flash/FlashSystem.cs +++ b/Content.Server/Flash/FlashSystem.cs @@ -152,7 +152,7 @@ public void Flash(EntityUid target, } } - public void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) + public override void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { var transform = Transform(source); var mapPosition = _transform.GetMapCoordinates(transform); diff --git a/Content.Shared/Flash/SharedFlashSystem.cs b/Content.Shared/Flash/SharedFlashSystem.cs index f83f02a31058..b7788098870b 100644 --- a/Content.Shared/Flash/SharedFlashSystem.cs +++ b/Content.Shared/Flash/SharedFlashSystem.cs @@ -1,10 +1,15 @@ +using Content.Shared.Flash.Components; using Content.Shared.StatusEffect; +using Robust.Shared.Audio; +using Robust.Shared.Prototypes; -namespace Content.Shared.Flash +namespace Content.Shared.Flash; + +public abstract class SharedFlashSystem : EntitySystem { - public abstract class SharedFlashSystem : EntitySystem + public ProtoId FlashedKey = "Flashed"; + + public virtual void FlashArea(Entity source, EntityUid? user, float range, float duration, float slowTo = 0.8f, bool displayPopup = false, float probability = 1f, SoundSpecifier? sound = null) { - [ValidatePrototypeId] - public const string FlashedKey = "Flashed"; } } From 1c839da60496f4a3171c7f959a88effe4aeff5a8 Mon Sep 17 00:00:00 2001 From: deltanedas <39013340+deltanedas@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:01:40 +0000 Subject: [PATCH 20/40] move TriggerExplosion to shared (#30227) * move component to shared * add fake systems * update server explosion system and remove duplicate transform query --------- Co-authored-by: deltanedas <@deltanedas:kde.org> --- Content.Client/Explosion/ExplosionSystem.cs | 5 +-- .../Behaviors/SolutionExplosionBehavior.cs | 2 +- .../EntitySystems/ExplosionSystem.Airtight.cs | 3 +- .../EntitySystems/ExplosionSystem.CVars.cs | 4 +-- .../EntitySystems/ExplosionSystem.GridMap.cs | 2 +- .../ExplosionSystem.Processing.cs | 7 ++-- .../EntitySystems/ExplosionSystem.TileFill.cs | 4 +-- .../EntitySystems/ExplosionSystem.Visuals.cs | 3 +- .../EntitySystems/ExplosionSystem.cs | 15 +++----- .../Components/ExplosiveComponent.cs | 35 +++++++------------ .../EntitySystems/SharedExplosionSystem.cs | 25 ++++++++++--- 11 files changed, 52 insertions(+), 53 deletions(-) rename {Content.Server => Content.Shared}/Explosion/Components/ExplosiveComponent.cs (76%) diff --git a/Content.Client/Explosion/ExplosionSystem.cs b/Content.Client/Explosion/ExplosionSystem.cs index a2ed2d50e0d1..692782ded4b7 100644 --- a/Content.Client/Explosion/ExplosionSystem.cs +++ b/Content.Client/Explosion/ExplosionSystem.cs @@ -2,7 +2,4 @@ namespace Content.Client.Explosion.EntitySystems; -public sealed class ExplosionSystem : SharedExplosionSystem -{ - -} +public sealed class ExplosionSystem : SharedExplosionSystem; diff --git a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs index 5166aaccabba..08c7c8f068f8 100644 --- a/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs +++ b/Content.Server/Destructible/Thresholds/Behaviors/SolutionExplosionBehavior.cs @@ -1,4 +1,4 @@ -using Content.Server.Explosion.Components; +using Content.Shared.Explosion.Components; using JetBrains.Annotations; namespace Content.Server.Destructible.Thresholds.Behaviors diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs index 4b59c8f1c48f..6fa553bc8b60 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Airtight.cs @@ -6,9 +6,10 @@ using Content.Shared.Explosion.EntitySystems; using Content.Shared.FixedPoint; using Robust.Shared.Map.Components; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { [Dependency] private readonly DestructibleSystem _destructibleSystem = default!; diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs index ce98f89de7af..5af06ef93684 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.CVars.cs @@ -1,8 +1,8 @@ using Content.Shared.CCVar; -using Content.Shared.Explosion.EntitySystems; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { public int MaxIterations { get; private set; } public int MaxArea { get; private set; } diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs index 75bb606441a4..29477c16b28e 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.GridMap.cs @@ -12,7 +12,7 @@ namespace Content.Server.Explosion.EntitySystems; // A good portion of it is focused around keeping track of what tile-indices on a grid correspond to tiles that border // space. AFAIK no other system currently needs to track these "edge-tiles". If they do, this should probably be a // property of the grid itself? -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { /// /// Set of tiles of each grid that are directly adjacent to space, along with the directions that face space. diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs index 6d0cbcf2794c..97d52e436a8f 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Processing.cs @@ -22,9 +22,10 @@ using Robust.Shared.Timing; using Robust.Shared.Utility; using TimedDespawnComponent = Robust.Shared.Spawners.TimedDespawnComponent; + namespace Content.Server.Explosion.EntitySystems; -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { [Dependency] private readonly FlammableSystem _flammableSystem = default!; @@ -218,7 +219,7 @@ internal bool ExplodeTile(BroadphaseComponent lookup, // get the entities on a tile. Note that we cannot process them directly, or we get // enumerator-changed-while-enumerating errors. List<(EntityUid, TransformComponent)> list = new(); - var state = (list, processed, _transformQuery); + var state = (list, processed, EntityManager.TransformQuery); // get entities: lookup.DynamicTree.QueryAabb(ref state, GridQueryCallback, gridBox, true); @@ -317,7 +318,7 @@ internal void ExplodeSpace(BroadphaseComponent lookup, var gridBox = Box2.FromDimensions(tile * DefaultTileSize, new Vector2(DefaultTileSize, DefaultTileSize)); var worldBox = spaceMatrix.TransformBox(gridBox); var list = new List<(EntityUid, TransformComponent)>(); - var state = (list, processed, invSpaceMatrix, lookup.Owner, _transformQuery, gridBox, _transformSystem); + var state = (list, processed, invSpaceMatrix, lookup.Owner, EntityManager.TransformQuery, gridBox, _transformSystem); // get entities: lookup.DynamicTree.QueryAabb(ref state, SpaceQueryCallback, worldBox, true); diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs index 8c3229e06eef..7b73490d9467 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.TileFill.cs @@ -7,13 +7,13 @@ using Robust.Shared.Map.Components; using Robust.Shared.Physics.Components; using Robust.Shared.Timing; -using Content.Shared.Explosion.EntitySystems; + namespace Content.Server.Explosion.EntitySystems; // This partial part of the explosion system has all of the functions used to create the actual explosion map. // I.e, to get the sets of tiles & intensity values that describe an explosion. -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { /// /// This is the main explosion generating function. diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs index 219dba4bdeb8..57323e4de709 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.Visuals.cs @@ -5,10 +5,11 @@ using Robust.Server.GameObjects; using Robust.Shared.GameStates; using Robust.Shared.Map; + namespace Content.Server.Explosion.EntitySystems; // This part of the system handled send visual / overlay data to clients. -public sealed partial class ExplosionSystem : SharedExplosionSystem +public sealed partial class ExplosionSystem { public void InitVisuals() { diff --git a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs index cd0ca1c22eb2..818953ed4b47 100644 --- a/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs +++ b/Content.Server/Explosion/EntitySystems/ExplosionSystem.cs @@ -12,6 +12,8 @@ using Content.Shared.Damage; using Content.Shared.Database; using Content.Shared.Explosion; +using Content.Shared.Explosion.Components; +using Content.Shared.Explosion.EntitySystems; using Content.Shared.GameTicking; using Content.Shared.Inventory; using Content.Shared.Projectiles; @@ -53,7 +55,6 @@ public sealed partial class ExplosionSystem : SharedExplosionSystem [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly SharedMapSystem _map = default!; - private EntityQuery _transformQuery; private EntityQuery _flammableQuery; private EntityQuery _physicsQuery; private EntityQuery _projectileQuery; @@ -103,7 +104,6 @@ public override void Initialize() InitAirtightMap(); InitVisuals(); - _transformQuery = GetEntityQuery(); _flammableQuery = GetEntityQuery(); _physicsQuery = GetEntityQuery(); _projectileQuery = GetEntityQuery(); @@ -141,15 +141,8 @@ private void OnGetResistance(EntityUid uid, ExplosionResistanceComponent compone args.DamageCoefficient *= modifier; } - /// - /// Given an entity with an explosive component, spawn the appropriate explosion. - /// - /// - /// Also accepts radius or intensity arguments. This is useful for explosives where the intensity is not - /// specified in the yaml / by the component, but determined dynamically (e.g., by the quantity of a - /// solution in a reaction). - /// - public void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) + /// + public override void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) { // log missing: false, because some entities (e.g. liquid tanks) attempt to trigger explosions when damaged, // but may not actually be explosive. diff --git a/Content.Server/Explosion/Components/ExplosiveComponent.cs b/Content.Shared/Explosion/Components/ExplosiveComponent.cs similarity index 76% rename from Content.Server/Explosion/Components/ExplosiveComponent.cs rename to Content.Shared/Explosion/Components/ExplosiveComponent.cs index 2b27a89d9db7..bab7f5a7d678 100644 --- a/Content.Server/Explosion/Components/ExplosiveComponent.cs +++ b/Content.Shared/Explosion/Components/ExplosiveComponent.cs @@ -1,8 +1,7 @@ -using Content.Server.Explosion.EntitySystems; -using Content.Shared.Explosion; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; +using Content.Shared.Explosion.EntitySystems; +using Robust.Shared.Prototypes; -namespace Content.Server.Explosion.Components; +namespace Content.Shared.Explosion.Components; /// /// Specifies an explosion that can be spawned by this entity. The explosion itself is spawned via -[RegisterComponent] +[RegisterComponent, Access(typeof(SharedExplosionSystem))] public sealed partial class ExplosiveComponent : Component { - /// /// The explosion prototype. This determines the damage types, the tile-break chance, and some visual /// information (e.g., the light that the explosion gives off). /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("explosionType", required: true, customTypeSerializer: typeof(PrototypeIdSerializer))] - public string ExplosionType = default!; + [DataField(required: true)] + public ProtoId ExplosionType = default!; /// /// The maximum intensity the explosion can have on a single tile. This limits the maximum damage and tile /// break chance the explosion can achieve at any given location. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxIntensity")] + [DataField] public float MaxIntensity = 4; /// /// How quickly the intensity drops off as you move away from the epicenter. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("intensitySlope")] + [DataField] public float IntensitySlope = 1; /// @@ -47,38 +42,34 @@ public sealed partial class ExplosiveComponent : Component /// This number can be overridden by passing optional argument to . /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("totalIntensity")] + [DataField] public float TotalIntensity = 10; /// /// Factor used to scale the explosion intensity when calculating tile break chances. Allows for stronger /// explosives that don't space tiles, without having to create a new explosion-type prototype. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("tileBreakScale")] + [DataField] public float TileBreakScale = 1f; /// /// Maximum number of times that an explosive can break a tile. Currently, for normal space stations breaking a /// tile twice will generally result in a vacuum. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("maxTileBreak")] + [DataField] public int MaxTileBreak = int.MaxValue; /// /// Whether this explosive should be able to create a vacuum by breaking tiles. /// - [ViewVariables(VVAccess.ReadWrite)] - [DataField("canCreateVacuum")] + [DataField] public bool CanCreateVacuum = true; /// /// An override for whether or not the entity should be deleted after it explodes. /// If null, the system calling the explode method handles it. /// - [DataField("deleteAfterExplosion")] + [DataField] public bool? DeleteAfterExplosion; /// diff --git a/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs b/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs index 1d926dd0b67d..f29825580784 100644 --- a/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs +++ b/Content.Shared/Explosion/EntitySystems/SharedExplosionSystem.cs @@ -1,25 +1,40 @@ -using Content.Shared.Explosion.Components; using Content.Shared.Armor; +using Content.Shared.Explosion.Components; namespace Content.Shared.Explosion.EntitySystems; +/// +/// Lets code in shared trigger explosions and handles explosion resistance examining. +/// All processing is still done clientside. +/// public abstract class SharedExplosionSystem : EntitySystem { - public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnArmorExamine); } - private void OnArmorExamine(EntityUid uid, ExplosionResistanceComponent component, ref ArmorExamineEvent args) + private void OnArmorExamine(Entity ent, ref ArmorExamineEvent args) { - var value = MathF.Round((1f - component.DamageCoefficient) * 100, 1); + var value = MathF.Round((1f - ent.Comp.DamageCoefficient) * 100, 1); if (value == 0) return; args.Msg.PushNewline(); - args.Msg.AddMarkupOrThrow(Loc.GetString(component.Examine, ("value", value))); + args.Msg.AddMarkupOrThrow(Loc.GetString(ent.Comp.Examine, ("value", value))); + } + + /// + /// Given an entity with an explosive component, spawn the appropriate explosion. + /// + /// + /// Also accepts radius or intensity arguments. This is useful for explosives where the intensity is not + /// specified in the yaml / by the component, but determined dynamically (e.g., by the quantity of a + /// solution in a reaction). + /// + public virtual void TriggerExplosive(EntityUid uid, ExplosiveComponent? explosive = null, bool delete = true, float? totalIntensity = null, float? radius = null, EntityUid? user = null) + { } } From 4f77709eed9b5012e58303820eafb0242a0f36fd Mon Sep 17 00:00:00 2001 From: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:02:27 +1000 Subject: [PATCH 21/40] Add flip button to mapping state (#30636) --- Content.Client/Mapping/MappingScreen.xaml | 1 + Content.Client/Mapping/MappingScreen.xaml.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+) diff --git a/Content.Client/Mapping/MappingScreen.xaml b/Content.Client/Mapping/MappingScreen.xaml index b64136084788..9cc3e734f0e9 100644 --- a/Content.Client/Mapping/MappingScreen.xaml +++ b/Content.Client/Mapping/MappingScreen.xaml @@ -78,6 +78,7 @@ ToolTip="Pick (Hold 5)" /> + diff --git a/Content.Client/Mapping/MappingScreen.xaml.cs b/Content.Client/Mapping/MappingScreen.xaml.cs index b2ad2fd83fbb..46c0e51fad69 100644 --- a/Content.Client/Mapping/MappingScreen.xaml.cs +++ b/Content.Client/Mapping/MappingScreen.xaml.cs @@ -96,6 +96,22 @@ public MappingScreen() Pick.Texture.TexturePath = "/Textures/Interface/eyedropper.svg.png"; Delete.Texture.TexturePath = "/Textures/Interface/eraser.svg.png"; + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png"; + Flip.OnPressed += args => FlipSides(); + } + + public void FlipSides() + { + ScreenContainer.Flip(); + + if (SpawnContainer.GetPositionInParent() == 0) + { + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_cw.svg.192dpi.png"; + } + else + { + Flip.Texture.TexturePath = "/Textures/Interface/VerbIcons/rotate_ccw.svg.192dpi.png"; + } } private void OnDecalColorPicked(Color color) From 6958789f37db66d54a8c68f6d04d997c8f1650ab Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Wed, 18 Sep 2024 17:08:37 -0700 Subject: [PATCH 22/40] Give prototype refactor (#29697) * Update GivePrototype * File scoped namespace * Change to EntProtoId instead of ProtoId<> for better validation --- .../Construction/Completions/GivePrototype.cs | 54 ++++++++++--------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/Content.Server/Construction/Completions/GivePrototype.cs b/Content.Server/Construction/Completions/GivePrototype.cs index f45bd5ba1052..f05feb70c034 100644 --- a/Content.Server/Construction/Completions/GivePrototype.cs +++ b/Content.Server/Construction/Completions/GivePrototype.cs @@ -1,44 +1,50 @@ using Content.Server.Stack; using Content.Shared.Construction; +using Content.Shared.Hands.Components; using Content.Shared.Hands.EntitySystems; using Content.Shared.Prototypes; using Content.Shared.Stacks; using JetBrains.Annotations; using Robust.Shared.Prototypes; -using Robust.Shared.Serialization.TypeSerializers.Implementations.Custom.Prototype; -namespace Content.Server.Construction.Completions +namespace Content.Server.Construction.Completions; + +[UsedImplicitly] +[DataDefinition] +public sealed partial class GivePrototype : IGraphAction { - [UsedImplicitly] - [DataDefinition] - public sealed partial class GivePrototype : IGraphAction + [DataField] + public EntProtoId Prototype { get; private set; } = string.Empty; + + [DataField] + public int Amount { get; private set; } = 1; + + public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) { - [DataField("prototype", customTypeSerializer:typeof(PrototypeIdSerializer))] - public string Prototype { get; private set; } = string.Empty; - [DataField("amount")] - public int Amount { get; private set; } = 1; + if (string.IsNullOrEmpty(Prototype)) + return; - public void PerformAction(EntityUid uid, EntityUid? userUid, IEntityManager entityManager) + if (EntityPrototypeHelpers.HasComponent(Prototype)) { - if (string.IsNullOrEmpty(Prototype)) - return; + var stackSystem = entityManager.EntitySysManager.GetEntitySystem(); + var stacks = stackSystem.SpawnMultiple(Prototype, Amount, userUid ?? uid); - var coordinates = entityManager.GetComponent(userUid ?? uid).Coordinates; + if (userUid is null || !entityManager.TryGetComponent(userUid, out HandsComponent? handsComp)) + return; - if (EntityPrototypeHelpers.HasComponent(Prototype)) + foreach (var item in stacks) { - var stackEnt = entityManager.SpawnEntity(Prototype, coordinates); - var stack = entityManager.GetComponent(stackEnt); - entityManager.EntitySysManager.GetEntitySystem().SetCount(stackEnt, Amount, stack); - entityManager.EntitySysManager.GetEntitySystem().PickupOrDrop(userUid, stackEnt); + stackSystem.TryMergeToHands(item, userUid.Value, hands: handsComp); } - else + } + else + { + var handsSystem = entityManager.EntitySysManager.GetEntitySystem(); + var handsComp = userUid is not null ? entityManager.GetComponent(userUid.Value) : null; + for (var i = 0; i < Amount; i++) { - for (var i = 0; i < Amount; i++) - { - var item = entityManager.SpawnEntity(Prototype, coordinates); - entityManager.EntitySysManager.GetEntitySystem().PickupOrDrop(userUid, item); - } + var item = entityManager.SpawnNextToOrDrop(Prototype, userUid ?? uid); + handsSystem.PickupOrDrop(userUid, item, handsComp: handsComp); } } } From cc7e5e01508b6ac79d6e85b18ec4ec7bc839ec71 Mon Sep 17 00:00:00 2001 From: SlamBamActionman <83650252+SlamBamActionman@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:14:29 +0200 Subject: [PATCH 23/40] Allow containment field generators to be enabled on mapinit (#31158) * Initial commit * review fix --- .../EntitySystems/ContainmentFieldGeneratorSystem.cs | 7 +++++++ .../Components/ContainmentFieldGeneratorComponent.cs | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs index 05262f299962..6d97c8ccb3dd 100644 --- a/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs +++ b/Content.Server/Singularity/EntitySystems/ContainmentFieldGeneratorSystem.cs @@ -37,6 +37,7 @@ public override void Initialize() SubscribeLocalEvent(OnUnanchorAttempt); SubscribeLocalEvent(OnComponentRemoved); SubscribeLocalEvent(PreventBreach); + SubscribeLocalEvent(OnMapInit); } public override void Update(float frameTime) @@ -61,6 +62,12 @@ public override void Update(float frameTime) #region Events + private void OnMapInit(Entity generator, ref MapInitEvent args) + { + if (generator.Comp.Enabled) + ChangeFieldVisualizer(generator); + } + /// /// A generator receives power from a source colliding with it. /// diff --git a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs index 938b34f354a6..6b09edfa1f00 100644 --- a/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs +++ b/Content.Shared/Singularity/Components/ContainmentFieldGeneratorComponent.cs @@ -79,7 +79,7 @@ public int PowerBuffer /// /// Is the generator toggled on? /// - [ViewVariables] + [DataField] public bool Enabled; /// From c2a201d998830b36fa525c5ee9bb1375bf41d732 Mon Sep 17 00:00:00 2001 From: Winkarst <74284083+Winkarst-cpu@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:23:50 +0300 Subject: [PATCH 24/40] Make fire leave burnt decals on the tiles (#31939) * Make fire leave burnt decals on the tiles * License * Yes * Update * Spelling error * Prototypes reload support * To array --- .../EntitySystems/AtmosphereSystem.Hotspot.cs | 33 +++++++++++++++--- .../Atmos/EntitySystems/AtmosphereSystem.cs | 19 ++++++++++ Resources/Prototypes/Decals/burnt.yml | 31 ++++++++++++++++ .../Textures/Decals/burnt.rsi/burnt1.png | Bin 0 -> 896 bytes .../Textures/Decals/burnt.rsi/burnt2.png | Bin 0 -> 938 bytes .../Textures/Decals/burnt.rsi/burnt3.png | Bin 0 -> 928 bytes .../Textures/Decals/burnt.rsi/burnt4.png | Bin 0 -> 1041 bytes Resources/Textures/Decals/burnt.rsi/meta.json | 27 ++++++++++++++ 8 files changed, 106 insertions(+), 4 deletions(-) create mode 100644 Resources/Prototypes/Decals/burnt.yml create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt1.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt2.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt3.png create mode 100644 Resources/Textures/Decals/burnt.rsi/burnt4.png create mode 100644 Resources/Textures/Decals/burnt.rsi/meta.json diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs index db952237338f..a03f27b561ae 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.Hotspot.cs @@ -1,19 +1,21 @@ using Content.Server.Atmos.Components; -using Content.Server.Atmos.Reactions; +using Content.Server.Decals; using Content.Shared.Atmos; using Content.Shared.Atmos.Components; using Content.Shared.Atmos.Reactions; -using Content.Shared.Audio; using Content.Shared.Database; using Robust.Shared.Audio; using Robust.Shared.Map; using Robust.Shared.Map.Components; -using Robust.Shared.Player; +using Robust.Shared.Random; namespace Content.Server.Atmos.EntitySystems { public sealed partial class AtmosphereSystem { + [Dependency] private readonly DecalSystem _decalSystem = default!; + [Dependency] private readonly IRobustRandom _random = default!; + private const int HotspotSoundCooldownCycles = 200; private int _hotspotSoundCooldown = 0; @@ -56,7 +58,30 @@ private void ProcessHotspot( if (tile.Hotspot.Bypassing) { tile.Hotspot.State = 3; - // TODO ATMOS: Burn tile here + + var gridUid = ent.Owner; + var tilePos = tile.GridIndices; + + // Get the existing decals on the tile + var tileDecals = _decalSystem.GetDecalsInRange(gridUid, tilePos); + + // Count the burnt decals on the tile + var tileBurntDecals = 0; + + foreach (var set in tileDecals) + { + if (Array.IndexOf(_burntDecals, set.Decal.Id) == -1) + continue; + + tileBurntDecals++; + + if (tileBurntDecals > 4) + break; + } + + // Add a random burned decal to the tile only if there are less than 4 of them + if (tileBurntDecals < 4) + _decalSystem.TryAddDecal(_burntDecals[_random.Next(_burntDecals.Length)], new EntityCoordinates(gridUid, tilePos), out _, cleanable: true); if (tile.Air.Temperature > Atmospherics.FireMinimumTemperatureToSpread) { diff --git a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs index 44bfa4cc10c7..13d8f73dc56b 100644 --- a/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs +++ b/Content.Server/Atmos/EntitySystems/AtmosphereSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Fluids.EntitySystems; using Content.Server.NodeContainer.EntitySystems; using Content.Shared.Atmos.EntitySystems; +using Content.Shared.Decals; using Content.Shared.Doors.Components; using Content.Shared.Maps; using JetBrains.Annotations; @@ -12,7 +13,9 @@ using Robust.Shared.Containers; using Robust.Shared.Map; using Robust.Shared.Physics.Systems; +using Robust.Shared.Prototypes; using Robust.Shared.Random; +using System.Linq; namespace Content.Server.Atmos.EntitySystems; @@ -36,6 +39,7 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem [Dependency] private readonly SharedTransformSystem _transformSystem = default!; [Dependency] private readonly TileSystem _tile = default!; [Dependency] private readonly MapSystem _map = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; [Dependency] public readonly PuddleSystem Puddle = default!; private const float ExposedUpdateDelay = 1f; @@ -47,6 +51,8 @@ public sealed partial class AtmosphereSystem : SharedAtmosphereSystem private EntityQuery _firelockQuery; private HashSet _entSet = new(); + private string[] _burntDecals = []; + public override void Initialize() { base.Initialize(); @@ -66,7 +72,9 @@ public override void Initialize() _firelockQuery = GetEntityQuery(); SubscribeLocalEvent(OnTileChanged); + SubscribeLocalEvent(OnPrototypesReloaded); + CacheDecals(); } public override void Shutdown() @@ -81,6 +89,12 @@ private void OnTileChanged(ref TileChangedEvent ev) InvalidateTile(ev.NewTile.GridUid, ev.NewTile.GridIndices); } + private void OnPrototypesReloaded(PrototypesReloadedEventArgs ev) + { + if (ev.WasModified()) + CacheDecals(); + } + public override void Update(float frameTime) { base.Update(frameTime); @@ -107,4 +121,9 @@ public override void Update(float frameTime) _exposedTimer -= ExposedUpdateDelay; } + + private void CacheDecals() + { + _burntDecals = _prototypeManager.EnumeratePrototypes().Where(x => x.Tags.Contains("burnt")).Select(x => x.ID).ToArray(); + } } diff --git a/Resources/Prototypes/Decals/burnt.yml b/Resources/Prototypes/Decals/burnt.yml new file mode 100644 index 000000000000..d9d500e1aa25 --- /dev/null +++ b/Resources/Prototypes/Decals/burnt.yml @@ -0,0 +1,31 @@ +- type: decal + id: burnt1 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt1 + +- type: decal + id: burnt2 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt2 + +- type: decal + id: burnt3 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt3 + +- type: decal + id: burnt4 + tags: ["burnt"] + defaultCleanable: true + sprite: + sprite: Decals/burnt.rsi + state: burnt4 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt1.png b/Resources/Textures/Decals/burnt.rsi/burnt1.png new file mode 100644 index 0000000000000000000000000000000000000000..3fcb7a4949b5bd561e68d784d47d9de20a5411d2 GIT binary patch literal 896 zcmV-`1AqL9P)_`sikSPhHe~3@fwDqi`!27YaPdN z#XAQ{Mbb&qIqVecW=VHRx3Ec4r4L^n0fb{a_q`;oVHMzdNk>T+Sc&%@lCF||0?2Ft z@TYMc*YYNKA9lck1x~sM{t=mf#{D6J5x9NYmwnV>7*yT_FA<=R=W95g?Z)O zXSr#2Y=Ql?;o%@8o6DVb-DIUOt;rA7Zqkdr_f#YackO{-WHbkhbz#xIZKXZvnvEm5 zqy=1*J0rIo$w#m!1hcO>t!)7E3@{KcA~AFJ1mfTv&z_QJ?G^KYLr)tTSp~V56pmai zijU>lBbsI)jXMU>N%|82%xnYVQR|G~sBqFV0d4O6tE9hS-})Wbk4UT*l<1YPa0dME z%4dp2&wEZnHs9=N?ya7z8ydklV$1s3jzCLe6r|b5_i)Oi)aKYqGeBI^ZuBez`a(2a-$50Ok=tVpxs0ZTk;p WW37K`!OrIZ0000C literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt2.png b/Resources/Textures/Decals/burnt.rsi/burnt2.png new file mode 100644 index 0000000000000000000000000000000000000000..01f8f220b2ddae1a13fac2b816531109a5b848d9 GIT binary patch literal 938 zcmV;b16BNqP)18A2vnpw(ar z1~qsht;3vCD6w`Ao}uGYnUsA1aPJrnOd)6t3!DMiI$6ER(;`s9#u7N6pd4cTwdf`G z2_S*!hJ`)wbZg_0F*v6MHg>;GCHx+Tzwt=JH}-T(U;23XN71bm6J#p9IFTkcm5gqK z^tAwduWz%!Cu7Bw`%{PCis#BPcvk^T9Mi6`N4!4&RvUe%3k*DgXzsb>EVX7P2z~>G z2Krrr1)9=8G5B6W`vj{g4YsN1zcPIW zV5X|>9a}N0^|cQ3pfrEhjEwHJG@W?V`+P6qA}w&JCyhP*2=lg}bc01jVF^I8;Vi)i z$25J`1XEDr2dgllPFL=UA+3cqy1hLF*B(=5xn)$H0500m$U z0e2oTkWELyx%aGmdnf@ivuFkGjjv`jofKps$SYI+o{QLmWYm8K086<%#GyXvdo6YO3$m!Aax?qf)&Kwi M07*qoM6N<$f@T`Jp8x;= literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/burnt3.png b/Resources/Textures/Decals/burnt.rsi/burnt3.png new file mode 100644 index 0000000000000000000000000000000000000000..e9dcbe37533f6e1aa9f17dca58d5c2b15973408a GIT binary patch literal 928 zcmV;R17G}!P)a;W5Jit{9MAGY^Z#EoHA`ZHfq9@0+$c_ss#F3Yb>H5b2K)d9;0(;b2;6I(YfiwU zR-b2J0b1Sv3Va8?0W0tZ+=|v(^sm5|IuEc8z_0pnEn*Eg)rHngikQ=J>b^JNQUKjM z124sV@V=U@}kW6B%Z?YOXZZ67&`UX#a^V zgRKSR6c-ac9NCPJ)+sP}?|AZ=OUQfLXypjSnJtYb^FAr12DEu*x(wYpR<-;Fy!M$X z52e%uQ@veg?pTLhLe{bD$dvbOccIXcG>9sFVDbZAW`p^r92HlsY)$oI$1Dm>^mDco)UP^r= zL+Z-M(9I&I26LR!R#}p>toG$s2_8XIFDGbZO=)!|&3&SZk+GSTFg37rL_af6-vjic z595{^=*`gg1HNabOX;%Sr-W)pb9q;Pne_ox{7lkJJQ?RL?wAwc2x0GCII8SaXXUwA zh|&jo5Hh~96&b6gen5aShX_!KrDrZs^V{%1UMzI3){{b2u`{;`kj?~;+p#!H6W9Q($&N#+@YmG_~VwO}MVq9HEt4ibR! zhh*Y?R!gSl{1)dNci=DZ8~9Uv+L^73v7BmCYqohITkDjrUwzIW5+(lw{H*!6G_W@$ zHWYejpJ=k8`QHCOJc`y>tLoMXe;4Cdwq9TXUb2K5Mw&zu=pPS`GTPfadjU^`5@AN8LXHrEQ@sW!o?S0000>5u66hM z4m^NiHO3eX*Z_Or0K5TPU{`Y+mg`cwewV(X0aFctb1gUnw^Fnz1$haG6`-ls3TRhj zTWcO=&?oQ*m|9r)0Oqp#TJM`0+fp{iP&x4|kXCy(F~*WRg|4yHm7O$Z3@hZC3%Q7b1Bh-dPs1$Qf@v`@_y9w&{#5aS4fRjqi1w0A)j?W*E(IU2gdNo z9N$d7p$suMngBj(^BcWn-b(pC1mEZxK88gPUSprtVEGXMrT{QD;1|8_{{_AmfH!*V z9dig8R{->c-pl3Y{#o_0o=P(3&A0uY&rB&Y*RmE;*Pk8zpt(CK!dC-Q9t-uZ#*1$#Q# zs9XRl_pag=_br{6ZoGQw63>Rr!|sEk;zL-tKE)=HtaD)P_Uwv=$Pjo*@23L$0)Vhy z04mMrG43W-@<$#%bt*m^j@A9H?@Bob9$)( zcjIm5%Yuhml7uSvU*J%ik1Ql~q4#|OWM7xEbH9mg zc=V!P9)U|X7FkdrQz<{vf5mjU9`M~HvpasHv#E72-S5h)6L9_u9x#X3!t};m00000 LNkvXXu0mjfo00E? literal 0 HcmV?d00001 diff --git a/Resources/Textures/Decals/burnt.rsi/meta.json b/Resources/Textures/Decals/burnt.rsi/meta.json new file mode 100644 index 000000000000..48a8f33138cf --- /dev/null +++ b/Resources/Textures/Decals/burnt.rsi/meta.json @@ -0,0 +1,27 @@ +{ + "version": 1, + "size": { + "x": 32, + "y": 32 + }, + "license": "CC-BY-SA-3.0", + "copyright": "From https://github.com/BeeStation/BeeStation-Hornet/blob/master/icons/turf/turf_damage.dmi at f2d6fbdf36aa0951049498cf28e028a38e32fe0b", + "states": [ + { + "name": "burnt1" + + }, + { + "name": "burnt2" + + }, + { + "name": "burnt3" + + }, + { + "name": "burnt4" + + } + ] +} From 0c5a053ae4ec06ad4471884dd81aa5053522d716 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 00:24:56 +0000 Subject: [PATCH 25/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8190ecd8fe4f..050ad0721c23 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Aquif - changes: - - message: It is now possible to "lock" admin faxes such that they cannot be edited - by cybersun pens or any other IC means. - type: Add - id: 6895 - time: '2024-07-10T05:28:36.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/28972 - author: Ghagliiarghii changes: - message: The Librarian's Books Bag can now hold D&D related items such as dice @@ -3918,3 +3910,10 @@ id: 7394 time: '2024-09-18T23:55:26.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29998 +- author: Winkarst-cpu + changes: + - message: Now fire leaves burn marks on the tiles that were affected by it. + type: Add + id: 7395 + time: '2024-09-19T00:23:50.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31939 From 1c3cfeeb35f425cd556103e4a673c01ae16cf69d Mon Sep 17 00:00:00 2001 From: ArchRBX <5040911+ArchRBX@users.noreply.github.com> Date: Thu, 19 Sep 2024 02:25:47 +0100 Subject: [PATCH 26/40] Coordinates under IFF Label on Mass Scanners and Shuttle Consoles (#31501) * adds coord label beneath iff label * fixed wrong coordinate system being used * changes the clamping on the label UI to instead normalise the UI's distance vector from the centre of the screen, fixes corner-hugging * cleaned up if-statement by moving the calc ahead of it * fixed clamping, fixed parenting issue, added draw cull on coord label --------- Co-authored-by: archrbx --- .../Shuttles/UI/ShuttleNavControl.xaml.cs | 47 +++++++++++++++---- 1 file changed, 38 insertions(+), 9 deletions(-) diff --git a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs index 64ead32586d2..2674343e0591 100644 --- a/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs +++ b/Content.Client/Shuttles/UI/ShuttleNavControl.xaml.cs @@ -199,7 +199,9 @@ protected override void Draw(DrawingHandleScreen handle) var gridMatrix = _transform.GetWorldMatrix(gUid); var matty = Matrix3x2.Multiply(gridMatrix, ourWorldMatrixInvert); - var color = _shuttles.GetIFFColor(grid, self: false, iff); + + var labelColor = _shuttles.GetIFFColor(grid, self: false, iff); + var coordColor = new Color(labelColor.R * 0.8f, labelColor.G * 0.8f, labelColor.B * 0.8f, 0.5f); // Others default: // Color.FromHex("#FFC000FF") @@ -213,25 +215,52 @@ protected override void Draw(DrawingHandleScreen handle) var gridCentre = Vector2.Transform(gridBody.LocalCenter, matty); gridCentre.Y = -gridCentre.Y; + var distance = gridCentre.Length(); var labelText = Loc.GetString("shuttle-console-iff-label", ("name", labelName), ("distance", $"{distance:0.0}")); + var mapCoords = _transform.GetWorldPosition(gUid); + var coordsText = $"({mapCoords.X:0.0}, {mapCoords.Y:0.0})"; + // yes 1.0 scale is intended here. var labelDimensions = handle.GetDimensions(Font, labelText, 1f); + var coordsDimensions = handle.GetDimensions(Font, coordsText, 0.7f); // y-offset the control to always render below the grid (vertically) var yOffset = Math.Max(gridBounds.Height, gridBounds.Width) * MinimapScale / 1.8f; - // The actual position in the UI. We offset the matrix position to render it off by half its width - // plus by the offset. - var uiPosition = ScalePosition(gridCentre)- new Vector2(labelDimensions.X / 2f, -yOffset); + // The actual position in the UI. We centre the label by offsetting the matrix position + // by half the label's width, plus the y-offset + var gridScaledPosition = ScalePosition(gridCentre) - new Vector2(0, -yOffset); - // Look this is uggo so feel free to cleanup. We just need to clamp the UI position to within the viewport. - uiPosition = new Vector2(Math.Clamp(uiPosition.X, 0f, PixelWidth - labelDimensions.X ), - Math.Clamp(uiPosition.Y, 0f, PixelHeight - labelDimensions.Y)); + // Normalize the grid position if it exceeds the viewport bounds + // normalizing it instead of clamping it preserves the direction of the vector and prevents corner-hugging + var gridOffset = gridScaledPosition / PixelSize - new Vector2(0.5f, 0.5f); + var offsetMax = Math.Max(Math.Abs(gridOffset.X), Math.Abs(gridOffset.Y)) * 2f; + if (offsetMax > 1) + { + gridOffset = new Vector2(gridOffset.X / offsetMax, gridOffset.Y / offsetMax); + + gridScaledPosition = (gridOffset + new Vector2(0.5f, 0.5f)) * PixelSize; + } - handle.DrawString(Font, uiPosition, labelText, color); + var labelUiPosition = gridScaledPosition - new Vector2(labelDimensions.X / 2f, 0); + var coordUiPosition = gridScaledPosition - new Vector2(coordsDimensions.X / 2f, -labelDimensions.Y); + + // clamp the IFF label's UI position to within the viewport extents so it hugs the edges of the viewport + // coord label intentionally isn't clamped so we don't get ugly clutter at the edges + var controlExtents = PixelSize - new Vector2(labelDimensions.X, labelDimensions.Y); //new Vector2(labelDimensions.X * 2f, labelDimensions.Y); + labelUiPosition = Vector2.Clamp(labelUiPosition, Vector2.Zero, controlExtents); + + // draw IFF label + handle.DrawString(Font, labelUiPosition, labelText, labelColor); + + // only draw coords label if close enough + if (offsetMax < 1) + { + handle.DrawString(Font, coordUiPosition, coordsText, 0.7f, coordColor); + } } // Detailed view @@ -241,7 +270,7 @@ protected override void Draw(DrawingHandleScreen handle) if (!gridAABB.Intersects(viewAABB)) continue; - DrawGrid(handle, matty, grid, color); + DrawGrid(handle, matty, grid, labelColor); DrawDocks(handle, gUid, matty); } } From c2f0626e029c1f3b33aa9b7770ef7d3ee0fa2aae Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 01:26:53 +0000 Subject: [PATCH 27/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 050ad0721c23..4b779d845b67 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Ghagliiarghii - changes: - - message: The Librarian's Books Bag can now hold D&D related items such as dice - and battlemats. - type: Tweak - id: 6896 - time: '2024-07-10T05:51:01.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29863 - author: Beck Thompson, Tayrtahn changes: - message: Typing indicators now correctly stack and will not overwrite your default @@ -3917,3 +3909,14 @@ id: 7395 time: '2024-09-19T00:23:50.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31939 +- author: ArchRBX + changes: + - message: Mass scanners and shuttle consoles now display coordinates beneath IFF + labels + type: Add + - message: IFF labels that are beyond the viewport extents maintain their heading + and don't hug corners + type: Fix + id: 7396 + time: '2024-09-19T01:25:47.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31501 From 9c905cd58f5453c6ab7821709bdbf5fcf1249df9 Mon Sep 17 00:00:00 2001 From: Luiz Costa <33888056+luizwritescode@users.noreply.github.com> Date: Wed, 18 Sep 2024 23:15:44 -0300 Subject: [PATCH 28/40] Fix TEG acting as infinite energy source on destruction (#29972) * TEG now checks for power supply before checking for IsFullyBuilt * Update Content.Server/Power/Generation/Teg/TegSystem.cs Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --------- Co-authored-by: metalgearsloth <31366439+metalgearsloth@users.noreply.github.com> Co-authored-by: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> --- Content.Server/Power/Generation/Teg/TegSystem.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Content.Server/Power/Generation/Teg/TegSystem.cs b/Content.Server/Power/Generation/Teg/TegSystem.cs index 9fb7d5ff1f64..027f25704023 100644 --- a/Content.Server/Power/Generation/Teg/TegSystem.cs +++ b/Content.Server/Power/Generation/Teg/TegSystem.cs @@ -102,10 +102,6 @@ private void GeneratorExamined(EntityUid uid, TegGeneratorComponent component, E private void GeneratorUpdate(EntityUid uid, TegGeneratorComponent component, ref AtmosDeviceUpdateEvent args) { - var tegGroup = GetNodeGroup(uid); - if (tegGroup is not { IsFullyBuilt: true }) - return; - var supplier = Comp(uid); var powerReceiver = Comp(uid); if (!powerReceiver.Powered) @@ -114,6 +110,10 @@ private void GeneratorUpdate(EntityUid uid, TegGeneratorComponent component, ref return; } + var tegGroup = GetNodeGroup(uid); + if (tegGroup is not { IsFullyBuilt: true }) + return; + var circA = tegGroup.CirculatorA!.Owner; var circB = tegGroup.CirculatorB!.Owner; From b1296294052e6bb1af45efb97c350cc898746b22 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 02:16:50 +0000 Subject: [PATCH 29/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 4b779d845b67..8eba2ed6d887 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Beck Thompson, Tayrtahn - changes: - - message: Typing indicators now correctly stack and will not overwrite your default - species indicator. - type: Fix - id: 6897 - time: '2024-07-10T05:51:48.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29492 - author: Winkarst-cpu changes: - message: Now confirmation popup is displayed and item panel status is updated @@ -3920,3 +3912,10 @@ id: 7396 time: '2024-09-19T01:25:47.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31501 +- author: coffeeware + changes: + - message: a powered TEG won't produce infinite power when destroyed + type: Fix + id: 7397 + time: '2024-09-19T02:15:44.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/29972 From 550c4231816cd28251d3c42d32002bcf0ac4d5aa Mon Sep 17 00:00:00 2001 From: IProduceWidgets <107586145+IProduceWidgets@users.noreply.github.com> Date: Wed, 18 Sep 2024 22:17:13 -0400 Subject: [PATCH 30/40] Clean up solution regen and drain comps (#29777) * clean up solution regen and drain comps * Tape applied. * Update Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs Co-authored-by: Tayrtahn * remain entity * That has to be a rogue test fail. --------- Co-authored-by: Tayrtahn --- .../SolutionRegenerationComponent.cs | 12 +++++----- .../SolutionRegenerationSystem.cs | 4 ++-- .../Fluids/Components/DrainComponent.cs | 24 +++++++++---------- 3 files changed, 20 insertions(+), 20 deletions(-) diff --git a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs index 23bf6b215736..03c0ffe0c1ae 100644 --- a/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs +++ b/Content.Server/Chemistry/Components/SolutionRegenerationComponent.cs @@ -14,31 +14,31 @@ public sealed partial class SolutionRegenerationComponent : Component /// /// The name of the solution to add to. /// - [DataField("solution", required: true), ViewVariables(VVAccess.ReadWrite)] + [DataField("solution", required: true)] public string SolutionName = string.Empty; /// /// The solution to add reagents to. /// - [DataField("solutionRef")] - public Entity? Solution = null; + [DataField] + public Entity? SolutionRef = null; /// /// The reagent(s) to be regenerated in the solution. /// - [DataField("generated", required: true), ViewVariables(VVAccess.ReadWrite)] + [DataField(required: true)] public Solution Generated = default!; /// /// How long it takes to regenerate once. /// - [DataField("duration"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public TimeSpan Duration = TimeSpan.FromSeconds(1); /// /// The time when the next regeneration will occur. /// - [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer)), ViewVariables(VVAccess.ReadWrite)] + [DataField("nextChargeTime", customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextRegenTime = TimeSpan.FromSeconds(0); } diff --git a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs index 6a600628572d..bccd59470696 100644 --- a/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs +++ b/Content.Server/Chemistry/EntitySystems/SolutionRegenerationSystem.cs @@ -24,7 +24,7 @@ public override void Update(float frameTime) // timer ignores if its full, it's just a fixed cycle regen.NextRegenTime = _timing.CurTime + regen.Duration; - if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.Solution, out var solution)) + if (_solutionContainer.ResolveSolution((uid, manager), regen.SolutionName, ref regen.SolutionRef, out var solution)) { var amount = FixedPoint2.Min(solution.AvailableVolume, regen.Generated.Volume); if (amount <= FixedPoint2.Zero) @@ -41,7 +41,7 @@ public override void Update(float frameTime) generated = regen.Generated.Clone().SplitSolution(amount); } - _solutionContainer.TryAddSolution(regen.Solution.Value, generated); + _solutionContainer.TryAddSolution(regen.SolutionRef.Value, generated); } } } diff --git a/Content.Shared/Fluids/Components/DrainComponent.cs b/Content.Shared/Fluids/Components/DrainComponent.cs index 4fb4fe943833..50cb5f519581 100644 --- a/Content.Shared/Fluids/Components/DrainComponent.cs +++ b/Content.Shared/Fluids/Components/DrainComponent.cs @@ -23,14 +23,14 @@ public sealed partial class DrainComponent : Component [DataField] public Entity? Solution = null; - [DataField("accumulator")] + [DataField] public float Accumulator = 0f; /// /// Does this drain automatically absorb surrouding puddles? Or is it a drain designed to empty - /// solutions in it manually? + /// solutions in it manually? /// - [DataField("autoDrain"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public bool AutoDrain = true; /// @@ -38,47 +38,47 @@ public sealed partial class DrainComponent : Component /// Divided by puddles, so if there are 5 puddles this will take 1/5 from each puddle. /// This will stay fixed to 1 second no matter what DrainFrequency is. /// - [DataField("unitsPerSecond")] + [DataField] public float UnitsPerSecond = 6f; /// /// How many units are ejected from the buffer per second. /// - [DataField("unitsDestroyedPerSecond")] + [DataField] public float UnitsDestroyedPerSecond = 3f; /// /// How many (unobstructed) tiles away the drain will /// drain puddles from. /// - [DataField("range"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float Range = 2f; /// /// How often in seconds the drain checks for puddles around it. /// If the EntityQuery seems a bit unperformant this can be increased. /// - [DataField("drainFrequency")] + [DataField] public float DrainFrequency = 1f; /// /// How much time it takes to unclog it with a plunger /// - [DataField("unclogDuration"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float UnclogDuration = 1f; /// /// What's the probability of uncloging on each try /// - [DataField("unclogProbability"), ViewVariables(VVAccess.ReadWrite)] + [DataField] public float UnclogProbability = 0.75f; - [DataField("manualDrainSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier ManualDrainSound = new SoundPathSpecifier("/Audio/Effects/Fluids/slosh.ogg"); - [DataField("plungerSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier PlungerSound = new SoundPathSpecifier("/Audio/Items/Janitor/plunger.ogg"); - [DataField("unclogSound"), ViewVariables(VVAccess.ReadOnly)] + [DataField] public SoundSpecifier UnclogSound = new SoundPathSpecifier("/Audio/Effects/Fluids/glug.ogg"); } From bdd0561254a0f2b6cef0a032af566bd908e9de58 Mon Sep 17 00:00:00 2001 From: Leon Friedrich <60421075+ElectroJr@users.noreply.github.com> Date: Thu, 19 Sep 2024 14:21:26 +1200 Subject: [PATCH 31/40] Make status effect networking not use `TryAddStatusEffect` (#28766) * Make status effect networking not use `TryAddStatusEffect` * a --- .../StatusEffect/StatusEffectsSystem.cs | 74 ++++++++++--------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/Content.Shared/StatusEffect/StatusEffectsSystem.cs b/Content.Shared/StatusEffect/StatusEffectsSystem.cs index 9806077f9bb8..95abea63db0d 100644 --- a/Content.Shared/StatusEffect/StatusEffectsSystem.cs +++ b/Content.Shared/StatusEffect/StatusEffectsSystem.cs @@ -14,6 +14,7 @@ public sealed class StatusEffectsSystem : EntitySystem [Dependency] private readonly IComponentFactory _componentFactory = default!; [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly AlertsSystem _alertsSystem = default!; + private List _toRemove = new(); public override void Initialize() { @@ -32,18 +33,28 @@ public override void Update(float frameTime) var curTime = _gameTiming.CurTime; var enumerator = EntityQueryEnumerator(); + _toRemove.Clear(); while (enumerator.MoveNext(out var uid, out _, out var status)) { - foreach (var state in status.ActiveEffects.ToArray()) + if (status.ActiveEffects.Count == 0) + { + // This shouldn't happen, but just in case something sneaks through + _toRemove.Add(uid); + continue; + } + + foreach (var state in status.ActiveEffects) { - // if we're past the end point of the effect if (curTime > state.Value.Cooldown.Item2) - { TryRemoveStatusEffect(uid, state.Key, status); - } } } + + foreach (var uid in _toRemove) + { + RemComp(uid); + } } private void OnGetState(EntityUid uid, StatusEffectsComponent component, ref ComponentGetState args) @@ -62,29 +73,21 @@ private void OnHandleState(EntityUid uid, StatusEffectsComponent component, ref component.AllowedEffects.AddRange(state.AllowedEffects); // Remove non-existent effects. - foreach (var effect in component.ActiveEffects.Keys) + foreach (var key in component.ActiveEffects.Keys) { - if (!state.ActiveEffects.ContainsKey(effect)) - { - TryRemoveStatusEffect(uid, effect, component, remComp: false); - } + if (!state.ActiveEffects.ContainsKey(key)) + component.ActiveEffects.Remove(key); } foreach (var (key, effect) in state.ActiveEffects) { - // don't bother with anything if we already have it - if (component.ActiveEffects.ContainsKey(key)) - { - component.ActiveEffects[key] = new(effect); - continue; - } - - var time = effect.Cooldown.Item2 - effect.Cooldown.Item1; - - TryAddStatusEffect(uid, key, time, true, component, effect.Cooldown.Item1); - component.ActiveEffects[key].RelevantComponent = effect.RelevantComponent; - // state handling should not add networked components, that is handled separately by the client game state manager. + component.ActiveEffects[key] = new(effect); } + + if (component.ActiveEffects.Count == 0) + RemComp(uid); + else + EnsureComp(uid); } private void OnRejuvenate(EntityUid uid, StatusEffectsComponent component, RejuvenateEvent args) @@ -109,18 +112,16 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool if (!Resolve(uid, ref status, false)) return false; - if (TryAddStatusEffect(uid, key, time, refresh, status)) - { - // If they already have the comp, we just won't bother updating anything. - if (!EntityManager.HasComponent(uid)) - { - var comp = EntityManager.AddComponent(uid); - status.ActiveEffects[key].RelevantComponent = _componentFactory.GetComponentName(comp.GetType()); - } + if (!TryAddStatusEffect(uid, key, time, refresh, status)) + return false; + + if (HasComp(uid)) return true; - } - return false; + EntityManager.AddComponent(uid); + status.ActiveEffects[key].RelevantComponent = _componentFactory.GetComponentName(); + return true; + } public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, string component, @@ -162,8 +163,12 @@ public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool re /// If the effect already exists, it will simply replace the cooldown with the new one given. /// If you want special 'effect merging' behavior, do it your own damn self! /// - public bool TryAddStatusEffect(EntityUid uid, string key, TimeSpan time, bool refresh, - StatusEffectsComponent? status = null, TimeSpan? startTime = null) + public bool TryAddStatusEffect(EntityUid uid, + string key, + TimeSpan time, + bool refresh, + StatusEffectsComponent? status = null, + TimeSpan? startTime = null) { if (!Resolve(uid, ref status, false)) return false; @@ -334,8 +339,7 @@ public bool HasStatusEffect(EntityUid uid, string key, /// The entity to check on. /// The status effect ID to check for /// The status effect component, should you already have it. - public bool CanApplyEffect(EntityUid uid, string key, - StatusEffectsComponent? status = null) + public bool CanApplyEffect(EntityUid uid, string key, StatusEffectsComponent? status = null) { // don't log since stuff calling this prolly doesn't care if we don't actually have it if (!Resolve(uid, ref status, false)) From 3fc9f96b75b2a3ebc1a02319758eb6853452cb05 Mon Sep 17 00:00:00 2001 From: ShadowCommander <10494922+ShadowCommander@users.noreply.github.com> Date: Thu, 19 Sep 2024 00:42:49 -0700 Subject: [PATCH 32/40] Move PlaceableSurfaceComponent usages to PlaceableSurfaceSystem (#28384) * Move placeable check to PlaceableSurfaceSystem This check stops entities from being inserted into a storage entity when it has a PlaceableSurfaceComponent. The entity is instead placed on top of the entity like a table. * Move SetPlaceable to PlaceableSurfaceSystem * Update to transform system and consolidate code * Fix interaction with storage that has a placeable component * deadlock --------- Co-authored-by: metalgearsloth --- .../Placeable/PlaceableSurfaceSystem.cs | 29 ++++++++++++++++--- .../SharedEntityStorageSystem.cs | 3 -- .../EntitySystems/SharedStorageSystem.cs | 4 ++- Content.Shared/Storage/StorageComponent.cs | 3 ++ 4 files changed, 31 insertions(+), 8 deletions(-) diff --git a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs index a9a9390a6e0e..c332064ea38e 100644 --- a/Content.Shared/Placeable/PlaceableSurfaceSystem.cs +++ b/Content.Shared/Placeable/PlaceableSurfaceSystem.cs @@ -1,6 +1,7 @@ using System.Numerics; using Content.Shared.Hands.EntitySystems; using Content.Shared.Interaction; +using Content.Shared.Storage; using Content.Shared.Storage.Components; namespace Content.Shared.Placeable; @@ -8,12 +9,16 @@ namespace Content.Shared.Placeable; public sealed class PlaceableSurfaceSystem : EntitySystem { [Dependency] private readonly SharedHandsSystem _handsSystem = default!; + [Dependency] private readonly SharedTransformSystem _transformSystem = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnAfterInteractUsing); + SubscribeLocalEvent(OnStorageInteractUsingAttempt); + SubscribeLocalEvent(OnStorageAfterOpen); + SubscribeLocalEvent(OnStorageAfterClose); } public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceComponent? surface = null) @@ -21,6 +26,9 @@ public void SetPlaceable(EntityUid uid, bool isPlaceable, PlaceableSurfaceCompon if (!Resolve(uid, ref surface, false)) return; + if (surface.IsPlaceable == isPlaceable) + return; + surface.IsPlaceable = isPlaceable; Dirty(uid, surface); } @@ -59,11 +67,24 @@ private void OnAfterInteractUsing(EntityUid uid, PlaceableSurfaceComponent surfa if (!_handsSystem.TryDrop(args.User, args.Used)) return; - if (surface.PlaceCentered) - Transform(args.Used).LocalPosition = Transform(uid).LocalPosition + surface.PositionOffset; - else - Transform(args.Used).Coordinates = args.ClickLocation; + _transformSystem.SetCoordinates(args.Used, + surface.PlaceCentered ? Transform(uid).Coordinates.Offset(surface.PositionOffset) : args.ClickLocation); args.Handled = true; } + + private void OnStorageInteractUsingAttempt(Entity ent, ref StorageInteractUsingAttemptEvent args) + { + args.Cancelled = true; + } + + private void OnStorageAfterOpen(Entity ent, ref StorageAfterOpenEvent args) + { + SetPlaceable(ent.Owner, true, ent.Comp); + } + + private void OnStorageAfterClose(Entity ent, ref StorageAfterCloseEvent args) + { + SetPlaceable(ent.Owner, false, ent.Comp); + } } diff --git a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs index 4932613d0e64..309ac0a2e093 100644 --- a/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedEntityStorageSystem.cs @@ -487,9 +487,6 @@ private void ModifyComponents(EntityUid uid, SharedEntityStorageComponent? compo } } - if (TryComp(uid, out var surface)) - _placeableSurface.SetPlaceable(uid, component.Open, surface); - _appearance.SetData(uid, StorageVisuals.Open, component.Open); _appearance.SetData(uid, StorageVisuals.HasContents, component.Contents.ContainedEntities.Count > 0); } diff --git a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs index def9d797c483..d6fde292a147 100644 --- a/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs +++ b/Content.Shared/Storage/EntitySystems/SharedStorageSystem.cs @@ -364,7 +364,9 @@ private void OnInteractUsing(EntityUid uid, StorageComponent storageComp, Intera if (args.Handled || !CanInteract(args.User, (uid, storageComp), storageComp.ClickInsert, false)) return; - if (HasComp(uid)) + var attemptEv = new StorageInteractUsingAttemptEvent(); + RaiseLocalEvent(uid, ref attemptEv); + if (attemptEv.Cancelled) return; PlayerInsertHeldEntity((uid, storageComp), args.User); diff --git a/Content.Shared/Storage/StorageComponent.cs b/Content.Shared/Storage/StorageComponent.cs index a666169f5294..d2c607e57f76 100644 --- a/Content.Shared/Storage/StorageComponent.cs +++ b/Content.Shared/Storage/StorageComponent.cs @@ -238,6 +238,9 @@ public AnimateInsertingEntitiesEvent(NetEntity storage, List storedEn [ByRefEvent] public record struct StorageInteractAttemptEvent(bool Silent, bool Cancelled = false); + [ByRefEvent] + public record struct StorageInteractUsingAttemptEvent(bool Cancelled = false); + [NetSerializable] [Serializable] public enum StorageVisuals : byte From 3acf6b93a109ea542b3110c1f9b7fc59c6976aa3 Mon Sep 17 00:00:00 2001 From: Willhelm53 <97707302+Willhelm53@users.noreply.github.com> Date: Thu, 19 Sep 2024 03:51:33 -0400 Subject: [PATCH 33/40] Padded ItemStatus Text (#29560) * Back in the saddle again! <(8o) * if you like my STYLE you should see my SHEETS ;-) * stylesheet change works for ItemStatusNotHeld but broken for ItemStatus. Just using xaml for now. * teehee * beeg --------- Co-authored-by: metalgearsloth --- Content.Client/Stylesheets/StyleNano.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/Content.Client/Stylesheets/StyleNano.cs b/Content.Client/Stylesheets/StyleNano.cs index 0bd75003a209..ccd36c35e82b 100644 --- a/Content.Client/Stylesheets/StyleNano.cs +++ b/Content.Client/Stylesheets/StyleNano.cs @@ -695,6 +695,18 @@ public StyleNano(IResourceCache resCache) : base(resCache) new StyleProperty("font-color", Color.FromHex("#E5E5E581")), }), + // ItemStatus for hands + Element() + .Class(StyleClassItemStatusNotHeld) + .Prop("font", notoSansItalic10) + .Prop("font-color", ItemStatusNotHeldColor) + .Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)), + + Element() + .Class(StyleClassItemStatus) + .Prop(nameof(RichTextLabel.LineHeightScale), 0.7f) + .Prop(nameof(Control.Margin), new Thickness(4, 0, 0, 2)), + // Context Menu window Element().Class(ContextMenuPopup.StyleClassContextMenuPopup) .Prop(PanelContainer.StylePropertyPanel, contextMenuBackground), From 94ad76fd07f148628c1b5d8070565635957caeb2 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 19 Sep 2024 04:02:37 -0400 Subject: [PATCH 34/40] Fix Set Outfit command/verb (#29672) * Filter Set Outfit menu to exclude loadout sets * Apply loadouts to job outfits * Use appropriate species for Urists * squishy --------- Co-authored-by: metalgearsloth --- .../UI/SetOutfit/SetOutfitMenu.xaml.cs | 18 +++++++--- .../Commands/SetOutfitCommand.cs | 36 +++++++++++++++++++ 2 files changed, 49 insertions(+), 5 deletions(-) diff --git a/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs b/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs index 7cb32b43df59..615f1434df22 100644 --- a/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs +++ b/Content.Client/Administration/UI/SetOutfit/SetOutfitMenu.xaml.cs @@ -1,14 +1,13 @@ +using System.Linq; using System.Numerics; using Content.Client.UserInterface.Controls; +using Content.Shared.Preferences.Loadouts; using Content.Shared.Roles; using Robust.Client.AutoGenerated; using Robust.Client.Console; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; -using Robust.Shared.GameObjects; -using Robust.Shared.IoC; -using Robust.Shared.Localization; using Robust.Shared.Prototypes; namespace Content.Client.Administration.UI.SetOutfit @@ -65,9 +64,18 @@ private void SearchBarOnOnTextChanged(LineEdit.LineEditEventArgs obj) PopulateByFilter(SearchBar.Text); } + private IEnumerable GetPrototypes() + { + // Filter out any StartingGearPrototypes that belong to loadouts + var loadouts = _prototypeManager.EnumeratePrototypes(); + var loadoutGears = loadouts.Select(l => l.StartingGear); + return _prototypeManager.EnumeratePrototypes() + .Where(p => !loadoutGears.Contains(p.ID)); + } + private void PopulateList() { - foreach (var gear in _prototypeManager.EnumeratePrototypes()) + foreach (var gear in GetPrototypes()) { OutfitList.Add(GetItem(gear, OutfitList)); } @@ -76,7 +84,7 @@ private void PopulateList() private void PopulateByFilter(string filter) { OutfitList.Clear(); - foreach (var gear in _prototypeManager.EnumeratePrototypes()) + foreach (var gear in GetPrototypes()) { if (!string.IsNullOrEmpty(filter) && gear.ID.ToLowerInvariant().Contains(filter.Trim().ToLowerInvariant())) diff --git a/Content.Server/Administration/Commands/SetOutfitCommand.cs b/Content.Server/Administration/Commands/SetOutfitCommand.cs index ff4d34705a6c..9240e7b91b66 100644 --- a/Content.Server/Administration/Commands/SetOutfitCommand.cs +++ b/Content.Server/Administration/Commands/SetOutfitCommand.cs @@ -4,11 +4,15 @@ using Content.Server.Preferences.Managers; using Content.Shared.Access.Components; using Content.Shared.Administration; +using Content.Shared.Clothing; using Content.Shared.Hands.Components; +using Content.Shared.Humanoid; using Content.Shared.Inventory; using Content.Shared.PDA; using Content.Shared.Preferences; +using Content.Shared.Preferences.Loadouts; using Content.Shared.Roles; +using Content.Shared.Station; using Robust.Shared.Console; using Robust.Shared.Player; using Robust.Shared.Prototypes; @@ -82,9 +86,11 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit return false; HumanoidCharacterProfile? profile = null; + ICommonSession? session = null; // Check if we are setting the outfit of a player to respect the preferences if (entityManager.TryGetComponent(target, out ActorComponent? actorComponent)) { + session = actorComponent.PlayerSession; var userId = actorComponent.PlayerSession.UserId; var preferencesManager = IoCManager.Resolve(); var prefs = preferencesManager.GetPreferences(userId); @@ -128,6 +134,36 @@ public static bool SetOutfit(EntityUid target, string gear, IEntityManager entit } } + // See if this starting gear is associated with a job + var jobs = prototypeManager.EnumeratePrototypes(); + foreach (var job in jobs) + { + if (job.StartingGear != gear) + continue; + + var jobProtoId = LoadoutSystem.GetJobPrototype(job.ID); + if (!prototypeManager.TryIndex(jobProtoId, out var jobProto)) + break; + + // Don't require a player, so this works on Urists + profile ??= entityManager.TryGetComponent(target, out var comp) + ? HumanoidCharacterProfile.DefaultWithSpecies(comp.Species) + : new HumanoidCharacterProfile(); + // Try to get the user's existing loadout for the role + profile.Loadouts.TryGetValue(jobProtoId, out var roleLoadout); + + if (roleLoadout == null) + { + // If they don't have a loadout for the role, make a default one + roleLoadout = new RoleLoadout(jobProtoId); + roleLoadout.SetDefault(profile, session, prototypeManager); + } + + // Equip the target with the job loadout + var stationSpawning = entityManager.System(); + stationSpawning.EquipRoleLoadout(target, roleLoadout, jobProto); + } + return true; } } From 59a8f4445d36d76a58ef814b3762cc324130deee Mon Sep 17 00:00:00 2001 From: Boaz1111 <149967078+Boaz1111@users.noreply.github.com> Date: Thu, 19 Sep 2024 10:41:24 +0200 Subject: [PATCH 35/40] adds plasma and uranium arrows (#31241) --- .../Weapons/Guns/Projectiles/arrows.yml | 53 +++++++++++++++++++ .../Graphs/weapons/improvised_arrow.yml | 48 +++++++++++++++++ .../Recipes/Construction/weapons.yml | 22 ++++++++ 3 files changed, 123 insertions(+) diff --git a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml index 6f925139fb1b..f1172c5de08c 100644 --- a/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml +++ b/Resources/Prototypes/Entities/Objects/Weapons/Guns/Projectiles/arrows.yml @@ -106,3 +106,56 @@ - type: Construction graph: ImprovisedArrow node: ImprovisedArrow + +- type: entity + parent: BaseArrow + id: ArrowImprovisedPlasma + name: plasma glass shard arrow + description: The greyshirt's preferred projectile. Now with extra lethality! + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/arrows.rsi + layers: + - state: tail + color: white + - state: rod + color: darkgray + - state: tip + color: purple + - state: solution1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false + - type: Projectile + damage: + types: + Piercing: 30 + - type: Construction + graph: ImprovisedArrowPlasma + node: ImprovisedArrowPlasma + +- type: entity + parent: BaseArrow + id: ArrowImprovisedUranium + name: uranium glass shard arrow + description: The greyshirt's preferred projectile. Now with added radiation! + components: + - type: Sprite + sprite: Objects/Weapons/Guns/Projectiles/arrows.rsi + layers: + - state: tail + color: white + - state: rod + color: darkgray + - state: tip + color: green + - state: solution1 + map: ["enum.SolutionContainerLayers.Fill"] + visible: false + - type: Projectile + damage: + types: + Piercing: 25 + Radiation: 5 + - type: Construction + graph: ImprovisedArrowUranium + node: ImprovisedArrowUranium diff --git a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml index 04b94690467d..20e06e9f4841 100644 --- a/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml +++ b/Resources/Prototypes/Recipes/Construction/Graphs/weapons/improvised_arrow.yml @@ -21,3 +21,51 @@ - node: ImprovisedArrow entity: ArrowImprovised + +- type: constructionGraph + id: ImprovisedArrowPlasma + start: start + graph: + - node: start + edges: + - to: ImprovisedArrowPlasma + steps: + - material: MetalRod + amount: 1 + doAfter: 0.5 + - material: Cloth + amount: 1 + doAfter: 0.5 + - tag: PlasmaGlassShard + name: plasma glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + doAfter: 0.5 + + - node: ImprovisedArrowPlasma + entity: ArrowImprovisedPlasma + +- type: constructionGraph + id: ImprovisedArrowUranium + start: start + graph: + - node: start + edges: + - to: ImprovisedArrowUranium + steps: + - material: MetalRod + amount: 1 + doAfter: 0.5 + - material: Cloth + amount: 1 + doAfter: 0.5 + - tag: UraniumGlassShard + name: uranium glass shard + icon: + sprite: Objects/Materials/Shards/shard.rsi + state: shard1 + doAfter: 0.5 + + - node: ImprovisedArrowUranium + entity: ArrowImprovisedUranium diff --git a/Resources/Prototypes/Recipes/Construction/weapons.yml b/Resources/Prototypes/Recipes/Construction/weapons.yml index 040d4c8963d1..5936a3506913 100644 --- a/Resources/Prototypes/Recipes/Construction/weapons.yml +++ b/Resources/Prototypes/Recipes/Construction/weapons.yml @@ -152,6 +152,28 @@ icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: wielded-arrow } objectType: Item +- type: construction + name: plasma glass shard arrow + id: ImprovisedArrowPlasma + graph: ImprovisedArrowPlasma + startNode: start + targetNode: ImprovisedArrowPlasma + category: construction-category-weapons + description: An arrow tipped with pieces of a plasma glass shard, for use with a bow. + icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: wielded-arrow } + objectType: Item + +- type: construction + name: uranium glass shard arrow + id: ImprovisedArrowUranium + graph: ImprovisedArrowUranium + startNode: start + targetNode: ImprovisedArrowUranium + category: construction-category-weapons + description: An arrow tipped with pieces of a uranium glass shard, for use with a bow. + icon: { sprite: Objects/Weapons/Guns/Bow/bow.rsi, state: wielded-arrow } + objectType: Item + - type: construction name: improvised bow id: ImprovisedBow From 75ff65d108e0a228d85a2d5dde5cbdbd50ed0cd3 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 08:42:31 +0000 Subject: [PATCH 36/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 8eba2ed6d887..156fe91ffc8d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: Winkarst-cpu - changes: - - message: Now confirmation popup is displayed and item panel status is updated - after setting a custom solution transfer volume. - type: Fix - id: 6898 - time: '2024-07-10T10:32:30.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29852 - author: Winkarst-cpu changes: - message: Added exit confirmation for character setup menu with unsaved changes. @@ -3919,3 +3911,10 @@ id: 7397 time: '2024-09-19T02:15:44.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/29972 +- author: Boaz1111 + changes: + - message: Added plasma and uranium arrows. + type: Add + id: 7398 + time: '2024-09-19T08:41:24.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31241 From 1468cbdb8a59beb2dfc9188a3108157496549a57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=AD=D0=B4=D1=83=D0=B0=D1=80=D0=B4?= <36124833+Ertanic@users.noreply.github.com> Date: Thu, 19 Sep 2024 13:22:02 +0300 Subject: [PATCH 37/40] Wanted list cartridge (#31223) * WantedListCartridge has been added * WantedListCartridge user interface works * WantedListCartridge is added as standard in some PDAs * The CriminalRecordsSystem can now also take into account who created the record * Added offense history table * Fix of missing loaderUid for a cartridge without installing the program * Added personalized information about the target * The crime history has been finalized * Added StatusList * The officer's name has been added to the automatic history * WantedListCartridge has been added to the HOS locker * WantedListCartridge has been removed from brigmedic's preset programs * The StealConditionSystem now takes into account whether a cartridge is inserted or installed * Added target to thief on WantedListCartridge * Merge fix * Removing copypaste * Fix merge 2 * The sprite of WantedListCartridge has been changed * Update pda.yml * Fix scrollbar in the history table * Upstream localization fix * `StatusList` has been replaced by `ListContainer` with `TextureRect` * Margin fix --- .../Cartridges/WantedListUi.cs | 30 +++ .../Cartridges/WantedListUiFragment.cs | 240 ++++++++++++++++++ .../Cartridges/WantedListUiFragment.xaml | 50 ++++ .../CartridgeLoader/CartridgeLoaderSystem.cs | 6 + .../Cartridges/WantedListCartridge.cs | 8 + .../Systems/CriminalRecordsConsoleSystem.cs | 34 +-- .../Systems/CriminalRecordsSystem.cs | 90 ++++++- .../Systems/StealConditionSystem.cs | 6 + .../Cartridges/WantedListUiState.cs | 11 + .../CriminalRecords/CriminalRecord.cs | 8 +- .../Systems/SharedCriminalRecordsSystem.cs | 21 ++ .../en-US/cartridge-loader/cartridges.ftl | 29 +++ .../criminal-records/criminal-records.ftl | 2 +- .../conditions/steal-target-groups.ftl | 1 + .../Catalog/Fills/Lockers/heads.yml | 1 + .../Entities/Objects/Devices/cartridges.yml | 23 ++ .../Entities/Objects/Devices/pda.yml | 31 ++- .../Prototypes/Objectives/objectiveGroups.yml | 1 + .../Objectives/stealTargetGroups.yml | 7 + Resources/Prototypes/Objectives/thief.yml | 9 + .../Devices/cartridge.rsi/cart-sec.png | Bin 0 -> 314 bytes .../Objects/Devices/cartridge.rsi/meta.json | 5 +- 22 files changed, 579 insertions(+), 34 deletions(-) create mode 100644 Content.Client/CartridgeLoader/Cartridges/WantedListUi.cs create mode 100644 Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.cs create mode 100644 Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.xaml create mode 100644 Content.Server/CartridgeLoader/Cartridges/WantedListCartridge.cs create mode 100644 Content.Shared/CartridgeLoader/Cartridges/WantedListUiState.cs create mode 100644 Resources/Textures/Objects/Devices/cartridge.rsi/cart-sec.png diff --git a/Content.Client/CartridgeLoader/Cartridges/WantedListUi.cs b/Content.Client/CartridgeLoader/Cartridges/WantedListUi.cs new file mode 100644 index 000000000000..3c97b8b37d15 --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/WantedListUi.cs @@ -0,0 +1,30 @@ +using Content.Client.UserInterface.Fragments; +using Content.Shared.CartridgeLoader.Cartridges; +using Robust.Client.UserInterface; + +namespace Content.Client.CartridgeLoader.Cartridges; + +public sealed partial class WantedListUi : UIFragment +{ + private WantedListUiFragment? _fragment; + + public override Control GetUIFragmentRoot() + { + return _fragment!; + } + + public override void Setup(BoundUserInterface userInterface, EntityUid? fragmentOwner) + { + _fragment = new WantedListUiFragment(); + } + + public override void UpdateState(BoundUserInterfaceState state) + { + switch (state) + { + case WantedListUiState cast: + _fragment?.UpdateState(cast.Records); + break; + } + } +} diff --git a/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.cs b/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.cs new file mode 100644 index 000000000000..4137f6c2af0c --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.cs @@ -0,0 +1,240 @@ +using System.Linq; +using Content.Client.UserInterface.Controls; +using Content.Shared.CriminalRecords.Systems; +using Content.Shared.Security; +using Content.Shared.StatusIcon; +using Robust.Client.AutoGenerated; +using Robust.Client.GameObjects; +using Robust.Client.ResourceManagement; +using Robust.Client.UserInterface; +using Robust.Client.UserInterface.Controls; +using Robust.Client.UserInterface.XAML; +using Robust.Shared.Input; +using Robust.Shared.Map; +using Robust.Shared.Prototypes; +using Robust.Shared.Utility; + +namespace Content.Client.CartridgeLoader.Cartridges; + +[GenerateTypedNameReferences] +public sealed partial class WantedListUiFragment : BoxContainer +{ + [Dependency] private readonly IEntitySystemManager _entitySystem = default!; + [Dependency] private readonly IPrototypeManager _prototypeManager = default!; + private readonly SpriteSystem _spriteSystem; + + private string? _selectedTargetName; + private List _wantedRecords = new(); + + public WantedListUiFragment() + { + RobustXamlLoader.Load(this); + IoCManager.InjectDependencies(this); + _spriteSystem = _entitySystem.GetEntitySystem(); + + SearchBar.OnTextChanged += OnSearchBarTextChanged; + } + + private void OnSearchBarTextChanged(LineEdit.LineEditEventArgs args) + { + var found = !String.IsNullOrWhiteSpace(args.Text) + ? _wantedRecords.FindAll(r => + r.TargetInfo.Name.Contains(args.Text) || + r.Status.ToString().Contains(args.Text, StringComparison.OrdinalIgnoreCase)) + : _wantedRecords; + + UpdateState(found, false); + } + + public void UpdateState(List records, bool refresh = true) + { + if (records.Count == 0) + { + NoRecords.Visible = true; + RecordsList.Visible = false; + RecordUnselected.Visible = false; + PersonContainer.Visible = false; + + _selectedTargetName = null; + if (refresh) + _wantedRecords.Clear(); + + RecordsList.PopulateList(new List()); + + return; + } + + NoRecords.Visible = false; + RecordsList.Visible = true; + RecordUnselected.Visible = true; + PersonContainer.Visible = false; + + var dataList = records.Select(r => new StatusListData(r)).ToList(); + + RecordsList.GenerateItem = GenerateItem; + RecordsList.ItemPressed = OnItemSelected; + RecordsList.PopulateList(dataList); + + if (refresh) + _wantedRecords = records; + } + + private void OnItemSelected(BaseButton.ButtonEventArgs args, ListData data) + { + if (data is not StatusListData(var record)) + return; + + FormattedMessage GetLoc(string fluentId, params (string,object)[] args) + { + var msg = new FormattedMessage(); + var fluent = Loc.GetString(fluentId, args); + msg.AddMarkupPermissive(fluent); + return msg; + } + + // Set personal info + PersonName.Text = record.TargetInfo.Name; + TargetAge.SetMessage(GetLoc( + "wanted-list-age-label", + ("age", record.TargetInfo.Age) + )); + TargetJob.SetMessage(GetLoc( + "wanted-list-job-label", + ("job", record.TargetInfo.JobTitle.ToLower()) + )); + TargetSpecies.SetMessage(GetLoc( + "wanted-list-species-label", + ("species", record.TargetInfo.Species.ToLower()) + )); + TargetGender.SetMessage(GetLoc( + "wanted-list-gender-label", + ("gender", record.TargetInfo.Gender) + )); + + // Set reason + WantedReason.SetMessage(GetLoc( + "wanted-list-reason-label", + ("reason", record.Reason ?? Loc.GetString("wanted-list-unknown-reason-label")) + )); + + // Set status + PersonState.SetMessage(GetLoc( + "wanted-list-status-label", + ("status", record.Status.ToString().ToLower()) + )); + + // Set initiator + InitiatorName.SetMessage(GetLoc( + "wanted-list-initiator-label", + ("initiator", record.Initiator ?? Loc.GetString("wanted-list-unknown-initiator-label")) + )); + + // History table + // Clear table if it exists + HistoryTable.RemoveAllChildren(); + + HistoryTable.AddChild(new Label() + { + Text = Loc.GetString("wanted-list-history-table-time-col"), + StyleClasses = { "LabelSmall" }, + HorizontalAlignment = HAlignment.Center, + }); + HistoryTable.AddChild(new Label() + { + Text = Loc.GetString("wanted-list-history-table-reason-col"), + StyleClasses = { "LabelSmall" }, + HorizontalAlignment = HAlignment.Center, + HorizontalExpand = true, + }); + + HistoryTable.AddChild(new Label() + { + Text = Loc.GetString("wanted-list-history-table-initiator-col"), + StyleClasses = { "LabelSmall" }, + HorizontalAlignment = HAlignment.Center, + }); + + if (record.History.Count > 0) + { + HistoryTable.Visible = true; + + foreach (var history in record.History.OrderByDescending(h => h.AddTime)) + { + HistoryTable.AddChild(new Label() + { + Text = $"{history.AddTime.Hours:00}:{history.AddTime.Minutes:00}:{history.AddTime.Seconds:00}", + StyleClasses = { "LabelSmall" }, + VerticalAlignment = VAlignment.Top, + }); + + HistoryTable.AddChild(new RichTextLabel() + { + Text = $"[color=white]{history.Crime}[/color]", + HorizontalExpand = true, + VerticalAlignment = VAlignment.Top, + StyleClasses = { "LabelSubText" }, + Margin = new(10f, 0f), + }); + + HistoryTable.AddChild(new RichTextLabel() + { + Text = $"[color=white]{history.InitiatorName}[/color]", + StyleClasses = { "LabelSubText" }, + VerticalAlignment = VAlignment.Top, + }); + } + } + + RecordUnselected.Visible = false; + PersonContainer.Visible = true; + + // Save selected item + _selectedTargetName = record.TargetInfo.Name; + } + + private void GenerateItem(ListData data, ListContainerButton button) + { + if (data is not StatusListData(var record)) + return; + + var box = new BoxContainer() { Orientation = LayoutOrientation.Horizontal, HorizontalExpand = true }; + var label = new Label() { Text = record.TargetInfo.Name }; + var rect = new TextureRect() + { + TextureScale = new(2.2f), + VerticalAlignment = VAlignment.Center, + HorizontalAlignment = HAlignment.Center, + Margin = new(0f, 0f, 6f, 0f), + }; + + if (record.Status is not SecurityStatus.None) + { + var proto = "SecurityIcon" + record.Status switch + { + SecurityStatus.Detained => "Incarcerated", + _ => record.Status.ToString(), + }; + + if (_prototypeManager.TryIndex(proto, out var prototype)) + { + rect.Texture = _spriteSystem.Frame0(prototype.Icon); + } + } + + box.AddChild(rect); + box.AddChild(label); + button.AddChild(box); + button.AddStyleClass(ListContainer.StyleClassListContainerButton); + + if (record.TargetInfo.Name.Equals(_selectedTargetName)) + { + button.Pressed = true; + // For some reason the event is not called when `Pressed` changed, call it manually. + OnItemSelected( + new(button, new(new(), BoundKeyState.Down, new(), false, new(), new())), + data); + } + } +} + +internal record StatusListData(WantedRecord Record) : ListData; diff --git a/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.xaml b/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.xaml new file mode 100644 index 000000000000..7b5d116ad74b --- /dev/null +++ b/Content.Client/CartridgeLoader/Cartridges/WantedListUiFragment.xaml @@ -0,0 +1,50 @@ + + + + + + + diff --git a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs index cd422328c3e1..7caec6150ede 100644 --- a/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs +++ b/Content.Server/CartridgeLoader/CartridgeLoaderSystem.cs @@ -340,6 +340,9 @@ protected override void OnItemInserted(EntityUid uid, CartridgeLoaderComponent l if (args.Container.ID != InstalledContainerId && args.Container.ID != loader.CartridgeSlot.ID) return; + if (TryComp(args.Entity, out CartridgeComponent? cartridge)) + cartridge.LoaderUid = uid; + RaiseLocalEvent(args.Entity, new CartridgeAddedEvent(uid)); base.OnItemInserted(uid, loader, args); } @@ -360,6 +363,9 @@ protected override void OnItemRemoved(EntityUid uid, CartridgeLoaderComponent lo if (deactivate) RaiseLocalEvent(args.Entity, new CartridgeDeactivatedEvent(uid)); + if (TryComp(args.Entity, out CartridgeComponent? cartridge)) + cartridge.LoaderUid = null; + RaiseLocalEvent(args.Entity, new CartridgeRemovedEvent(uid)); base.OnItemRemoved(uid, loader, args); diff --git a/Content.Server/CartridgeLoader/Cartridges/WantedListCartridge.cs b/Content.Server/CartridgeLoader/Cartridges/WantedListCartridge.cs new file mode 100644 index 000000000000..08eef62379ab --- /dev/null +++ b/Content.Server/CartridgeLoader/Cartridges/WantedListCartridge.cs @@ -0,0 +1,8 @@ +using Content.Shared.Security; + +namespace Content.Server.CartridgeLoader.Cartridges; + +[RegisterComponent] +public sealed partial class WantedListCartridgeComponent : Component +{ +} diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs index c5f1d159f31c..ca1d45e64494 100644 --- a/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs +++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsConsoleSystem.cs @@ -68,6 +68,13 @@ private void OnFiltersChanged(Entity ent, ref S } } + private void GetOfficer(EntityUid uid, out string officer) + { + var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(null, uid); + RaiseLocalEvent(tryGetIdentityShortInfoEvent); + officer = tryGetIdentityShortInfoEvent.Title ?? Loc.GetString("criminal-records-console-unknown-officer"); + } + private void OnChangeStatus(Entity ent, ref CriminalRecordChangeStatus msg) { // prevent malf client violating wanted/reason nullability @@ -90,29 +97,22 @@ private void OnChangeStatus(Entity ent, ref Cri return; } + var oldStatus = record.Status; + + var name = _records.RecordName(key.Value); + GetOfficer(mob.Value, out var officer); + // when arresting someone add it to history automatically // fallback exists if the player was not set to wanted beforehand if (msg.Status == SecurityStatus.Detained) { var oldReason = record.Reason ?? Loc.GetString("criminal-records-console-unspecified-reason"); var history = Loc.GetString("criminal-records-console-auto-history", ("reason", oldReason)); - _criminalRecords.TryAddHistory(key.Value, history); + _criminalRecords.TryAddHistory(key.Value, history, officer); } - var oldStatus = record.Status; - // will probably never fail given the checks above - _criminalRecords.TryChangeStatus(key.Value, msg.Status, msg.Reason); - - var name = _records.RecordName(key.Value); - var officer = Loc.GetString("criminal-records-console-unknown-officer"); - - var tryGetIdentityShortInfoEvent = new TryGetIdentityShortInfoEvent(null, mob.Value); - RaiseLocalEvent(tryGetIdentityShortInfoEvent); - if (tryGetIdentityShortInfoEvent.Title != null) - { - officer = tryGetIdentityShortInfoEvent.Title; - } + _criminalRecords.TryChangeStatus(key.Value, msg.Status, msg.Reason, officer); (string, object)[] args; if (reason != null) @@ -152,14 +152,16 @@ private void OnChangeStatus(Entity ent, ref Cri private void OnAddHistory(Entity ent, ref CriminalRecordAddHistory msg) { - if (!CheckSelected(ent, msg.Actor, out _, out var key)) + if (!CheckSelected(ent, msg.Actor, out var mob, out var key)) return; var line = msg.Line.Trim(); if (line.Length < 1 || line.Length > ent.Comp.MaxStringLength) return; - if (!_criminalRecords.TryAddHistory(key.Value, line)) + GetOfficer(mob.Value, out var officer); + + if (!_criminalRecords.TryAddHistory(key.Value, line, officer)) return; // no radio message since its not crucial to officers patrolling diff --git a/Content.Server/CriminalRecords/Systems/CriminalRecordsSystem.cs b/Content.Server/CriminalRecords/Systems/CriminalRecordsSystem.cs index a65fb0be9e1a..7c65ce8c248c 100644 --- a/Content.Server/CriminalRecords/Systems/CriminalRecordsSystem.cs +++ b/Content.Server/CriminalRecords/Systems/CriminalRecordsSystem.cs @@ -1,10 +1,15 @@ -using System.Diagnostics.CodeAnalysis; +using System.Linq; +using Content.Server.CartridgeLoader; +using Content.Server.CartridgeLoader.Cartridges; using Content.Server.StationRecords.Systems; using Content.Shared.CriminalRecords; using Content.Shared.CriminalRecords.Systems; using Content.Shared.Security; using Content.Shared.StationRecords; using Content.Server.GameTicking; +using Content.Server.Station.Systems; +using Content.Shared.CartridgeLoader; +using Content.Shared.CartridgeLoader.Cartridges; namespace Content.Server.CriminalRecords.Systems; @@ -20,12 +25,18 @@ public sealed class CriminalRecordsSystem : SharedCriminalRecordsSystem { [Dependency] private readonly GameTicker _ticker = default!; [Dependency] private readonly StationRecordsSystem _records = default!; + [Dependency] private readonly StationSystem _station = default!; + [Dependency] private readonly CartridgeLoaderSystem _cartridge = default!; public override void Initialize() { base.Initialize(); SubscribeLocalEvent(OnGeneralRecordCreated); + SubscribeLocalEvent(OnRecordChanged); + SubscribeLocalEvent(OnCartridgeUiReady); + SubscribeLocalEvent(OnHistoryAdded); + SubscribeLocalEvent(OnHistoryRemoved); } private void OnGeneralRecordCreated(AfterGeneralRecordCreatedEvent ev) @@ -39,14 +50,14 @@ private void OnGeneralRecordCreated(AfterGeneralRecordCreatedEvent ev) /// Reason should only be passed if status is Wanted, nullability isn't checked. /// /// True if the status is changed, false if not - public bool TryChangeStatus(StationRecordKey key, SecurityStatus status, string? reason) + public bool TryChangeStatus(StationRecordKey key, SecurityStatus status, string? reason, string? initiatorName = null) { // don't do anything if its the same status if (!_records.TryGetRecord(key, out var record) || status == record.Status) return false; - OverwriteStatus(key, record, status, reason); + OverwriteStatus(key, record, status, reason, initiatorName); return true; } @@ -54,16 +65,24 @@ public bool TryChangeStatus(StationRecordKey key, SecurityStatus status, string? /// /// Sets the status without checking previous status or reason nullability. /// - public void OverwriteStatus(StationRecordKey key, CriminalRecord record, SecurityStatus status, string? reason) + public void OverwriteStatus(StationRecordKey key, CriminalRecord record, SecurityStatus status, string? reason, string? initiatorName = null) { record.Status = status; record.Reason = reason; + record.InitiatorName = initiatorName; var name = _records.RecordName(key); if (name != string.Empty) UpdateCriminalIdentity(name, status); _records.Synchronize(key); + + var args = new CriminalRecordChangedEvent(record); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var readerUid, out _)) + { + RaiseLocalEvent(readerUid, ref args); + } } /// @@ -76,15 +95,23 @@ public bool TryAddHistory(StationRecordKey key, CrimeHistory entry) return false; record.History.Add(entry); + + var args = new CriminalHistoryAddedEvent(entry); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var readerUid, out _)) + { + RaiseLocalEvent(readerUid, ref args); + } + return true; } /// /// Creates and tries to add a history entry using the current time. /// - public bool TryAddHistory(StationRecordKey key, string line) + public bool TryAddHistory(StationRecordKey key, string line, string? initiatorName = null) { - var entry = new CrimeHistory(_ticker.RoundDuration(), line); + var entry = new CrimeHistory(_ticker.RoundDuration(), line, initiatorName); return TryAddHistory(key, entry); } @@ -100,7 +127,58 @@ public bool TryDeleteHistory(StationRecordKey key, uint index) if (index >= record.History.Count) return false; + var history = record.History[(int)index]; record.History.RemoveAt((int) index); + + var args = new CriminalHistoryRemovedEvent(history); + var query = EntityQueryEnumerator(); + while (query.MoveNext(out var readerUid, out _)) + { + RaiseLocalEvent(readerUid, ref args); + } + return true; } + + private void OnRecordChanged(Entity ent, ref CriminalRecordChangedEvent args) => + StateChanged(ent); + + private void OnHistoryAdded(Entity ent, ref CriminalHistoryAddedEvent args) => + StateChanged(ent); + + private void OnHistoryRemoved(Entity ent, ref CriminalHistoryRemovedEvent args) => + StateChanged(ent); + + private void StateChanged(Entity ent) + { + if (Comp(ent).LoaderUid is not { } loaderUid) + return; + + UpdateReaderUi(ent, loaderUid); + } + + private void OnCartridgeUiReady(Entity ent, ref CartridgeUiReadyEvent args) + { + UpdateReaderUi(ent, args.Loader); + } + + private void UpdateReaderUi(Entity ent, EntityUid loaderUid) + { + if (_station.GetOwningStation(ent) is not { } station) + return; + + var records = _records.GetRecordsOfType(station) + .Where(cr => cr.Item2.Status is not SecurityStatus.None || cr.Item2.History.Count > 0) + .Select(cr => + { + var (i, r) = cr; + var key = new StationRecordKey(i, station); + // Hopefully it will work smoothly..... + _records.TryGetRecord(key, out GeneralStationRecord? generalRecord); + return new WantedRecord(generalRecord!, r.Status, r.Reason, r.InitiatorName, r.History); + }); + var state = new WantedListUiState(records.ToList()); + + _cartridge.UpdateCartridgeUiState(loaderUid, state); + } } diff --git a/Content.Server/Objectives/Systems/StealConditionSystem.cs b/Content.Server/Objectives/Systems/StealConditionSystem.cs index be34a80fe348..e2d81e011cf5 100644 --- a/Content.Server/Objectives/Systems/StealConditionSystem.cs +++ b/Content.Server/Objectives/Systems/StealConditionSystem.cs @@ -1,5 +1,6 @@ using Content.Server.Objectives.Components; using Content.Server.Objectives.Components.Targets; +using Content.Shared.CartridgeLoader; using Content.Shared.Mind; using Content.Shared.Objectives.Components; using Content.Shared.Objectives.Systems; @@ -172,6 +173,11 @@ private int CheckStealTarget(EntityUid entity, StealConditionComponent condition if (target.StealGroup != condition.StealGroup) return 0; + // check if cartridge is installed + if (TryComp(entity, out var cartridge) && + cartridge.InstallationStatus is not InstallationStatus.Cartridge) + return 0; + // check if needed target alive if (condition.CheckAlive) { diff --git a/Content.Shared/CartridgeLoader/Cartridges/WantedListUiState.cs b/Content.Shared/CartridgeLoader/Cartridges/WantedListUiState.cs new file mode 100644 index 000000000000..9d55e0c16368 --- /dev/null +++ b/Content.Shared/CartridgeLoader/Cartridges/WantedListUiState.cs @@ -0,0 +1,11 @@ +using Content.Shared.CriminalRecords; +using Content.Shared.CriminalRecords.Systems; +using Robust.Shared.Serialization; + +namespace Content.Shared.CartridgeLoader.Cartridges; + +[Serializable, NetSerializable] +public sealed class WantedListUiState(List records) : BoundUserInterfaceState +{ + public List Records = records; +} diff --git a/Content.Shared/CriminalRecords/CriminalRecord.cs b/Content.Shared/CriminalRecords/CriminalRecord.cs index 0fe23d439541..5a023a9188c6 100644 --- a/Content.Shared/CriminalRecords/CriminalRecord.cs +++ b/Content.Shared/CriminalRecords/CriminalRecord.cs @@ -23,6 +23,12 @@ public sealed record CriminalRecord [DataField] public string? Reason; + /// + /// The name of the person who changed the status. + /// + [DataField] + public string? InitiatorName; + /// /// Criminal history of the person. /// This should have charges and time served added after someone is detained. @@ -35,4 +41,4 @@ public sealed record CriminalRecord /// A line of criminal activity and the time it was added at. /// [Serializable, NetSerializable] -public record struct CrimeHistory(TimeSpan AddTime, string Crime); +public record struct CrimeHistory(TimeSpan AddTime, string Crime, string? InitiatorName); diff --git a/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsSystem.cs b/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsSystem.cs index 96b33ab91bd3..d665d32f1ed2 100644 --- a/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsSystem.cs +++ b/Content.Shared/CriminalRecords/Systems/SharedCriminalRecordsSystem.cs @@ -2,6 +2,8 @@ using Content.Shared.IdentityManagement.Components; using Content.Shared.Security; using Content.Shared.Security.Components; +using Content.Shared.StationRecords; +using Robust.Shared.Serialization; namespace Content.Shared.CriminalRecords.Systems; @@ -50,3 +52,22 @@ public void SetCriminalIcon(string name, SecurityStatus status, EntityUid charac Dirty(characterUid, record); } } + +[Serializable, NetSerializable] +public struct WantedRecord(GeneralStationRecord targetInfo, SecurityStatus status, string? reason, string? initiator, List history) +{ + public GeneralStationRecord TargetInfo = targetInfo; + public SecurityStatus Status = status; + public string? Reason = reason; + public string? Initiator = initiator; + public List History = history; +}; + +[ByRefEvent] +public record struct CriminalRecordChangedEvent(CriminalRecord Record); + +[ByRefEvent] +public record struct CriminalHistoryAddedEvent(CrimeHistory History); + +[ByRefEvent] +public record struct CriminalHistoryRemovedEvent(CrimeHistory History); diff --git a/Resources/Locale/en-US/cartridge-loader/cartridges.ftl b/Resources/Locale/en-US/cartridge-loader/cartridges.ftl index f5cda2f2a18b..2db27f5be09a 100644 --- a/Resources/Locale/en-US/cartridge-loader/cartridges.ftl +++ b/Resources/Locale/en-US/cartridge-loader/cartridges.ftl @@ -19,3 +19,32 @@ log-probe-scan = Downloaded logs from {$device}! log-probe-label-time = Time log-probe-label-accessor = Accessed by log-probe-label-number = # + +# Wanted list cartridge +wanted-list-program-name = Wanted list +wanted-list-label-no-records = It's all right, cowboy +wanted-list-search-placeholder = Search by name and status + +wanted-list-age-label = [color=darkgray]Age:[/color] [color=white]{$age}[/color] +wanted-list-job-label = [color=darkgray]Job:[/color] [color=white]{$job}[/color] +wanted-list-species-label = [color=darkgray]Species:[/color] [color=white]{$species}[/color] +wanted-list-gender-label = [color=darkgray]Gender:[/color] [color=white]{$gender}[/color] + +wanted-list-reason-label = [color=darkgray]Reason:[/color] [color=white]{$reason}[/color] +wanted-list-unknown-reason-label = unknown reason + +wanted-list-initiator-label = [color=darkgray]Initiator:[/color] [color=white]{$initiator}[/color] +wanted-list-unknown-initiator-label = unknown initiator + +wanted-list-status-label = [color=darkgray]status:[/color] {$status -> + [suspected] [color=yellow]suspected[/color] + [wanted] [color=red]wanted[/color] + [detained] [color=#b18644]detained[/color] + [paroled] [color=green]paroled[/color] + [discharged] [color=green]discharged[/color] + *[other] none + } + +wanted-list-history-table-time-col = Time +wanted-list-history-table-reason-col = Crime +wanted-list-history-table-initiator-col = Initiator diff --git a/Resources/Locale/en-US/criminal-records/criminal-records.ftl b/Resources/Locale/en-US/criminal-records/criminal-records.ftl index 6d6a97300c23..2a7c09912fae 100644 --- a/Resources/Locale/en-US/criminal-records/criminal-records.ftl +++ b/Resources/Locale/en-US/criminal-records/criminal-records.ftl @@ -39,7 +39,7 @@ criminal-records-console-released = {$name} has been released by {$officer}. criminal-records-console-not-wanted = {$officer} cleared the wanted status of {$name}. criminal-records-console-paroled = {$name} has been released on parole by {$officer}. criminal-records-console-not-parole = {$officer} cleared the parole status of {$name}. -criminal-records-console-unknown-officer = +criminal-records-console-unknown-officer = ## Filters diff --git a/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl b/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl index 91b3c92b1c33..689e2e7808eb 100644 --- a/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl +++ b/Resources/Locale/en-US/objectives/conditions/steal-target-groups.ftl @@ -40,6 +40,7 @@ steal-target-groups-clothing-eyes-hud-beer = beer goggles steal-target-groups-bible = bible steal-target-groups-clothing-neck-goldmedal = gold medal of crewmanship steal-target-groups-clothing-neck-clownmedal = clown medal +steal-target-groups-wanted-list-cartridge = wanted list cartridge # Thief structures steal-target-groups-teg = teg generator part diff --git a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml index d31896301600..31ebad618370 100644 --- a/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml +++ b/Resources/Prototypes/Catalog/Fills/Lockers/heads.yml @@ -325,6 +325,7 @@ - id: RubberStampHos - id: SecurityTechFabCircuitboard - id: WeaponDisabler + - id: WantedListCartridge # Hardsuit table, used for suit storage as well - type: entityTable diff --git a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml index f9581149e214..91493f48cd1f 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/cartridges.yml @@ -93,3 +93,26 @@ - type: GuideHelp guides: - Forensics + +- type: entity + parent: BaseItem + id: WantedListCartridge + name: Wanted list cartridge + description: A program to get a list of wanted persons. + components: + - type: Sprite + sprite: Objects/Devices/cartridge.rsi + state: cart-sec + - type: Icon + sprite: Objects/Devices/cartridge.rsi + state: cart-sec + - type: UIFragment + ui: !type:WantedListUi + - type: Cartridge + programName: wanted-list-program-name + icon: + sprite: Objects/Misc/books.rsi + state: icon_magnifier + - type: WantedListCartridge + - type: StealTarget + stealGroup: WantedListCartridge diff --git a/Resources/Prototypes/Entities/Objects/Devices/pda.yml b/Resources/Prototypes/Entities/Objects/Devices/pda.yml index 40f6f77e12d2..48e7a28debeb 100644 --- a/Resources/Prototypes/Entities/Objects/Devices/pda.yml +++ b/Resources/Prototypes/Entities/Objects/Devices/pda.yml @@ -114,6 +114,18 @@ - type: Speech speechVerb: Robotic +- type: entity + id: BaseSecurityPDA + abstract: true + components: + - type: CartridgeLoader + uiKey: enum.PdaUiKey.Key + preinstalled: + - CrewManifestCartridge + - NotekeeperCartridge + - NewsReaderCartridge + - WantedListCartridge + - type: entity parent: BasePDA id: BaseMedicalPDA @@ -433,7 +445,7 @@ state: pda-library - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: LawyerPDA name: lawyer PDA description: For lawyers to poach dubious clients. @@ -476,7 +488,7 @@ state: pda-janitor - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: CaptainPDA name: captain PDA description: Surprisingly no different from your PDA. @@ -651,7 +663,7 @@ state: pda-science - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: HoSPDA name: head of security PDA description: Whosoever bears this PDA is the law. @@ -666,7 +678,7 @@ state: pda-hos - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: WardenPDA name: warden PDA description: The OS appears to have been jailbroken. @@ -681,7 +693,7 @@ state: pda-warden - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: SecurityPDA name: security PDA description: Red to hide the stains of passenger blood. @@ -695,7 +707,7 @@ state: pda-security - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: CentcomPDA name: CentComm PDA description: Light green sign of walking bureaucracy. @@ -733,6 +745,7 @@ - NotekeeperCartridge - NewsReaderCartridge - LogProbeCartridge + - WantedListCartridge - type: entity parent: CentcomPDA @@ -834,7 +847,7 @@ - Cartridge - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: ERTLeaderPDA name: ERT Leader PDA suffix: Leader @@ -982,7 +995,7 @@ state: pda-boxer - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: DetectivePDA name: detective PDA description: Smells like rain... pouring down the rooftops... @@ -1082,7 +1095,7 @@ state: pda-seniorphysician - type: entity - parent: BasePDA + parent: [BaseSecurityPDA, BasePDA] id: SeniorOfficerPDA name: senior officer PDA description: Beaten, battered and broken, but just barely useable. diff --git a/Resources/Prototypes/Objectives/objectiveGroups.yml b/Resources/Prototypes/Objectives/objectiveGroups.yml index 481ca0f93d84..e72de0d94a93 100644 --- a/Resources/Prototypes/Objectives/objectiveGroups.yml +++ b/Resources/Prototypes/Objectives/objectiveGroups.yml @@ -73,6 +73,7 @@ ForensicScannerStealObjective: 1 #sec FlippoEngravedLighterStealObjective: 0.5 ClothingHeadHatWardenStealObjective: 1 + WantedListCartridgeStealObjective: 1 ClothingOuterHardsuitVoidParamedStealObjective: 1 #med MedicalTechFabCircuitboardStealObjective: 1 ClothingHeadsetAltMedicalStealObjective: 1 diff --git a/Resources/Prototypes/Objectives/stealTargetGroups.yml b/Resources/Prototypes/Objectives/stealTargetGroups.yml index 48f56e2bfcd7..09619bf9868e 100644 --- a/Resources/Prototypes/Objectives/stealTargetGroups.yml +++ b/Resources/Prototypes/Objectives/stealTargetGroups.yml @@ -263,6 +263,13 @@ sprite: Clothing/Neck/Medals/clownmedal.rsi state: icon +- type: stealTargetGroup + id: WantedListCartridge + name: steal-target-groups-wanted-list-cartridge + sprite: + sprite: Objects/Devices/cartridge.rsi + state: cart-sec + #Thief structures - type: stealTargetGroup diff --git a/Resources/Prototypes/Objectives/thief.yml b/Resources/Prototypes/Objectives/thief.yml index f8e44d831e94..7a46d0f5e9b8 100644 --- a/Resources/Prototypes/Objectives/thief.yml +++ b/Resources/Prototypes/Objectives/thief.yml @@ -184,6 +184,15 @@ - type: Objective difficulty: 1.2 +- type: entity + parent: BaseThiefStealObjective + id: WantedListCartridgeStealObjective + components: + - type: StealCondition + stealGroup: WantedListCartridge + - type: Objective + difficulty: 1 + - type: entity #Medical subgroup parent: BaseThiefStealObjective id: ClothingOuterHardsuitVoidParamedStealObjective diff --git a/Resources/Textures/Objects/Devices/cartridge.rsi/cart-sec.png b/Resources/Textures/Objects/Devices/cartridge.rsi/cart-sec.png new file mode 100644 index 0000000000000000000000000000000000000000..6a3197004cbf0460f517049aae94986a820100c8 GIT binary patch literal 314 zcmeAS@N?(olHy`uVBq!ia0vp^3LwnE1|*BCs=fdz#^NA%Cx&(BWL^R}w>(`OLn2z= zPBG+bHsEosU!^CfG-YaI@P@Arw!!>Ij%i9n2!48CD9e?Vk(r#al<({8fG=PF9}i=a zXiNNK?We4?Xvgswmreg783m87T6N&e>_dCMzu2W0{b+?@a@w5Va_S66OTvzKT-&+) zy`Tg0gP>`v7O_v|ifB21#c)yI>9-=2!@74lNZGY-JEyyB!?LprqYi4z{jcMH#o42s z{*tBWRzJ5%XQ9=%64~O4%?le|Nwo=>Mck8YduV;#K$H3X-)LTAXO}DUR*80WXvyrb zb#Pgt_wn=c8wNawcQEPn`j%LP9bO0YC0}ZUXPU1sgBFm@0mLA1DR?r7@^tlcS?83{ F1ONqldhh@M literal 0 HcmV?d00001 diff --git a/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json b/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json index f3b02a2b2eab..d5fad5600621 100644 --- a/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json +++ b/Resources/Textures/Objects/Devices/cartridge.rsi/meta.json @@ -1,7 +1,7 @@ { "version": 1, "license": "CC-BY-SA-3.0", - "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1cdfb0230cc96d0ba751fa002d04f8aa2f25ad7d and tgstation at tgstation at https://github.com/tgstation/tgstation/commit/0c15d9dbcf0f2beb230eba5d9d889ef2d1945bb8, cart-log made by Skarletto (github)", + "copyright": "Taken from vgstation at https://github.com/vgstation-coders/vgstation13/commit/1cdfb0230cc96d0ba751fa002d04f8aa2f25ad7d and tgstation at tgstation at https://github.com/tgstation/tgstation/commit/0c15d9dbcf0f2beb230eba5d9d889ef2d1945bb8, cart-log made by Skarletto (github), cart-sec made by dieselmohawk (discord)", "size": { "x": 32, "y": 32 @@ -79,6 +79,9 @@ { "name": "cart-y" }, + { + "name": "cart-sec" + }, { "name": "insert_overlay" } From ccadcc97819daaa2f8028df695527643392f9063 Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 10:23:08 +0000 Subject: [PATCH 38/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index 156fe91ffc8d..df513a66be1d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,11 +1,4 @@ Entries: -- author: Winkarst-cpu - changes: - - message: Added exit confirmation for character setup menu with unsaved changes. - type: Add - id: 6899 - time: '2024-07-11T00:24:37.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29875 - author: ShadowCommander changes: - message: Players can now use melee attacks and shoves while dragging an entity @@ -3918,3 +3911,14 @@ id: 7398 time: '2024-09-19T08:41:24.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31241 +- author: Ertanic + changes: + - message: Wanted list program and its cartridge. + type: Add + - message: The cartridge has been added to the HOS locker. + type: Add + - message: Added target to thief on wanted list cartridge. + type: Add + id: 7399 + time: '2024-09-19T10:22:02.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31223 From 854bfd27cb062680caaeeec2a4c58b53372b4af6 Mon Sep 17 00:00:00 2001 From: Errant <35878406+Errant-4@users.noreply.github.com> Date: Thu, 19 Sep 2024 12:23:45 +0200 Subject: [PATCH 39/40] Crew Monitor filter (#31659) * crewmon filter * string case matching Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --------- Co-authored-by: slarticodefast <161409025+slarticodefast@users.noreply.github.com> --- .../Medical/CrewMonitoring/CrewMonitoringWindow.xaml | 3 +++ .../Medical/CrewMonitoring/CrewMonitoringWindow.xaml.cs | 5 +++++ .../en-US/medical/components/crew-monitoring-component.ftl | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml index 660f2e5e11f5..dd40749d33b2 100644 --- a/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml +++ b/Content.Client/Medical/CrewMonitoring/CrewMonitoringWindow.xaml @@ -15,6 +15,9 @@ + + departmentSens // Populate departments foreach (var sensor in departmentSensors) { + if (!string.IsNullOrEmpty(SearchLineEdit.Text) + && !sensor.Name.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase) + && !sensor.Job.Contains(SearchLineEdit.Text, StringComparison.CurrentCultureIgnoreCase)) + continue; + var coordinates = _entManager.GetCoordinates(sensor.Coordinates); // Add a button that will hold a username and other details diff --git a/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl b/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl index 7fd7f4608e16..601c45e4e223 100644 --- a/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl +++ b/Resources/Locale/en-US/medical/components/crew-monitoring-component.ftl @@ -2,6 +2,8 @@ crew-monitoring-user-interface-title = Crew Monitoring Console +crew-monitor-filter-line-placeholder = Filter + crew-monitoring-user-interface-name = Name crew-monitoring-user-interface-job = Job crew-monitoring-user-interface-status = Status From eb9047982a0080b9b26b1d124e56b6279a0bd96f Mon Sep 17 00:00:00 2001 From: PJBot Date: Thu, 19 Sep 2024 10:24:51 +0000 Subject: [PATCH 40/40] Automatic changelog update --- Resources/Changelog/Changelog.yml | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/Resources/Changelog/Changelog.yml b/Resources/Changelog/Changelog.yml index df513a66be1d..5f5d96f41c9d 100644 --- a/Resources/Changelog/Changelog.yml +++ b/Resources/Changelog/Changelog.yml @@ -1,12 +1,4 @@ Entries: -- author: ShadowCommander - changes: - - message: Players can now use melee attacks and shoves while dragging an entity - in their active hand. - type: Tweak - id: 6900 - time: '2024-07-11T04:48:00.0000000+00:00' - url: https://github.com/space-wizards/space-station-14/pull/29703 - author: Cojoke-dot changes: - message: You can no longer shoot out of crates with guns @@ -3922,3 +3914,10 @@ id: 7399 time: '2024-09-19T10:22:02.0000000+00:00' url: https://github.com/space-wizards/space-station-14/pull/31223 +- author: Errant + changes: + - message: Crew monitor list can now be filtered by name and job. + type: Add + id: 7400 + time: '2024-09-19T10:23:45.0000000+00:00' + url: https://github.com/space-wizards/space-station-14/pull/31659