diff --git a/.github/workflows/build-map-renderer.yml b/.github/workflows/build-map-renderer.yml index 35aed1a7f7..01575f64b9 100644 --- a/.github/workflows/build-map-renderer.yml +++ b/.github/workflows/build-map-renderer.yml @@ -10,7 +10,7 @@ on: jobs: build: - if: github.actor != 'PJBot' && github.event.pull_request.draft == false + if: github.actor != 'PJBot' && github.event.pull_request.draft == false && github.actor != 'DeltaV-Bot' strategy: matrix: os: [ubuntu-latest] diff --git a/.github/workflows/build-test-debug.yml b/.github/workflows/build-test-debug.yml index 47f9fd1a51..519f5af6f4 100644 --- a/.github/workflows/build-test-debug.yml +++ b/.github/workflows/build-test-debug.yml @@ -10,7 +10,7 @@ on: jobs: build: - if: github.actor != 'PJBot' && github.event.pull_request.draft == false + if: github.actor != 'PJBot' && github.event.pull_request.draft == false && github.actor != 'DeltaV-Bot' strategy: matrix: os: [ubuntu-latest] diff --git a/.github/workflows/close-master-pr.yml b/.github/workflows/close-master-pr.yml new file mode 100644 index 0000000000..66843d35dd --- /dev/null +++ b/.github/workflows/close-master-pr.yml @@ -0,0 +1,27 @@ +name: Close PR's on master + +on: + pull_request_target: + types: [ opened, ready_for_review ] + +jobs: + run: + runs-on: ubuntu-latest + if: ${{github.head_ref == 'master' || github.head_ref == 'main' || github.head_ref == 'develop'}} + + steps: + - uses: superbrothers/close-pull-request@v3 + with: + comment: "Thank you for contributing to the Space Station 14 repository. Unfortunately, it looks like you submitted your pull request from the master branch. We suggest you follow [our git usage documentation](https://docs.spacestation14.com/en/general-development/setup/git-for-the-ss14-developer.html) \n\n You can move your current work from the master branch to another branch by doing `git branch + diff --git a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs index 670ba08871..bf5984e809 100644 --- a/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs +++ b/Content.Client/Access/UI/IdCardConsoleWindow.xaml.cs @@ -55,7 +55,7 @@ public IdCardConsoleWindow(IdCardConsoleBoundUserInterface owner, IPrototypeMana foreach (var job in jobs) { - if (!job.SetPreference) + if (!job.OverrideConsoleVisibility.GetValueOrDefault(job.SetPreference)) { continue; } diff --git a/Content.Client/Administration/QuickDialogSystem.cs b/Content.Client/Administration/QuickDialogSystem.cs index 84236c5a3e..d015b7769b 100644 --- a/Content.Client/Administration/QuickDialogSystem.cs +++ b/Content.Client/Administration/QuickDialogSystem.cs @@ -1,13 +1,8 @@ -using System.Linq; using Content.Client.UserInterface.Controls; using Content.Shared.Administration; -using Robust.Client.UserInterface; -using Robust.Client.UserInterface.Controls; namespace Content.Client.Administration; -// mfw they ported input() from BYOND - /// /// This handles the client portion of quick dialogs. /// @@ -21,149 +16,22 @@ public override void Initialize() private void OpenDialog(QuickDialogOpenEvent ev) { - var window = new FancyWindow() - { - Title = ev.Title - }; - - var entryContainer = new BoxContainer() - { - Orientation = BoxContainer.LayoutOrientation.Vertical, - Margin = new Thickness(8), - }; - - var promptsDict = new Dictionary(); - - for (var index = 0; index < ev.Prompts.Count; index++) - { - var entry = ev.Prompts[index]; - var entryBox = new BoxContainer() - { - Orientation = BoxContainer.LayoutOrientation.Horizontal - }; - - entryBox.AddChild(new Label { Text = entry.Prompt, HorizontalExpand = true, SizeFlagsStretchRatio = 0.5f }); - var edit = new LineEdit() { HorizontalExpand = true }; - entryBox.AddChild(edit); - switch (entry.Type) - { - case QuickDialogEntryType.Integer: - edit.IsValid += VerifyInt; - edit.PlaceHolder = Loc.GetString("quick-dialog-ui-integer"); - break; - case QuickDialogEntryType.Float: - edit.IsValid += VerifyFloat; - edit.PlaceHolder = Loc.GetString("quick-dialog-ui-float"); - break; - case QuickDialogEntryType.ShortText: - edit.IsValid += VerifyShortText; - edit.PlaceHolder = Loc.GetString("quick-dialog-ui-short-text"); - break; - case QuickDialogEntryType.LongText: - edit.IsValid += VerifyLongText; - edit.PlaceHolder = Loc.GetString("quick-dialog-ui-long-text"); - break; - default: - throw new ArgumentOutOfRangeException(); - } - - promptsDict.Add(entry.FieldId, edit); - entryContainer.AddChild(entryBox); - - if (index == ev.Prompts.Count - 1) - { - // Last text box gets enter confirmation. - // Only the last so you don't accidentally confirm early. - edit.OnTextEntered += _ => Confirm(); - } - } + var ok = (ev.Buttons & QuickDialogButtonFlag.OkButton) != 0; + var cancel = (ev.Buttons & QuickDialogButtonFlag.CancelButton) != 0; + var window = new DialogWindow(ev.Title, ev.Prompts, ok: ok, cancel: cancel); - var buttonsBox = new BoxContainer() + window.OnConfirmed += responses => { - Orientation = BoxContainer.LayoutOrientation.Horizontal, - HorizontalAlignment = Control.HAlignment.Center, - }; - - var alreadyReplied = false; - - if ((ev.Buttons & QuickDialogButtonFlag.OkButton) != 0) - { - var okButton = new Button() - { - Text = Loc.GetString("quick-dialog-ui-ok"), - }; - - okButton.OnPressed += _ => Confirm(); - - buttonsBox.AddChild(okButton); - } - - if ((ev.Buttons & QuickDialogButtonFlag.OkButton) != 0) - { - var cancelButton = new Button() - { - Text = Loc.GetString("quick-dialog-ui-cancel"), - }; - - cancelButton.OnPressed += _ => - { - RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId, - new(), - QuickDialogButtonFlag.CancelButton)); - alreadyReplied = true; - window.Close(); - }; - - buttonsBox.AddChild(cancelButton); - } - - window.OnClose += () => - { - if (!alreadyReplied) - { - RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId, - new(), - QuickDialogButtonFlag.CancelButton)); - } + RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId, + responses, + QuickDialogButtonFlag.OkButton)); }; - entryContainer.AddChild(buttonsBox); - - window.ContentsContainer.AddChild(entryContainer); - - window.MinWidth *= 2; // Just double it. - - window.OpenCentered(); - - return; - - void Confirm() + window.OnCancelled += () => { RaiseNetworkEvent(new QuickDialogResponseEvent(ev.DialogId, - promptsDict.Select(x => (x.Key, x.Value.Text)).ToDictionary(x => x.Key, x => x.Text), - QuickDialogButtonFlag.OkButton)); - alreadyReplied = true; - window.Close(); - } - } - - private bool VerifyInt(string input) - { - return int.TryParse(input, out var _); - } - - private bool VerifyFloat(string input) - { - return float.TryParse(input, out var _); - } - - private bool VerifyShortText(string input) - { - return input.Length <= 100; - } - - private bool VerifyLongText(string input) - { - return input.Length <= 2000; + new(), + QuickDialogButtonFlag.CancelButton)); + }; } } diff --git a/Content.Client/Antag/AntagStatusIconSystem.cs b/Content.Client/Antag/AntagStatusIconSystem.cs index bf3955b49a..5d87837893 100644 --- a/Content.Client/Antag/AntagStatusIconSystem.cs +++ b/Content.Client/Antag/AntagStatusIconSystem.cs @@ -1,6 +1,8 @@ -using Content.Shared.Ghost; +using Content.Shared.Antag; +using Content.Shared.Revolutionary.Components; using Content.Shared.StatusIcon; using Content.Shared.StatusIcon.Components; +using Content.Shared.Zombies; using Robust.Client.Player; using Robust.Shared.Prototypes; @@ -9,24 +11,44 @@ namespace Content.Client.Antag; /// /// Used for assigning specified icons for antags. /// -public abstract class AntagStatusIconSystem : SharedStatusIconSystem - where T : IComponent +public sealed class AntagStatusIconSystem : SharedStatusIconSystem { [Dependency] private readonly IPrototypeManager _prototype = default!; [Dependency] private readonly IPlayerManager _player = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(GetRevIcon); + SubscribeLocalEvent(GetIcon); + SubscribeLocalEvent(GetIcon); + } /// - /// Will check if the local player has the same component as the one who called it and give the status icon. + /// Adds a Status Icon on an entity if the player is supposed to see it. /// - /// The status icon that your antag uses - /// The GetStatusIcon event. - protected virtual void GetStatusIcon(string antagStatusIcon, ref GetStatusIconsEvent args) + private void GetIcon(EntityUid uid, T comp, ref GetStatusIconsEvent ev) where T: IAntagStatusIconComponent { - var ent = _player.LocalPlayer?.ControlledEntity; + var ent = _player.LocalSession?.AttachedEntity; + + var canEv = new CanDisplayStatusIconsEvent(ent); + RaiseLocalEvent(uid, ref canEv); + + if (!canEv.Cancelled) + ev.StatusIcons.Add(_prototype.Index(comp.StatusIcon)); + } - if (!HasComp(ent) && !HasComp(ent)) + + /// + /// Adds the Rev Icon on an entity if the player is supposed to see it. This additional function is needed to deal + /// with a special case where if someone is a head rev we only want to display the headrev icon. + /// + private void GetRevIcon(EntityUid uid, RevolutionaryComponent comp, ref GetStatusIconsEvent ev) + { + if (HasComp(uid)) return; - args.StatusIcons.Add(_prototype.Index(antagStatusIcon)); + GetIcon(uid, comp, ref ev); + } } diff --git a/Content.Client/Atmos/EntitySystems/FirestarterSystem.cs b/Content.Client/Atmos/EntitySystems/FirestarterSystem.cs new file mode 100644 index 0000000000..3294959915 --- /dev/null +++ b/Content.Client/Atmos/EntitySystems/FirestarterSystem.cs @@ -0,0 +1,8 @@ +using Content.Shared.Atmos.EntitySystems; + +namespace Content.Client.Atmos.EntitySystems; + +public sealed class FirestarterSystem : SharedFirestarterSystem +{ + +} diff --git a/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs index 142fedc48f..ad496caa8e 100644 --- a/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs +++ b/Content.Client/Atmos/UI/GasAnalyzerBoundUserInterface.cs @@ -18,7 +18,7 @@ protected override void Open() _window = new GasAnalyzerWindow(); _window.OnClose += OnClose; - _window.OpenCentered(); + _window.OpenCenteredLeft(); } protected override void ReceiveMessage(BoundUserInterfaceMessage message) diff --git a/Content.Client/Audio/BackgroundAudioSystem.cs b/Content.Client/Audio/BackgroundAudioSystem.cs index 27b2dcb1b7..2927983062 100644 --- a/Content.Client/Audio/BackgroundAudioSystem.cs +++ b/Content.Client/Audio/BackgroundAudioSystem.cs @@ -25,8 +25,10 @@ public sealed class BackgroundAudioSystem : EntitySystem [Dependency] private readonly IStateManager _stateManager = default!; private readonly AudioParams _lobbyParams = new(-5f, 1, "Master", 0, 0, 0, true, 0f); + private readonly AudioParams _roundEndParams = new(-5f, 1, "Master", 0, 0, 0, false, 0f); - public EntityUid? LobbyStream; + public EntityUid? LobbyMusicStream; + public EntityUid? LobbyRoundRestartAudioStream; public override void Initialize() { @@ -115,7 +117,7 @@ public void RestartLobbyMusic() public void StartLobbyMusic() { - if (LobbyStream != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled)) + if (LobbyMusicStream != null || !_configManager.GetCVar(CCVars.LobbyMusicEnabled)) return; var file = _gameTicker.LobbySong; @@ -124,18 +126,21 @@ public void StartLobbyMusic() return; } - LobbyStream = _audio.PlayGlobal(file, Filter.Local(), false, + LobbyMusicStream = _audio.PlayGlobal( + file, + Filter.Local(), + false, _lobbyParams.WithVolume(_lobbyParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))))?.Entity; } private void EndLobbyMusic() { - LobbyStream = _audio.Stop(LobbyStream); + LobbyMusicStream = _audio.Stop(LobbyMusicStream); } private void PlayRestartSound(RoundRestartCleanupEvent ev) { - if (!_configManager.GetCVar(CCVars.LobbyMusicEnabled)) + if (!_configManager.GetCVar(CCVars.RestartSoundsEnabled)) return; var file = _gameTicker.RestartSound; @@ -144,10 +149,11 @@ private void PlayRestartSound(RoundRestartCleanupEvent ev) return; } - var volume = _lobbyParams.WithVolume(_lobbyParams.Volume + - SharedAudioSystem.GainToVolume( - _configManager.GetCVar(CCVars.LobbyMusicVolume))); - - _audio.PlayGlobal(file, Filter.Local(), false, volume); + LobbyRoundRestartAudioStream = _audio.PlayGlobal( + file, + Filter.Local(), + false, + _roundEndParams.WithVolume(_roundEndParams.Volume + SharedAudioSystem.GainToVolume(_configManager.GetCVar(CCVars.LobbyMusicVolume))) + )?.Entity; } } diff --git a/Content.Client/Audio/ContentAudioSystem.cs b/Content.Client/Audio/ContentAudioSystem.cs index ae881766ed..c81e0a44f1 100644 --- a/Content.Client/Audio/ContentAudioSystem.cs +++ b/Content.Client/Audio/ContentAudioSystem.cs @@ -50,15 +50,24 @@ private void OnRoundCleanup(RoundRestartCleanupEvent ev) _fadingOut.Clear(); // Preserve lobby music but everything else should get dumped. - var lobbyStream = EntityManager.System().LobbyStream; - TryComp(lobbyStream, out AudioComponent? audioComp); - var oldGain = audioComp?.Gain; + var lobbyMusic = EntityManager.System().LobbyMusicStream; + TryComp(lobbyMusic, out AudioComponent? lobbyMusicComp); + var oldMusicGain = lobbyMusicComp?.Gain; + + var restartAudio = EntityManager.System().LobbyRoundRestartAudioStream; + TryComp(restartAudio, out AudioComponent? restartComp); + var oldAudioGain = restartComp?.Gain; SilenceAudio(); - if (oldGain != null) + if (oldMusicGain != null) + { + Audio.SetGain(lobbyMusic, oldMusicGain.Value, lobbyMusicComp); + } + + if (oldAudioGain != null) { - Audio.SetGain(lobbyStream, oldGain.Value, audioComp); + Audio.SetGain(restartAudio, oldAudioGain.Value, restartComp); } } diff --git a/Content.Client/Botany/Components/ProduceComponent.cs b/Content.Client/Botany/Components/ProduceComponent.cs new file mode 100644 index 0000000000..68857da1b7 --- /dev/null +++ b/Content.Client/Botany/Components/ProduceComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Botany.Components; + +namespace Content.Client.Botany.Components; + +[RegisterComponent] +public sealed partial class ProduceComponent : SharedProduceComponent +{ +} diff --git a/Content.Client/Botany/Components/SeedComponent.cs b/Content.Client/Botany/Components/SeedComponent.cs new file mode 100644 index 0000000000..11663020fc --- /dev/null +++ b/Content.Client/Botany/Components/SeedComponent.cs @@ -0,0 +1,8 @@ +using Content.Shared.Botany.Components; + +namespace Content.Client.Botany.Components; + +[RegisterComponent] +public sealed partial class SeedComponent : SharedSeedComponent +{ +} diff --git a/Content.Client/Buckle/BuckleSystem.cs b/Content.Client/Buckle/BuckleSystem.cs index 8536c3c429..fea18e5cf3 100644 --- a/Content.Client/Buckle/BuckleSystem.cs +++ b/Content.Client/Buckle/BuckleSystem.cs @@ -2,7 +2,6 @@ using Content.Shared.Buckle; using Content.Shared.Buckle.Components; using Content.Shared.Rotation; -using Content.Shared.Vehicle.Components; using Robust.Client.GameObjects; namespace Content.Client.Buckle; @@ -26,9 +25,6 @@ private void OnBuckleAfterAutoHandleState(EntityUid uid, BuckleComponent compone if (!TryComp(uid, out var ownerSprite)) return; - if (HasComp(component.LastEntityBuckledTo)) - return; - // Adjust draw depth when the chair faces north so that the seat back is drawn over the player. // Reset the draw depth when rotated in any other direction. // TODO when ECSing, make this a visualizer diff --git a/Content.Client/Camera/CameraRecoilSystem.cs b/Content.Client/Camera/CameraRecoilSystem.cs index 65a3fc71c7..bb419b465d 100644 --- a/Content.Client/Camera/CameraRecoilSystem.cs +++ b/Content.Client/Camera/CameraRecoilSystem.cs @@ -1,14 +1,34 @@ using System.Numerics; using Content.Shared.Camera; +using Content.Shared.CCVar; +using Robust.Shared.Configuration; namespace Content.Client.Camera; public sealed class CameraRecoilSystem : SharedCameraRecoilSystem { + [Dependency] private readonly IConfigurationManager _configManager = default!; + + protected float Intensity; + public override void Initialize() { base.Initialize(); SubscribeNetworkEvent(OnCameraKick); + + _configManager.OnValueChanged(CCVars.ScreenShakeIntensity, OnCvarChanged, true); + } + + public override void Shutdown() + { + base.Shutdown(); + + _configManager.UnsubValueChanged(CCVars.ScreenShakeIntensity, OnCvarChanged); + } + + private void OnCvarChanged(float value) + { + Intensity = value; } private void OnCameraKick(CameraKickEvent ev) @@ -18,9 +38,14 @@ private void OnCameraKick(CameraKickEvent ev) public override void KickCamera(EntityUid uid, Vector2 recoil, CameraRecoilComponent? component = null) { + if (Intensity == 0) + return; + if (!Resolve(uid, ref component, false)) return; + recoil *= Intensity; + // Use really bad math to "dampen" kicks when we're already kicked. var existing = component.CurrentKick.Length(); var dampen = existing / KickMagnitudeMax; diff --git a/Content.Client/CartridgeLoader/Cartridges/LogProbeUiEntry.xaml b/Content.Client/CartridgeLoader/Cartridges/LogProbeUiEntry.xaml index 5712b301c3..598acf36e7 100644 --- a/Content.Client/CartridgeLoader/Cartridges/LogProbeUiEntry.xaml +++ b/Content.Client/CartridgeLoader/Cartridges/LogProbeUiEntry.xaml @@ -4,16 +4,16 @@ Orientation="Vertical"> diff --git a/Content.Client/CartridgeLoader/Cartridges/LogProbeUiFragment.xaml b/Content.Client/CartridgeLoader/Cartridges/LogProbeUiFragment.xaml index d369a33c6c..d12fb55cdc 100644 --- a/Content.Client/CartridgeLoader/Cartridges/LogProbeUiFragment.xaml +++ b/Content.Client/CartridgeLoader/Cartridges/LogProbeUiFragment.xaml @@ -9,10 +9,10 @@ BorderColor="#5a5a5a" BorderThickness="0 0 0 1"/> - -