diff --git a/.editorconfig b/.editorconfig index 8b92144453..8a5cf43521 100644 --- a/.editorconfig +++ b/.editorconfig @@ -127,6 +127,7 @@ csharp_indent_braces = false #csharp_indent_case_contents_when_block = true #csharp_indent_labels = one_less_than_current csharp_indent_switch_labels = true +xmldoc_indent_text = zeroindent # Space preferences csharp_space_after_cast = false diff --git a/.github/workflows/close-master-pr.yml b/.github/workflows/close-master-pr.yml index 51ce874dd0..42e512d556 100644 --- a/.github/workflows/close-master-pr.yml +++ b/.github/workflows/close-master-pr.yml @@ -12,7 +12,7 @@ jobs: 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 >()); var jobIndex = _jobPrototypeIds.IndexOf(state.TargetIdJobPrototype); - // If the job index is < 0 that means they don't have a job registered in the station records. + // If the job index is < 0 that means they don't have a job registered in the station records + // or the IdCardComponent's JobPrototype field. // For example, a new ID from a box would have no job index. if (jobIndex < 0) { diff --git a/Content.Client/Actions/ActionsSystem.cs b/Content.Client/Actions/ActionsSystem.cs index 5f0a8e1f2f..0302739816 100644 --- a/Content.Client/Actions/ActionsSystem.cs +++ b/Content.Client/Actions/ActionsSystem.cs @@ -1,6 +1,7 @@ using System.IO; using System.Linq; using Content.Shared.Actions; +using Content.Shared.Charges.Systems; using JetBrains.Annotations; using Robust.Client.Player; using Robust.Shared.ContentPack; @@ -22,6 +23,7 @@ namespace Content.Client.Actions { public delegate void OnActionReplaced(EntityUid actionId); + [Dependency] private readonly SharedChargesSystem _sharedCharges = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IResourceManager _resources = default!; [Dependency] private readonly ISerializationManager _serialization = default!; @@ -51,29 +53,6 @@ namespace Content.Client.Actions SubscribeLocalEvent(OnEntityWorldTargetHandleState); } - public override void FrameUpdate(float frameTime) - { - base.FrameUpdate(frameTime); - - var worldActionQuery = EntityQueryEnumerator(); - while (worldActionQuery.MoveNext(out var uid, out var action)) - { - UpdateAction(uid, action); - } - - var instantActionQuery = EntityQueryEnumerator(); - while (instantActionQuery.MoveNext(out var uid, out var action)) - { - UpdateAction(uid, action); - } - - var entityActionQuery = EntityQueryEnumerator(); - while (entityActionQuery.MoveNext(out var uid, out var action)) - { - UpdateAction(uid, action); - } - } - private void OnInstantHandleState(EntityUid uid, InstantActionComponent component, ref ComponentHandleState args) { if (args.Current is not InstantActionComponentState state) @@ -127,9 +106,6 @@ namespace Content.Client.Actions component.Toggled = state.Toggled; component.Cooldown = state.Cooldown; component.UseDelay = state.UseDelay; - component.Charges = state.Charges; - component.MaxCharges = state.MaxCharges; - component.RenewCharges = state.RenewCharges; component.Container = EnsureEntity(state.Container, uid); component.EntityIcon = EnsureEntity(state.EntityIcon, uid); component.CheckCanInteract = state.CheckCanInteract; @@ -152,7 +128,8 @@ namespace Content.Client.Actions if (!ResolveActionData(actionId, ref action)) return; - action.IconColor = action.Charges < 1 ? action.DisabledIconColor : action.OriginalIconColor; + // TODO: Decouple this. + action.IconColor = _sharedCharges.GetCurrentCharges(actionId.Value) == 0 ? action.DisabledIconColor : action.OriginalIconColor; base.UpdateAction(actionId, action); if (_playerManager.LocalEntity != action.AttachedEntity) diff --git a/Content.Client/Administration/AdminNameOverlay.cs b/Content.Client/Administration/AdminNameOverlay.cs index c0f31f1e3d..0d424cbff0 100644 --- a/Content.Client/Administration/AdminNameOverlay.cs +++ b/Content.Client/Administration/AdminNameOverlay.cs @@ -6,6 +6,7 @@ using Content.Shared.Administration; using Content.Shared.CCVar; using Content.Shared.Ghost; using Content.Shared.Mind; +using Content.Shared.Roles; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; @@ -22,10 +23,11 @@ internal sealed class AdminNameOverlay : Overlay private readonly IEyeManager _eyeManager; private readonly EntityLookupSystem _entityLookup; private readonly IUserInterfaceManager _userInterfaceManager; + private readonly SharedRoleSystem _roles; private readonly Font _font; private readonly Font _fontBold; - private bool _overlayClassic; - private bool _overlaySymbols; + private AdminOverlayAntagFormat _overlayFormat; + private AdminOverlayAntagSymbolStyle _overlaySymbolStyle; private bool _overlayPlaytime; private bool _overlayStartingJob; private float _ghostFadeDistance; @@ -33,9 +35,10 @@ internal sealed class AdminNameOverlay : Overlay private int _overlayStackMax; private float _overlayMergeDistance; - //TODO make this adjustable via GUI + //TODO make this adjustable via GUI? private readonly ProtoId[] _filter = ["SoloAntagonist", "TeamAntagonist", "SiliconAntagonist", "FreeAgent"]; + private readonly string _antagLabelClassic = Loc.GetString("admin-overlay-antag-classic"); public AdminNameOverlay( @@ -45,20 +48,22 @@ internal sealed class AdminNameOverlay : Overlay IResourceCache resourceCache, EntityLookupSystem entityLookup, IUserInterfaceManager userInterfaceManager, - IConfigurationManager config) + IConfigurationManager config, + SharedRoleSystem roles) { _system = system; _entityManager = entityManager; _eyeManager = eyeManager; _entityLookup = entityLookup; _userInterfaceManager = userInterfaceManager; + _roles = roles; ZIndex = 200; // Setting these to a specific ttf would break the antag symbols _font = resourceCache.NotoStack(); _fontBold = resourceCache.NotoStack(variation: "Bold"); - config.OnValueChanged(CCVars.AdminOverlayClassic, (show) => { _overlayClassic = show; }, true); - config.OnValueChanged(CCVars.AdminOverlaySymbols, (show) => { _overlaySymbols = show; }, true); + config.OnValueChanged(CCVars.AdminOverlayAntagFormat, (show) => { _overlayFormat = UpdateOverlayFormat(show); }, true); + config.OnValueChanged(CCVars.AdminOverlaySymbolStyle, (show) => { _overlaySymbolStyle = UpdateOverlaySymbolStyle(show); }, true); config.OnValueChanged(CCVars.AdminOverlayPlaytime, (show) => { _overlayPlaytime = show; }, true); config.OnValueChanged(CCVars.AdminOverlayStartingJob, (show) => { _overlayStartingJob = show; }, true); config.OnValueChanged(CCVars.AdminOverlayGhostHideDistance, (f) => { _ghostHideDistance = f; }, true); @@ -67,6 +72,22 @@ internal sealed class AdminNameOverlay : Overlay config.OnValueChanged(CCVars.AdminOverlayMergeDistance, (f) => { _overlayMergeDistance = f; }, true); } + private AdminOverlayAntagFormat UpdateOverlayFormat(string formatString) + { + if (!Enum.TryParse(formatString, out var format)) + format = AdminOverlayAntagFormat.Binary; + + return format; + } + + private AdminOverlayAntagSymbolStyle UpdateOverlaySymbolStyle(string symbolString) + { + if (!Enum.TryParse(symbolString, out var symbolStyle)) + symbolStyle = AdminOverlayAntagSymbolStyle.Off; + + return symbolStyle; + } + public override OverlaySpace Space => OverlaySpace.ScreenSpace; protected override void Draw(in OverlayDrawArgs args) @@ -183,34 +204,56 @@ internal sealed class AdminNameOverlay : Overlay currentOffset += lineoffset; } - // Classic Antag Label - if (_overlayClassic && playerInfo.Antag) + // Determine antag symbol + string? symbol; + switch (_overlaySymbolStyle) { - var symbol = _overlaySymbols ? Loc.GetString("player-tab-antag-prefix") : string.Empty; - var label = _overlaySymbols - ? Loc.GetString("player-tab-character-name-antag-symbol", - ("symbol", symbol), - ("name", _antagLabelClassic)) - : _antagLabelClassic; - color = Color.OrangeRed; - color.A = alpha; - args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color); - currentOffset += lineoffset; + case AdminOverlayAntagSymbolStyle.Specific: + symbol = playerInfo.RoleProto.Symbol; + break; + case AdminOverlayAntagSymbolStyle.Basic: + symbol = Loc.GetString("player-tab-antag-prefix"); + break; + default: + case AdminOverlayAntagSymbolStyle.Off: + symbol = string.Empty; + break; } - // Role Type - else if (!_overlayClassic && _filter.Contains(playerInfo.RoleProto)) + + // Determine antag/role type name + string? text; + switch (_overlayFormat) { - var symbol = _overlaySymbols && playerInfo.Antag ? playerInfo.RoleProto.Symbol : string.Empty; - var role = Loc.GetString(playerInfo.RoleProto.Name).ToUpper(); - var label = _overlaySymbols - ? Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", role)) - : role; - color = playerInfo.RoleProto.Color; - color.A = alpha; - args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color); - currentOffset += lineoffset; + case AdminOverlayAntagFormat.Roletype: + color = playerInfo.RoleProto.Color; + symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty; + text = _filter.Contains(playerInfo.RoleProto) + ? Loc.GetString(playerInfo.RoleProto.Name).ToUpper() + : string.Empty; + break; + case AdminOverlayAntagFormat.Subtype: + color = playerInfo.RoleProto.Color; + symbol = _filter.Contains(playerInfo.RoleProto) ? symbol : string.Empty; + text = _filter.Contains(playerInfo.RoleProto) + ? _roles.GetRoleSubtypeLabel(playerInfo.RoleProto.Name, playerInfo.Subtype).ToUpper() + : string.Empty; + break; + default: + case AdminOverlayAntagFormat.Binary: + color = Color.OrangeRed; + symbol = playerInfo.Antag ? symbol : string.Empty; + text = playerInfo.Antag ? _antagLabelClassic : string.Empty; + break; } + // Draw antag label + color.A = alpha; + var label = !string.IsNullOrEmpty(symbol) + ? Loc.GetString("player-tab-character-name-antag-symbol", ("symbol", symbol), ("name", text)) + : text; + args.ScreenHandle.DrawString(_fontBold, screenCoordinates + currentOffset, label, uiScale, color); + currentOffset += lineoffset; + //Save the coordinates and size of the text block, for stack merge check drawnOverlays.Add((screenCoordinatesCenter, currentOffset)); } diff --git a/Content.Client/Administration/OverlayOptions.cs b/Content.Client/Administration/OverlayOptions.cs new file mode 100644 index 0000000000..39195603bf --- /dev/null +++ b/Content.Client/Administration/OverlayOptions.cs @@ -0,0 +1,15 @@ +namespace Content.Client.Administration; + +public enum AdminOverlayAntagFormat +{ + Binary, + Roletype, + Subtype +} + +public enum AdminOverlayAntagSymbolStyle +{ + Off, + Basic, + Specific +} diff --git a/Content.Client/Administration/Systems/AdminSystem.Overlay.cs b/Content.Client/Administration/Systems/AdminSystem.Overlay.cs index ba56f4694f..a630df4521 100644 --- a/Content.Client/Administration/Systems/AdminSystem.Overlay.cs +++ b/Content.Client/Administration/Systems/AdminSystem.Overlay.cs @@ -1,4 +1,5 @@ using Content.Client.Administration.Managers; +using Content.Shared.Roles; using Robust.Client.Graphics; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface; @@ -15,6 +16,7 @@ namespace Content.Client.Administration.Systems [Dependency] private readonly EntityLookupSystem _entityLookup = default!; [Dependency] private readonly IUserInterfaceManager _userInterfaceManager = default!; [Dependency] private readonly IConfigurationManager _configurationManager = default!; + [Dependency] private readonly SharedRoleSystem _roles = default!; private AdminNameOverlay _adminNameOverlay = default!; @@ -30,7 +32,8 @@ namespace Content.Client.Administration.Systems _resourceCache, _entityLookup, _userInterfaceManager, - _configurationManager); + _configurationManager, + _roles); _adminManager.AdminStatusUpdated += OnAdminStatusUpdated; } @@ -46,7 +49,8 @@ namespace Content.Client.Administration.Systems public void AdminOverlayOn() { - if (_overlayManager.HasOverlay()) return; + if (_overlayManager.HasOverlay()) + return; _overlayManager.AddOverlay(_adminNameOverlay); OverlayEnabled?.Invoke(); } diff --git a/Content.Client/Administration/Systems/AdminVerbSystem.cs b/Content.Client/Administration/Systems/AdminVerbSystem.cs index dced59bbf2..1e15186706 100644 --- a/Content.Client/Administration/Systems/AdminVerbSystem.cs +++ b/Content.Client/Administration/Systems/AdminVerbSystem.cs @@ -32,7 +32,7 @@ namespace Content.Client.Administration.Systems var verb = new VvVerb() { Text = Loc.GetString("view-variables"), - Icon = new SpriteSpecifier.Texture(new ("/Textures/Interface/VerbIcons/vv.svg.192dpi.png")), + Icon = new SpriteSpecifier.Texture(new("/Textures/Interface/VerbIcons/vv.svg.192dpi.png")), Act = () => _clientConsoleHost.ExecuteCommand($"vv {GetNetEntity(args.Target)}"), ClientExclusive = true // opening VV window is client-side. Don't ask server to run this verb. }; diff --git a/Content.Client/Administration/UI/AdminUIHelpers.cs b/Content.Client/Administration/UI/AdminUIHelpers.cs deleted file mode 100644 index 89ab33e931..0000000000 --- a/Content.Client/Administration/UI/AdminUIHelpers.cs +++ /dev/null @@ -1,59 +0,0 @@ -using System.Threading; -using Content.Client.Stylesheets; -using Robust.Client.UserInterface.Controls; -using Timer = Robust.Shared.Timing.Timer; - -namespace Content.Client.Administration.UI; - -public static class AdminUIHelpers -{ - private static void ResetButton(Button button, ConfirmationData data) - { - data.Cancellation.Cancel(); - button.ModulateSelfOverride = null; - button.Text = data.OriginalText; - } - - public static bool RemoveConfirm(Button button, Dictionary confirmations) - { - if (confirmations.Remove(button, out var data)) - { - ResetButton(button, data); - return true; - } - - return false; - } - - public static void RemoveAllConfirms(Dictionary confirmations) - { - foreach (var (button, confirmation) in confirmations) - { - ResetButton(button, confirmation); - } - - confirmations.Clear(); - } - - public static bool TryConfirm(Button button, Dictionary confirmations) - { - if (RemoveConfirm(button, confirmations)) - return true; - - var data = new ConfirmationData(new CancellationTokenSource(), button.Text); - confirmations[button] = data; - - Timer.Spawn(TimeSpan.FromSeconds(5), () => - { - confirmations.Remove(button); - button.ModulateSelfOverride = null; - button.Text = data.OriginalText; - }, data.Cancellation.Token); - - button.ModulateSelfOverride = StyleNano.ButtonColorCautionDefault; - button.Text = Loc.GetString("admin-player-actions-confirm"); - return false; - } -} - -public readonly record struct ConfirmationData(CancellationTokenSource Cancellation, string? OriginalText); diff --git a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml index d53101f68e..2c27fdd2ce 100644 --- a/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml +++ b/Content.Client/Administration/UI/Bwoink/BwoinkControl.xaml @@ -1,6 +1,7 @@  + xmlns:cc="clr-namespace:Content.Client.Administration.UI.CustomControls" + xmlns:controls="clr-namespace:Content.Client.UserInterface.Controls"> @@ -18,9 +19,9 @@ - - - - - - - - + + + + + + + - - + + + + + + + + + + + + + + + + + - - - - + + + + + + + +