using Content.Client.Stylesheets; using Content.Client.UserInterface.Controls; using Content.Shared.Access; using Content.Shared.Access.Systems; using Content.Shared.TurretController; using Content.Shared.Turrets; using Robust.Client.AutoGenerated; using Robust.Client.Player; using Robust.Client.ResourceManagement; using Robust.Client.UserInterface.Controls; using Robust.Client.UserInterface.CustomControls; using Robust.Client.UserInterface.XAML; using Robust.Shared.Prototypes; using System.Numerics; namespace Content.Client.TurretController; [GenerateTypedNameReferences] public sealed partial class TurretControllerWindow : BaseWindow { [Dependency] private readonly IEntityManager _entManager = default!; [Dependency] private readonly IPlayerManager _playerManager = default!; [Dependency] private readonly IResourceCache _cache = default!; private readonly AccessReaderSystem _accessReaderSystem; private EntityUid? _owner; // Button groups private readonly ButtonGroup _armamentButtons = new(); // Events public event Action>, bool>? OnAccessLevelsChangedEvent; public event Action? OnArmamentSettingChangedEvent; // Colors private static readonly Dictionary ThemeColors = new() { [TurretArmamentSetting.Safe] = Color.FromHex("#33e633"), [TurretArmamentSetting.Stun] = Color.FromHex("#dfb827"), [TurretArmamentSetting.Lethal] = Color.FromHex("#da2a2a") }; public TurretControllerWindow() { RobustXamlLoader.Load(this); IoCManager.InjectDependencies(this); _accessReaderSystem = _entManager.System(); CloseButton.OnPressed += _ => Close(); // Set up armament buttons SafeButton.OnToggled += args => OnArmamentButtonPressed(SafeButton, TurretArmamentSetting.Safe); StunButton.OnToggled += args => OnArmamentButtonPressed(StunButton, TurretArmamentSetting.Stun); LethalButton.OnToggled += args => OnArmamentButtonPressed(LethalButton, TurretArmamentSetting.Lethal); SafeButton.Group = _armamentButtons; StunButton.Group = _armamentButtons; LethalButton.Group = _armamentButtons; SafeButton.Label.AddStyleClass("ConsoleText"); StunButton.Label.AddStyleClass("ConsoleText"); LethalButton.Label.AddStyleClass("ConsoleText"); // Set up access configuration buttons AccessConfiguration.SetMonotone(true); AccessConfiguration.SetLabelStyleClass("ConsoleText"); AccessConfiguration.OnAccessLevelsChangedEvent += OnAccessLevelsChanged; // Override footer font var smallFont = _cache.NotoStack(size: 8); Footer.FontOverride = smallFont; } private void OnAccessLevelsChanged(HashSet> accessLevels, bool isPressed) { OnAccessLevelsChangedEvent?.Invoke(accessLevels, isPressed); } private void OnArmamentButtonPressed(MonotoneButton pressedButton, TurretArmamentSetting setting) { UpdateTheme(setting); OnArmamentSettingChangedEvent?.Invoke(setting); } private void Initialize() { RefreshLinkedTurrets(new()); if (_entManager.TryGetComponent(_owner, out var turretController)) { AccessConfiguration.SetAccessGroups(turretController.AccessGroups); AccessConfiguration.SetAccessLevels(turretController.AccessLevels); UpdateTheme((TurretArmamentSetting)turretController.ArmamentState); } if (_entManager.TryGetComponent(_owner, out var turretTargetSettings)) { RefreshAccessControls(turretTargetSettings.ExemptAccessLevels); } } public void SetOwner(EntityUid owner) { _owner = owner; Initialize(); } private void UpdateTheme(TurretArmamentSetting setting) { var setPressedOn = setting switch { TurretArmamentSetting.Safe => SafeButton, TurretArmamentSetting.Stun => StunButton, TurretArmamentSetting.Lethal => LethalButton, _ => throw new NotImplementedException(), }; setPressedOn.Pressed = true; var canInteract = IsLocalPlayerAllowedToInteract(); SafeButton.Disabled = !SafeButton.Pressed && !canInteract; StunButton.Disabled = !StunButton.Pressed && !canInteract; LethalButton.Disabled = !LethalButton.Pressed && !canInteract; ContentsContainer.Modulate = ThemeColors[setting]; } public void UpdateState(DeployableTurretControllerBoundInterfaceState state) { if (_entManager.TryGetComponent(_owner, out var turretController)) UpdateTheme((TurretArmamentSetting)turretController.ArmamentState); if (_entManager.TryGetComponent(_owner, out var turretTargetSettings)) RefreshAccessControls(turretTargetSettings.ExemptAccessLevels); RefreshLinkedTurrets(state.TurretStateByAddress); } public void RefreshLinkedTurrets(Dictionary turretStates) { var turretCount = turretStates.Count; var hasTurrets = turretCount > 0; NoLinkedTurretsText.Visible = !hasTurrets; LinkedTurretsContainer.Visible = hasTurrets; LinkedTurretsContainer.RemoveAllChildren(); foreach (var (address, state) in turretStates) { var text = Loc.GetString( "turret-controls-window-turret-status", ("device", address), ("status", Loc.GetString(state)) ); var label = new Label { Text = text, HorizontalAlignment = HAlignment.Left, Margin = new Thickness(10f, 0f, 10f, 0f), HorizontalExpand = true, SetHeight = 20f, }; label.AddStyleClass("ConsoleText"); LinkedTurretsContainer.AddChild(label); } TurretStatusHeader.Text = Loc.GetString("turret-controls-window-turret-status-label", ("count", turretCount)); } public void RefreshAccessControls(HashSet> exemptAccessLevels) { AccessConfiguration.SetActiveAccessLevels(exemptAccessLevels); AccessConfiguration.SetLocalPlayerAccessibility(IsLocalPlayerAllowedToInteract()); } protected override DragMode GetDragModeFor(Vector2 relativeMousePos) { return DragMode.Move; } private bool IsLocalPlayerAllowedToInteract() { if (_owner == null || _playerManager.LocalSession?.AttachedEntity == null) return false; return _accessReaderSystem.IsAllowed(_playerManager.LocalSession.AttachedEntity.Value, _owner.Value); } public enum TurretArmamentSetting { Safe = -1, Stun = 0, Lethal = 1, } }