Merge branch 'master' into ed-17-07-2024-dungenagain

This commit is contained in:
Ed
2024-08-05 23:08:01 +03:00
committed by GitHub
1423 changed files with 219353 additions and 54715 deletions

14
.github/FUNDING.yml vendored Normal file
View File

@@ -0,0 +1,14 @@
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
custom: ['https://boosty.to/theshued']

View File

@@ -7,11 +7,11 @@
<!-- Зачем нужно это изменение? Прикрепите любые обсуждения или проблемы здесь. Опишите, как это повлияет на текущий баланс игры. -->
## Media
<!--
<!--
PRs which make ingame changes (adding clothing, items, new features, etc) are required to have media attached that showcase the changes.
Small fixes/refactors are exempt.
-->
<!--
<!--
Пулл реквесты, которые несут за собой игровые изменения (добавления одежды, предметов и так далее) требуют чтобы вы прикрепили скриншоты или видеоролики, демонстрирующие эти изменения.
Небольшие исправления не считаются.
-->

4
.github/labeler.yml vendored
View File

@@ -12,6 +12,10 @@
- changed-files:
- any-glob-to-any-file: '**/*.xaml*'
"Changes: Shaders":
- changed-files:
- any-glob-to-any-file: '**/*.swsl'
"No C#":
- changed-files:
# Equiv to any-glob-to-all as long as this has one matcher. If ALL changed files are not C# files, then apply label.

View File

@@ -2,6 +2,7 @@ using Content.Shared.Access;
using Content.Shared.Access.Components;
using Content.Shared.Access.Systems;
using Content.Shared.Containers.ItemSlots;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
using static Content.Shared.Access.Components.AccessOverriderComponent;
@@ -23,6 +24,28 @@ namespace Content.Client.Access.UI
{
base.Open();
_window = this.CreateWindow<AccessOverriderWindow>();
RefreshAccess();
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
_window.OnSubmit += SubmitData;
_window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId));
}
public override void OnProtoReload(PrototypesReloadedEventArgs args)
{
base.OnProtoReload(args);
if (!args.WasModified<AccessLevelPrototype>())
return;
RefreshAccess();
if (State != null)
_window?.UpdateState(_prototypeManager, (AccessOverriderBoundUserInterfaceState) State);
}
private void RefreshAccess()
{
List<ProtoId<AccessLevelPrototype>> accessLevels;
if (EntMan.TryGetComponent<AccessOverriderComponent>(Owner, out var accessOverrider))
@@ -30,38 +53,20 @@ namespace Content.Client.Access.UI
accessLevels = accessOverrider.AccessLevels;
accessLevels.Sort();
}
else
{
accessLevels = new List<ProtoId<AccessLevelPrototype>>();
_accessOverriderSystem.Log.Error($"No AccessOverrider component found for {EntMan.ToPrettyString(Owner)}!");
}
_window = new AccessOverriderWindow(this, _prototypeManager, accessLevels)
{
Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName
};
_window.PrivilegedIdButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(PrivilegedIdCardSlotId));
_window.OnClose += Close;
_window.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
_window?.SetAccessLevels(_prototypeManager, accessLevels);
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
var castState = (AccessOverriderBoundUserInterfaceState) state;
_window?.UpdateState(castState);
_window?.UpdateState(_prototypeManager, castState);
}
public void SubmitData(List<ProtoId<AccessLevelPrototype>> newAccessList)

View File

@@ -13,26 +13,24 @@ namespace Content.Client.Access.UI
[GenerateTypedNameReferences]
public sealed partial class AccessOverriderWindow : DefaultWindow
{
[Dependency] private readonly ILogManager _logManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly AccessOverriderBoundUserInterface _owner;
private readonly Dictionary<string, Button> _accessButtons = new();
public AccessOverriderWindow(AccessOverriderBoundUserInterface owner, IPrototypeManager prototypeManager,
List<ProtoId<AccessLevelPrototype>> accessLevels)
public event Action<List<ProtoId<AccessLevelPrototype>>>? OnSubmit;
public AccessOverriderWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
var logMill = _logManager.GetSawmill(SharedAccessOverriderSystem.Sawmill);
}
_owner = owner;
public void SetAccessLevels(IPrototypeManager protoManager, List<ProtoId<AccessLevelPrototype>> accessLevels)
{
_accessButtons.Clear();
AccessLevelGrid.DisposeAllChildren();
foreach (var access in accessLevels)
{
if (!prototypeManager.TryIndex(access, out var accessLevel))
if (!protoManager.TryIndex(access, out var accessLevel))
{
logMill.Error($"Unable to find accesslevel for {access}");
continue;
}
@@ -44,11 +42,16 @@ namespace Content.Client.Access.UI
AccessLevelGrid.AddChild(newButton);
_accessButtons.Add(accessLevel.ID, newButton);
newButton.OnPressed += _ => SubmitData();
newButton.OnPressed += _ =>
{
OnSubmit?.Invoke(
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
_accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId<AccessLevelPrototype>(x.Key)).ToList());
};
}
}
public void UpdateState(AccessOverriderBoundUserInterfaceState state)
public void UpdateState(IPrototypeManager protoManager, AccessOverriderBoundUserInterfaceState state)
{
PrivilegedIdLabel.Text = state.PrivilegedIdName;
PrivilegedIdButton.Text = state.IsPrivilegedIdPresent
@@ -66,11 +69,11 @@ namespace Content.Client.Access.UI
if (state.MissingPrivilegesList != null && state.MissingPrivilegesList.Any())
{
List<string> missingPrivileges = new List<string>();
var missingPrivileges = new List<string>();
foreach (string tag in state.MissingPrivilegesList)
{
string privilege = Loc.GetString(_prototypeManager.Index<AccessLevelPrototype>(tag)?.Name ?? "generic-unknown");
var privilege = Loc.GetString(protoManager.Index<AccessLevelPrototype>(tag)?.Name ?? "generic-unknown");
missingPrivileges.Add(privilege);
}
@@ -90,13 +93,5 @@ namespace Content.Client.Access.UI
}
}
}
private void SubmitData()
{
_owner.SubmitData(
// Iterate over the buttons dictionary, filter by `Pressed`, only get key from the key/value pair
_accessButtons.Where(x => x.Value.Pressed).Select(x => new ProtoId<AccessLevelPrototype>(x.Key)).ToList());
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Access.Systems;
using Content.Shared.StatusIcon;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Access.UI
@@ -20,16 +21,11 @@ namespace Content.Client.Access.UI
{
base.Open();
_window?.Dispose();
_window = new AgentIDCardWindow(this);
if (State != null)
UpdateState(State);
_window = this.CreateWindow<AgentIDCardWindow>();
_window.OpenCentered();
_window.OnClose += Close;
_window.OnNameChanged += OnNameChanged;
_window.OnJobChanged += OnJobChanged;
_window.OnJobIconChanged += OnJobIconChanged;
}
private void OnNameChanged(string newName)
@@ -61,14 +57,5 @@ namespace Content.Client.Access.UI
_window.SetCurrentJob(cast.CurrentJob);
_window.SetAllowedIcons(cast.Icons, cast.CurrentJobIconId);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
}
}
}

View File

@@ -17,19 +17,19 @@ namespace Content.Client.Access.UI
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[Dependency] private readonly IEntitySystemManager _entitySystem = default!;
private readonly SpriteSystem _spriteSystem;
private readonly AgentIDCardBoundUserInterface _bui;
private const int JobIconColumnCount = 10;
public event Action<string>? OnNameChanged;
public event Action<string>? OnJobChanged;
public AgentIDCardWindow(AgentIDCardBoundUserInterface bui)
public event Action<ProtoId<StatusIconPrototype>>? OnJobIconChanged;
public AgentIDCardWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_spriteSystem = _entitySystem.GetEntitySystem<SpriteSystem>();
_bui = bui;
NameLineEdit.OnTextEntered += e => OnNameChanged?.Invoke(e.Text);
NameLineEdit.OnFocusExit += e => OnNameChanged?.Invoke(e.Text);
@@ -67,7 +67,7 @@ namespace Content.Client.Access.UI
};
// Generate buttons textures
TextureRect jobIconTexture = new TextureRect
var jobIconTexture = new TextureRect
{
Texture = _spriteSystem.Frame0(jobIcon.Icon),
TextureScale = new Vector2(2.5f, 2.5f),
@@ -75,7 +75,7 @@ namespace Content.Client.Access.UI
};
jobIconButton.AddChild(jobIconTexture);
jobIconButton.OnPressed += _ => _bui.OnJobIconChanged(jobIconId);
jobIconButton.OnPressed += _ => OnJobIconChanged?.Invoke(jobIcon.ID);
IconGrid.AddChild(jobIconButton);
if (jobIconId.Equals(currentJobIconId))

View File

@@ -107,7 +107,7 @@ namespace Content.Client.Actions
UpdateAction(uid, component);
}
protected override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
public override void UpdateAction(EntityUid? actionId, BaseActionComponent? action = null)
{
if (!ResolveActionData(actionId, ref action))
return;

View File

@@ -1,5 +1,6 @@
using Content.Shared.Ame.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Ame.UI
{
@@ -16,9 +17,8 @@ namespace Content.Client.Ame.UI
{
base.Open();
_window = new AmeWindow(this);
_window.OnClose += Close;
_window.OpenCentered();
_window = this.CreateWindow<AmeWindow>();
_window.OnAmeButton += ButtonPressed;
}
/// <summary>
@@ -40,15 +40,5 @@ namespace Content.Client.Ame.UI
{
SendMessage(new UiButtonPressedMessage(button));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Linq;
using Content.Client.UserInterface;
using Content.Shared.Ame.Components;
using Robust.Client.AutoGenerated;
@@ -9,15 +10,17 @@ namespace Content.Client.Ame.UI
[GenerateTypedNameReferences]
public sealed partial class AmeWindow : DefaultWindow
{
public AmeWindow(AmeControllerBoundUserInterface ui)
public event Action<UiButton>? OnAmeButton;
public AmeWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
EjectButton.OnPressed += _ => ui.ButtonPressed(UiButton.Eject);
ToggleInjection.OnPressed += _ => ui.ButtonPressed(UiButton.ToggleInjection);
IncreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.IncreaseFuel);
DecreaseFuelButton.OnPressed += _ => ui.ButtonPressed(UiButton.DecreaseFuel);
EjectButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.Eject);
ToggleInjection.OnPressed += _ => OnAmeButton?.Invoke(UiButton.ToggleInjection);
IncreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.IncreaseFuel);
DecreaseFuelButton.OnPressed += _ => OnAmeButton?.Invoke(UiButton.DecreaseFuel);
}
/// <summary>
@@ -29,7 +32,7 @@ namespace Content.Client.Ame.UI
var castState = (AmeControllerBoundUserInterfaceState) state;
// Disable all buttons if not powered
if (Contents.Children != null)
if (Contents.Children.Any())
{
ButtonHelpers.SetButtonDisabledRecursive(Contents, !castState.HasPower);
EjectButton.Disabled = false;
@@ -65,8 +68,8 @@ namespace Content.Client.Ame.UI
CoreCount.Text = $"{castState.CoreCount}";
InjectionAmount.Text = $"{castState.InjectionAmount}";
// format power statistics to pretty numbers
CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply.ToString("N1")}";
TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply.ToString("N1")}";
CurrentPowerSupply.Text = $"{castState.CurrentPowerSupply:N1}";
TargetedPowerSupply.Text = $"{castState.TargetedPowerSupply:N1}";
}
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared.Anomaly;
using Content.Shared.Gravity;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Anomaly.Ui;
@@ -18,10 +19,8 @@ public sealed class AnomalyGeneratorBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new(Owner);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<AnomalyGeneratorWindow>();
_window.SetEntity(Owner);
_window.OnGenerateButtonPressed += () =>
{
@@ -37,18 +36,5 @@ public sealed class AnomalyGeneratorBoundUserInterface : BoundUserInterface
return;
_window?.UpdateState(msg);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
public void SetPowerSwitch(bool on)
{
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on));
}
}

View File

@@ -18,17 +18,21 @@ public sealed partial class AnomalyGeneratorWindow : FancyWindow
public Action? OnGenerateButtonPressed;
public AnomalyGeneratorWindow(EntityUid gen)
public AnomalyGeneratorWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
EntityView.SetEntity(gen);
EntityView.SpriteOffset = false;
GenerateButton.OnPressed += _ => OnGenerateButtonPressed?.Invoke();
}
public void SetEntity(EntityUid uid)
{
EntityView.SetEntity(uid);
}
public void UpdateState(AnomalyGeneratorUserInterfaceState state)
{
_cooldownEnd = state.CooldownEndTime;

View File

@@ -28,8 +28,6 @@ namespace Content.Client.Arcade
private static readonly Vector2 BlockSize = new(15, 15);
private readonly BlockGameBoundUserInterface _owner;
private readonly PanelContainer _mainPanel;
private readonly BoxContainer _gameRootContainer;
@@ -58,10 +56,11 @@ namespace Content.Client.Arcade
private bool _isPlayer = false;
private bool _gameOver = false;
public BlockGameMenu(BlockGameBoundUserInterface owner)
public event Action<BlockGamePlayerAction>? OnAction;
public BlockGameMenu()
{
Title = Loc.GetString("blockgame-menu-title");
_owner = owner;
MinSize = SetSize = new Vector2(410, 490);
@@ -176,7 +175,7 @@ namespace Content.Client.Arcade
};
_newGameButton.OnPressed += (e) =>
{
_owner.SendAction(BlockGamePlayerAction.NewGame);
OnAction?.Invoke(BlockGamePlayerAction.NewGame);
};
pauseMenuContainer.AddChild(_newGameButton);
pauseMenuContainer.AddChild(new Control { MinSize = new Vector2(1, 10) });
@@ -186,7 +185,10 @@ namespace Content.Client.Arcade
Text = Loc.GetString("blockgame-menu-button-scoreboard"),
TextAlign = Label.AlignMode.Center
};
_scoreBoardButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.ShowHighscores);
_scoreBoardButton.OnPressed += (e) =>
{
OnAction?.Invoke(BlockGamePlayerAction.ShowHighscores);
};
pauseMenuContainer.AddChild(_scoreBoardButton);
_unpauseButtonMargin = new Control { MinSize = new Vector2(1, 10), Visible = false };
pauseMenuContainer.AddChild(_unpauseButtonMargin);
@@ -199,7 +201,7 @@ namespace Content.Client.Arcade
};
_unpauseButton.OnPressed += (e) =>
{
_owner.SendAction(BlockGamePlayerAction.Unpause);
OnAction?.Invoke(BlockGamePlayerAction.Unpause);
};
pauseMenuContainer.AddChild(_unpauseButton);
@@ -257,7 +259,7 @@ namespace Content.Client.Arcade
};
_finalNewGameButton.OnPressed += (e) =>
{
_owner.SendAction(BlockGamePlayerAction.NewGame);
OnAction?.Invoke(BlockGamePlayerAction.NewGame);
};
gameOverMenuContainer.AddChild(_finalNewGameButton);
@@ -327,7 +329,10 @@ namespace Content.Client.Arcade
Text = Loc.GetString("blockgame-menu-button-back"),
TextAlign = Label.AlignMode.Center
};
_highscoreBackButton.OnPressed += (e) => _owner.SendAction(BlockGamePlayerAction.Pause);
_highscoreBackButton.OnPressed += (e) =>
{
OnAction?.Invoke(BlockGamePlayerAction.Pause);
};
menuContainer.AddChild(_highscoreBackButton);
menuInnerPanel.AddChild(menuContainer);
@@ -375,7 +380,7 @@ namespace Content.Client.Arcade
{
PanelOverride = back,
HorizontalExpand = true,
SizeFlagsStretchRatio = 60
SizeFlagsStretchRatio = 34.25f
};
var backgroundPanel = new PanelContainer
{
@@ -473,7 +478,7 @@ namespace Content.Client.Arcade
private void TryPause()
{
_owner.SendAction(BlockGamePlayerAction.Pause);
OnAction?.Invoke(BlockGamePlayerAction.Pause);
}
public void SetStarted()
@@ -576,19 +581,19 @@ namespace Content.Client.Arcade
return;
else if (args.Function == ContentKeyFunctions.ArcadeLeft)
_owner.SendAction(BlockGamePlayerAction.StartLeft);
OnAction?.Invoke(BlockGamePlayerAction.StartLeft);
else if (args.Function == ContentKeyFunctions.ArcadeRight)
_owner.SendAction(BlockGamePlayerAction.StartRight);
OnAction?.Invoke(BlockGamePlayerAction.StartRight);
else if (args.Function == ContentKeyFunctions.ArcadeUp)
_owner.SendAction(BlockGamePlayerAction.Rotate);
OnAction?.Invoke(BlockGamePlayerAction.Rotate);
else if (args.Function == ContentKeyFunctions.Arcade3)
_owner.SendAction(BlockGamePlayerAction.CounterRotate);
OnAction?.Invoke(BlockGamePlayerAction.CounterRotate);
else if (args.Function == ContentKeyFunctions.ArcadeDown)
_owner.SendAction(BlockGamePlayerAction.SoftdropStart);
OnAction?.Invoke(BlockGamePlayerAction.SoftdropStart);
else if (args.Function == ContentKeyFunctions.Arcade2)
_owner.SendAction(BlockGamePlayerAction.Hold);
OnAction?.Invoke(BlockGamePlayerAction.Hold);
else if (args.Function == ContentKeyFunctions.Arcade1)
_owner.SendAction(BlockGamePlayerAction.Harddrop);
OnAction?.Invoke(BlockGamePlayerAction.Harddrop);
}
protected override void KeyBindUp(GUIBoundKeyEventArgs args)
@@ -599,11 +604,11 @@ namespace Content.Client.Arcade
return;
else if (args.Function == ContentKeyFunctions.ArcadeLeft)
_owner.SendAction(BlockGamePlayerAction.EndLeft);
OnAction?.Invoke(BlockGamePlayerAction.EndLeft);
else if (args.Function == ContentKeyFunctions.ArcadeRight)
_owner.SendAction(BlockGamePlayerAction.EndRight);
OnAction?.Invoke(BlockGamePlayerAction.EndRight);
else if (args.Function == ContentKeyFunctions.ArcadeDown)
_owner.SendAction(BlockGamePlayerAction.SoftdropEnd);
OnAction?.Invoke(BlockGamePlayerAction.SoftdropEnd);
}
public void UpdateNextBlock(BlockGameBlock[] blocks)

View File

@@ -8,8 +8,6 @@ namespace Content.Client.Arcade
{
public sealed class SpaceVillainArcadeMenu : DefaultWindow
{
public SpaceVillainArcadeBoundUserInterface Owner { get; set; }
private readonly Label _enemyNameLabel;
private readonly Label _playerInfoLabel;
private readonly Label _enemyInfoLabel;
@@ -17,11 +15,13 @@ namespace Content.Client.Arcade
private readonly Label _enemyActionLabel;
private readonly Button[] _gameButtons = new Button[3]; //used to disable/enable all game buttons
public SpaceVillainArcadeMenu(SpaceVillainArcadeBoundUserInterface owner)
public event Action<SharedSpaceVillainArcadeComponent.PlayerAction>? OnPlayerAction;
public SpaceVillainArcadeMenu()
{
MinSize = SetSize = new Vector2(300, 225);
Title = Loc.GetString("spacevillain-menu-title");
Owner = owner;
var grid = new GridContainer { Columns = 1 };
@@ -47,32 +47,43 @@ namespace Content.Client.Arcade
grid.AddChild(_enemyActionLabel);
var buttonGrid = new GridContainer { Columns = 3 };
_gameButtons[0] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Attack)
_gameButtons[0] = new Button()
{
Text = Loc.GetString("spacevillain-menu-button-attack")
};
_gameButtons[0].OnPressed +=
_ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Attack);
buttonGrid.AddChild(_gameButtons[0]);
_gameButtons[1] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Heal)
_gameButtons[1] = new Button()
{
Text = Loc.GetString("spacevillain-menu-button-heal")
};
_gameButtons[1].OnPressed +=
_ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Heal);
buttonGrid.AddChild(_gameButtons[1]);
_gameButtons[2] = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.Recharge)
_gameButtons[2] = new Button()
{
Text = Loc.GetString("spacevillain-menu-button-recharge")
};
_gameButtons[2].OnPressed +=
_ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.Recharge);
buttonGrid.AddChild(_gameButtons[2]);
centerContainer = new CenterContainer();
centerContainer.AddChild(buttonGrid);
grid.AddChild(centerContainer);
var newGame = new ActionButton(Owner, SharedSpaceVillainArcadeComponent.PlayerAction.NewGame)
var newGame = new Button()
{
Text = Loc.GetString("spacevillain-menu-button-new-game")
};
newGame.OnPressed += _ => OnPlayerAction?.Invoke(SharedSpaceVillainArcadeComponent.PlayerAction.NewGame);
grid.AddChild(newGame);
Contents.AddChild(grid);
@@ -99,23 +110,5 @@ namespace Content.Client.Arcade
_playerActionLabel.Text = message.PlayerActionMessage;
_enemyActionLabel.Text = message.EnemyActionMessage;
}
private sealed class ActionButton : Button
{
private readonly SpaceVillainArcadeBoundUserInterface _owner;
private readonly SharedSpaceVillainArcadeComponent.PlayerAction _playerAction;
public ActionButton(SpaceVillainArcadeBoundUserInterface owner, SharedSpaceVillainArcadeComponent.PlayerAction playerAction)
{
_owner = owner;
_playerAction = playerAction;
OnPressed += Clicked;
}
private void Clicked(ButtonEventArgs e)
{
_owner.SendAction(_playerAction);
}
}
}
}

View File

@@ -1,5 +1,6 @@
using Content.Shared.Arcade;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Arcade.UI;
@@ -15,9 +16,8 @@ public sealed class BlockGameBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new BlockGameMenu(this);
_menu.OnClose += Close;
_menu.OpenCentered();
_menu = this.CreateWindow<BlockGameMenu>();
_menu.OnAction += SendAction;
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)

View File

@@ -1,4 +1,5 @@
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
using Robust.Shared.ViewVariables;
using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent;
@@ -9,8 +10,6 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface
{
[ViewVariables] private SpaceVillainArcadeMenu? _menu;
//public SharedSpaceVillainArcadeComponent SpaceVillainArcade;
public SpaceVillainArcadeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
SendAction(PlayerAction.RequestData);
@@ -25,10 +24,8 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new SpaceVillainArcadeMenu(this);
_menu.OnClose += Close;
_menu.OpenCentered();
_menu = this.CreateWindow<SpaceVillainArcadeMenu>();
_menu.OnPlayerAction += SendAction;
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
@@ -36,12 +33,4 @@ public sealed class SpaceVillainArcadeBoundUserInterface : BoundUserInterface
if (message is SpaceVillainArcadeDataUpdateMessage msg)
_menu?.UpdateInfo(msg);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_menu?.Dispose();
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared.Atmos;
using Content.Shared.Atmos.Monitor;
using Content.Shared.Atmos.Monitor.Components;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.GameObjects;
using Robust.Shared.IoC;
using Robust.Shared.Log;
@@ -20,16 +21,9 @@ public sealed class AirAlarmBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new AirAlarmWindow(this);
_window = this.CreateWindow<AirAlarmWindow>();
_window.SetEntity(Owner);
if (State != null)
{
UpdateState(State);
}
_window.OpenCentered();
_window.OnClose += Close;
_window.AtmosDeviceDataChanged += OnDeviceDataChanged;
_window.AtmosDeviceDataCopied += OnDeviceDataCopied;
_window.AtmosAlarmThresholdChanged += OnThresholdChanged;

View File

@@ -47,7 +47,7 @@ public sealed partial class AirAlarmWindow : FancyWindow
private CheckBox _autoMode => AutoModeCheckBox;
public AirAlarmWindow(BoundUserInterface owner)
public AirAlarmWindow()
{
RobustXamlLoader.Load(this);
@@ -95,8 +95,11 @@ public sealed partial class AirAlarmWindow : FancyWindow
_sensors.Clear();
ResyncAllRequested!.Invoke();
};
}
EntityView.SetEntity(owner.Owner);
public void SetEntity(EntityUid uid)
{
EntityView.SetEntity(uid);
}
public void UpdateState(AirAlarmUIState state)

View File

@@ -1,6 +1,7 @@
using Content.Shared.Atmos.Piping.Binary.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -21,14 +22,8 @@ namespace Content.Client.Atmos.UI
{
base.Open();
_window = new GasCanisterWindow();
_window = this.CreateWindow<GasCanisterWindow>();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window.ReleaseValveCloseButtonPressed += OnReleaseValveClosePressed;
_window.ReleaseValveOpenButtonPressed += OnReleaseValveOpenPressed;
_window.ReleasePressureSet += OnReleasePressureSet;

View File

@@ -3,6 +3,7 @@ using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Trinary.Components;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -28,14 +29,8 @@ namespace Content.Client.Atmos.UI
var atmosSystem = EntMan.System<AtmosphereSystem>();
_window = new GasFilterWindow(atmosSystem.Gases);
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GasFilterWindow>();
_window.PopulateGasList(atmosSystem.Gases);
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.FilterTransferRateChanged += OnFilterTransferRatePressed;

View File

@@ -26,10 +26,9 @@ namespace Content.Client.Atmos.UI
public event Action<string>? FilterTransferRateChanged;
public event Action? SelectGasPressed;
public GasFilterWindow(IEnumerable<GasPrototype> gases)
public GasFilterWindow()
{
RobustXamlLoader.Load(this);
PopulateGasList(gases);
ToggleStatusButton.OnPressed += _ => SetFilterStatus(!FilterStatus);
ToggleStatusButton.OnPressed += _ => ToggleStatusButtonPressed?.Invoke();
@@ -73,7 +72,7 @@ namespace Content.Client.Atmos.UI
SelectGasButton.Disabled = true;
}
private void PopulateGasList(IEnumerable<GasPrototype> gases)
public void PopulateGasList(IEnumerable<GasPrototype> gases)
{
GasList.Add(new ItemList.Item(GasList)
{
@@ -81,7 +80,7 @@ namespace Content.Client.Atmos.UI
Text = Loc.GetString("comp-gas-filter-ui-filter-gas-none")
});
foreach (GasPrototype gas in gases)
foreach (var gas in gases)
{
var gasName = Loc.GetString(gas.Name);
GasList.Add(GetGasItem(gas.ID, gasName, GasList));

View File

@@ -2,7 +2,7 @@ using Content.Shared.Atmos;
using Content.Shared.Atmos.Piping.Trinary.Components;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -26,14 +26,7 @@ namespace Content.Client.Atmos.UI
{
base.Open();
_window = new GasMixerWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GasMixerWindow>();
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.MixerOutputPressureChanged += OnMixerOutputPressurePressed;
@@ -83,12 +76,5 @@ namespace Content.Client.Atmos.UI
_window.SetOutputPressure(cast.OutputPressure);
_window.SetNodePercentages(cast.NodeOne);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -3,6 +3,7 @@ using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -26,14 +27,7 @@ namespace Content.Client.Atmos.UI
{
base.Open();
_window = new GasPressurePumpWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GasPressurePumpWindow>();
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.PumpOutputPressureChanged += OnPumpOutputPressurePressed;
@@ -67,12 +61,5 @@ namespace Content.Client.Atmos.UI
_window.SetPumpStatus(cast.Enabled);
_window.SetOutputPressure(cast.OutputPressure);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -2,6 +2,7 @@
using Content.Shared.Atmos.Piping.Unary.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -31,14 +32,7 @@ namespace Content.Client.Atmos.UI
{
base.Open();
_window = new GasThermomachineWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GasThermomachineWindow>();
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
_window.TemperatureSpinbox.OnValueChanged += _ => OnTemperatureChanged(_window.TemperatureSpinbox.Value);
@@ -91,12 +85,5 @@ namespace Content.Client.Atmos.UI
true => Loc.GetString("comp-gas-thermomachine-ui-title-heater")
};
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -3,6 +3,7 @@ using Content.Shared.Atmos.Piping.Binary.Components;
using Content.Shared.Localizations;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Atmos.UI
{
@@ -26,14 +27,7 @@ namespace Content.Client.Atmos.UI
{
base.Open();
_window = new GasVolumePumpWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GasVolumePumpWindow>();
_window.ToggleStatusButtonPressed += OnToggleStatusButtonPressed;
_window.PumpTransferRateChanged += OnPumpTransferRatePressed;
@@ -64,16 +58,9 @@ namespace Content.Client.Atmos.UI
if (_window == null || state is not GasVolumePumpBoundUserInterfaceState cast)
return;
_window.Title = (cast.PumpLabel);
_window.Title = cast.PumpLabel;
_window.SetPumpStatus(cast.Enabled);
_window.SetTransferRate(cast.TransferRate);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -1,5 +1,6 @@
using Content.Shared.Atmos.Piping.Portable.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.Atmos.UI;
@@ -21,14 +22,7 @@ public sealed class SpaceHeaterBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new SpaceHeaterWindow();
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<SpaceHeaterWindow>();
_window.ToggleStatusButton.OnPressed += _ => OnToggleStatusButtonPressed();
_window.IncreaseTempRange.OnPressed += _ => OnTemperatureRangeChanged(_window.TemperatureChangeDelta);

View File

@@ -1,8 +1,7 @@
using Content.Shared.Audio.Jukebox;
using Robust.Client.Audio;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Shared.Audio.Components;
using Robust.Shared.Player;
using Robust.Shared.Prototypes;
namespace Content.Client.Audio.Jukebox;
@@ -23,9 +22,7 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new JukeboxMenu();
_menu.OnClose += Close;
_menu.OpenCentered();
_menu = this.CreateWindow<JukeboxMenu>();
_menu.OnPlayPressed += args =>
{
@@ -100,19 +97,5 @@ public sealed class JukeboxBoundUserInterface : BoundUserInterface
SendMessage(new JukeboxSetTimeMessage(sentTime));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_menu == null)
return;
_menu.OnClose -= Close;
_menu.Dispose();
_menu = null;
}
}

View File

@@ -1,5 +1,6 @@
using Content.Shared.Bed.Cryostorage;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Bed.Cryostorage;
@@ -17,9 +18,7 @@ public sealed class CryostorageBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new();
_menu.OnClose += Close;
_menu = this.CreateWindow<CryostorageMenu>();
_menu.SlotRemoveButtonPressed += (ent, slot) =>
{
@@ -30,8 +29,6 @@ public sealed class CryostorageBoundUserInterface : BoundUserInterface
{
SendMessage(new CryostorageRemoveItemBuiMessage(ent, hand, CryostorageRemoveItemBuiMessage.RemovalType.Hand));
};
_menu.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -45,12 +42,4 @@ public sealed class CryostorageBoundUserInterface : BoundUserInterface
break;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}

View File

@@ -1,6 +1,7 @@
using Content.Client.Cargo.UI;
using Content.Shared.Cargo.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Cargo.BUI;
@@ -18,9 +19,7 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new();
_menu.OnClose += Close;
_menu = this.CreateWindow<CargoBountyMenu>();
_menu.OnLabelButtonPressed += id =>
{
@@ -31,8 +30,6 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
{
SendMessage(new BountySkipMessage(id));
};
_menu.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState message)
@@ -44,14 +41,4 @@ public sealed class CargoBountyConsoleBoundUserInterface : BoundUserInterface
_menu?.UpdateEntries(state.Bounties, state.UntilNextSkip);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}

View File

@@ -2,6 +2,7 @@ using Content.Client.Cargo.UI;
using Content.Shared.Cargo.BUI;
using Content.Shared.Cargo.Events;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Cargo.BUI;
@@ -18,21 +19,9 @@ public sealed class CargoPalletConsoleBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new CargoPalletMenu();
_menu = this.CreateWindow<CargoPalletMenu>();
_menu.AppraiseRequested += OnAppraisal;
_menu.SellRequested += OnSell;
_menu.OnClose += Close;
_menu.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_menu?.Dispose();
}
}
private void OnAppraisal()

View File

@@ -2,6 +2,7 @@ using Content.Client.Cargo.UI;
using Content.Shared.Cargo.BUI;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Cargo.BUI;
@@ -9,6 +10,8 @@ namespace Content.Client.Cargo.BUI;
[UsedImplicitly]
public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[ViewVariables]
private CargoShuttleMenu? _menu;
@@ -19,24 +22,7 @@ public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
protected override void Open()
{
base.Open();
var collection = IoCManager.Instance;
if (collection == null)
return;
_menu = new CargoShuttleMenu(collection.Resolve<IPrototypeManager>(), collection.Resolve<IEntitySystemManager>().GetEntitySystem<SpriteSystem>());
_menu.OnClose += Close;
_menu.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_menu?.Dispose();
}
_menu = this.CreateWindow<CargoShuttleMenu>();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -45,6 +31,6 @@ public sealed class CargoShuttleConsoleBoundUserInterface : BoundUserInterface
if (state is not CargoShuttleConsoleBoundUserInterfaceState cargoState) return;
_menu?.SetAccountName(cargoState.AccountName);
_menu?.SetShuttleName(cargoState.ShuttleName);
_menu?.SetOrders(cargoState.Orders);
_menu?.SetOrders(EntMan.System<SpriteSystem>(), _protoManager, cargoState.Orders);
}
}

View File

@@ -12,14 +12,9 @@ namespace Content.Client.Cargo.UI
[GenerateTypedNameReferences]
public sealed partial class CargoShuttleMenu : FancyWindow
{
private readonly IPrototypeManager _protoManager;
private readonly SpriteSystem _spriteSystem;
public CargoShuttleMenu(IPrototypeManager protoManager, SpriteSystem spriteSystem)
public CargoShuttleMenu()
{
RobustXamlLoader.Load(this);
_protoManager = protoManager;
_spriteSystem = spriteSystem;
Title = Loc.GetString("cargo-shuttle-console-menu-title");
}
@@ -33,19 +28,19 @@ namespace Content.Client.Cargo.UI
ShuttleNameLabel.Text = name;
}
public void SetOrders(List<CargoOrderData> orders)
public void SetOrders(SpriteSystem sprites, IPrototypeManager protoManager, List<CargoOrderData> orders)
{
Orders.DisposeAllChildren();
foreach (var order in orders)
{
var product = _protoManager.Index<EntityPrototype>(order.ProductId);
var product = protoManager.Index<EntityPrototype>(order.ProductId);
var productName = product.Name;
var row = new CargoOrderRow
{
Order = order,
Icon = { Texture = _spriteSystem.Frame0(product) },
Icon = { Texture = sprites.Frame0(product) },
ProductName =
{
Text = Loc.GetString(

View File

@@ -31,7 +31,7 @@ public sealed partial class NewsReaderUiFragment : BoxContainer
Author.Visible = true;
PageName.Text = article.Title;
PageText.SetMarkup(article.Content);
PageText.SetMarkupPermissive(article.Content);
PageNum.Text = $"{targetNum}/{totalNum}";

View File

@@ -2,6 +2,7 @@ using Content.Shared.Chemistry;
using Content.Shared.Containers.ItemSlots;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Chemistry.UI
{
@@ -27,13 +28,8 @@ namespace Content.Client.Chemistry.UI
base.Open();
// Setup window layout/elements
_window = new ChemMasterWindow
{
Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName,
};
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<ChemMasterWindow>();
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
// Setup static button actions.
_window.InputEjectButton.OnPressed += _ => SendMessage(
@@ -75,15 +71,5 @@ namespace Content.Client.Chemistry.UI
_window?.UpdateState(castState); // Update window state
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -3,6 +3,7 @@ using Content.Shared.Chemistry;
using Content.Shared.Containers.ItemSlots;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Chemistry.UI
{
@@ -15,9 +16,6 @@ namespace Content.Client.Chemistry.UI
[ViewVariables]
private ReagentDispenserWindow? _window;
[ViewVariables]
private ReagentDispenserBoundUserInterfaceState? _lastState;
public ReagentDispenserBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
@@ -32,14 +30,9 @@ namespace Content.Client.Chemistry.UI
base.Open();
// Setup window layout/elements
_window = new()
{
Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName,
HelpGuidebookIds = EntMan.GetComponent<GuideHelpComponent>(Owner).Guides
};
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<ReagentDispenserWindow>();
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
_window.HelpGuidebookIds = EntMan.GetComponent<GuideHelpComponent>(Owner).Guides;
// Setup static button actions.
_window.EjectButton.OnPressed += _ => SendMessage(new ItemSlotButtonPressedEvent(SharedReagentDispenser.OutputSlotName));
@@ -63,19 +56,7 @@ namespace Content.Client.Chemistry.UI
base.UpdateState(state);
var castState = (ReagentDispenserBoundUserInterfaceState) state;
_lastState = castState;
_window?.UpdateState(castState); //Update window state
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared.Chemistry;
using Content.Shared.FixedPoint;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Chemistry.UI
{
@@ -18,7 +19,7 @@ namespace Content.Client.Chemistry.UI
protected override void Open()
{
base.Open();
_window = new TransferAmountWindow();
_window = this.CreateWindow<TransferAmountWindow>();
_window.ApplyButton.OnPressed += _ =>
{
@@ -28,15 +29,6 @@ namespace Content.Client.Chemistry.UI
_window.Close();
}
};
_window.OnClose += Close;
_window.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -1,6 +1,7 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Content.Shared.Cloning.CloningConsole;
using Robust.Client.UserInterface;
namespace Content.Client.CloningConsole.UI
{
@@ -17,13 +18,11 @@ namespace Content.Client.CloningConsole.UI
protected override void Open()
{
base.Open();
_window = new CloningConsoleWindow
{
Title = Loc.GetString("cloning-console-window-title")
};
_window.OnClose += Close;
_window = this.CreateWindow<CloningConsoleWindow>();
_window.Title = Loc.GetString("cloning-console-window-title");
_window.CloneButton.OnPressed += _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone));
_window.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -32,19 +31,5 @@ namespace Content.Client.CloningConsole.UI
_window?.Populate((CloningConsoleBoundUserInterfaceState) state);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_window != null)
{
_window.OnClose -= Close;
_window.CloneButton.OnPressed -= _ => SendMessage(new UiButtonPressedMessage(UiButton.Clone));
}
_window?.Dispose();
}
}
}

View File

@@ -1,10 +1,12 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Numerics;
using Content.Client.DisplacementMap;
using Content.Client.Inventory;
using Content.Shared.Clothing;
using Content.Shared.Clothing.Components;
using Content.Shared.Clothing.EntitySystems;
using Content.Shared.DisplacementMap;
using Content.Shared.Humanoid;
using Content.Shared.Inventory;
using Content.Shared.Inventory.Events;
@@ -57,6 +59,7 @@ public sealed class ClientClothingSystem : ClothingSystem
[Dependency] private readonly IResourceCache _cache = default!;
[Dependency] private readonly ISerializationManager _serialization = default!;
[Dependency] private readonly InventorySystem _inventorySystem = default!;
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
public override void Initialize()
{
@@ -71,15 +74,14 @@ public sealed class ClientClothingSystem : ClothingSystem
private void OnAppearanceUpdate(EntityUid uid, InventoryComponent component, ref AppearanceChangeEvent args)
{
// May need to update jumpsuit stencils if the sex changed. Also required to properly set the stencil on init
// May need to update displacement maps if the sex changed. Also required to properly set the stencil on init
if (args.Sprite == null)
return;
if (_inventorySystem.TryGetSlotEntity(uid, Jumpsuit, out var suit, component)
&& TryComp(suit, out ClothingComponent? clothing))
var enumerator = _inventorySystem.GetSlotEnumerator((uid, component));
while (enumerator.NextItem(out var item, out var slot))
{
SetGenderedMask(uid, args.Sprite, clothing);
return;
RenderEquipment(uid, item, slot.Name, component);
}
// No clothing equipped -> make sure the layer is hidden, though this should already be handled by on-unequip.
@@ -186,14 +188,6 @@ public sealed class ClientClothingSystem : ClothingSystem
private void OnDidUnequip(EntityUid uid, SpriteComponent component, DidUnequipEvent args)
{
// Hide jumpsuit mask layer.
if (args.Slot == Jumpsuit
&& TryComp(uid, out SpriteComponent? sprite)
&& sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var maskLayer))
{
sprite.LayerSetVisible(maskLayer, false);
}
if (!TryComp(uid, out InventorySlotsComponent? inventorySlots))
return;
@@ -238,9 +232,6 @@ public sealed class ClientClothingSystem : ClothingSystem
return;
}
if (slot == Jumpsuit)
SetGenderedMask(equipee, sprite, clothingComponent);
if (!_inventorySystem.TryGetSlot(equipee, slot, out var slotDef, inventory))
return;
@@ -272,7 +263,25 @@ public sealed class ClientClothingSystem : ClothingSystem
// temporary, until layer draw depths get added. Basically: a layer with the key "slot" is being used as a
// bookmark to determine where in the list of layers we should insert the clothing layers.
bool slotLayerExists = sprite.LayerMapTryGet(slot, out var index);
var displacementData = inventory.Displacements.GetValueOrDefault(slot);
// Select displacement maps
var displacementData = inventory.Displacements.GetValueOrDefault(slot); //Default unsexed map
var equipeeSex = CompOrNull<HumanoidAppearanceComponent>(equipee)?.Sex;
if (equipeeSex != null)
{
switch (equipeeSex)
{
case Sex.Male:
if (inventory.MaleDisplacements.Count > 0)
displacementData = inventory.MaleDisplacements.GetValueOrDefault(slot);
break;
case Sex.Female:
if (inventory.FemaleDisplacements.Count > 0)
displacementData = inventory.FemaleDisplacements.GetValueOrDefault(slot);
break;
}
}
// add the new layers
foreach (var (key, layerData) in ev.Layers)
@@ -299,7 +308,7 @@ public sealed class ClientClothingSystem : ClothingSystem
index = sprite.LayerMapReserveBlank(key);
if (sprite[index] is not Layer layer)
return;
continue;
// In case no RSI is given, use the item's base RSI as a default. This cuts down on a lot of unnecessary yaml entries.
if (layerData.RsiPath == null
@@ -310,90 +319,19 @@ public sealed class ClientClothingSystem : ClothingSystem
layer.SetRsi(clothingSprite.BaseRSI);
}
// Another "temporary" fix for clothing stencil masks.
// Sprite layer redactor when
// Sprite "redactor" just a week away.
if (slot == Jumpsuit)
layerData.Shader ??= "StencilDraw";
sprite.LayerSetData(index, layerData);
layer.Offset += slotDef.Offset;
if (displacementData != null)
if (displacementData is not null)
{
if (displacementData.ShaderOverride != null)
sprite.LayerSetShader(index, displacementData.ShaderOverride);
var displacementKey = $"{key}-displacement";
if (!revealedLayers.Add(displacementKey))
{
Log.Warning($"Duplicate key for clothing visuals DISPLACEMENT: {displacementKey}.");
//Checking that the state is not tied to the current race. In this case we don't need to use the displacement maps.
if (layerData.State is not null && inventory.SpeciesId is not null && layerData.State.EndsWith(inventory.SpeciesId))
continue;
}
//CP14 48*48 displacement maps support
var displacementDataLayer = displacementData.Layer;
var actualRSI = sprite.LayerGetActualRSI(index);
if (actualRSI != null)
{
var layerSize = actualRSI.Size;
if (layerSize.X == 48 && displacementData.Layer48 != null)
displacementDataLayer = displacementData.Layer48;
}
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
//CP14 48*48 displacement maps support end
displacementLayer.CopyToShaderParameters!.LayerKey = key;
// Add before main layer for this item.
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
revealedLayers.Add(displacementKey);
_displacement.TryAddDisplacement(displacementData, sprite, index, key, revealedLayers);
}
}
RaiseLocalEvent(equipment, new EquipmentVisualsUpdatedEvent(equipee, slot, revealedLayers), true);
}
/// <summary>
/// Sets a sprite's gendered mask based on gender (obviously).
/// </summary>
/// <param name="sprite">Sprite to modify</param>
/// <param name="humanoid">Humanoid, to get gender from</param>
/// <param name="clothing">Clothing component, to get mask sprite type</param>
private void SetGenderedMask(EntityUid uid, SpriteComponent sprite, ClothingComponent clothing)
{
if (!sprite.LayerMapTryGet(HumanoidVisualLayers.StencilMask, out var layer))
return;
ClothingMask mask;
string prefix;
switch (CompOrNull<HumanoidAppearanceComponent>(uid)?.Sex)
{
case Sex.Male:
mask = clothing.MaleMask;
prefix = "male_";
break;
case Sex.Female:
mask = clothing.FemaleMask;
prefix = "female_";
break;
default:
mask = clothing.UnisexMask;
prefix = "unisex_";
break;
}
sprite.LayerSetState(layer, mask switch
{
ClothingMask.NoMask => $"{prefix}none",
ClothingMask.UniformTop => $"{prefix}top",
_ => $"{prefix}full",
});
sprite.LayerSetVisible(layer, true);
}
}

View File

@@ -2,6 +2,7 @@
using Content.Shared.Clothing.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Clothing.UI;
@@ -22,10 +23,8 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new ChameleonMenu();
_menu.OnClose += Close;
_menu = this.CreateWindow<ChameleonMenu>();
_menu.OnIdSelected += OnIdSelected;
_menu.OpenCentered();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -42,15 +41,4 @@ public sealed class ChameleonBoundUserInterface : BoundUserInterface
{
SendMessage(new ChameleonPrototypeSelectedMessage(selectedId));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_menu?.Close();
_menu = null;
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.CCVar;
using Content.Shared.Chat;
using Content.Shared.Communications;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
@@ -8,34 +9,11 @@ namespace Content.Client.Communications.UI
{
public sealed class CommunicationsConsoleBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly IConfigurationManager _cfg = default!;
[ViewVariables]
private CommunicationsConsoleMenu? _menu;
[ViewVariables]
public bool CanAnnounce { get; private set; }
[ViewVariables]
public bool CanBroadcast { get; private set; }
[ViewVariables]
public bool CanCall { get; private set; }
[ViewVariables]
public bool CountdownStarted { get; private set; }
[ViewVariables]
public bool AlertLevelSelectable { get; private set; }
[ViewVariables]
public string CurrentLevel { get; private set; } = default!;
[ViewVariables]
private TimeSpan? _expectedCountdownTime;
public int Countdown => _expectedCountdownTime == null ? 0 : Math.Max((int) _expectedCountdownTime.Value.Subtract(_gameTiming.CurTime).TotalSeconds, 0);
public CommunicationsConsoleBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
@@ -44,23 +22,25 @@ namespace Content.Client.Communications.UI
{
base.Open();
_menu = new CommunicationsConsoleMenu(this);
_menu.OnClose += Close;
_menu.OpenCentered();
_menu = this.CreateWindow<CommunicationsConsoleMenu>();
_menu.OnAnnounce += AnnounceButtonPressed;
_menu.OnBroadcast += BroadcastButtonPressed;
_menu.OnAlertLevel += AlertLevelSelected;
_menu.OnEmergencyLevel += EmergencyShuttleButtonPressed;
}
public void AlertLevelSelected(string level)
{
if (AlertLevelSelectable)
if (_menu!.AlertLevelSelectable)
{
CurrentLevel = level;
_menu.CurrentLevel = level;
SendMessage(new CommunicationsConsoleSelectAlertLevelMessage(level));
}
}
public void EmergencyShuttleButtonPressed()
{
if (CountdownStarted)
if (_menu!.CountdownStarted)
RecallShuttle();
else
CallShuttle();
@@ -95,31 +75,23 @@ namespace Content.Client.Communications.UI
if (state is not CommunicationsConsoleInterfaceState commsState)
return;
CanAnnounce = commsState.CanAnnounce;
CanBroadcast = commsState.CanBroadcast;
CanCall = commsState.CanCall;
_expectedCountdownTime = commsState.ExpectedCountdownEnd;
CountdownStarted = commsState.CountdownStarted;
AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0;
CurrentLevel = commsState.CurrentAlert;
if (_menu != null)
{
_menu.CanAnnounce = commsState.CanAnnounce;
_menu.CanBroadcast = commsState.CanBroadcast;
_menu.CanCall = commsState.CanCall;
_menu.CountdownStarted = commsState.CountdownStarted;
_menu.AlertLevelSelectable = commsState.AlertLevels != null && !float.IsNaN(commsState.CurrentAlertDelay) && commsState.CurrentAlertDelay <= 0;
_menu.CurrentLevel = commsState.CurrentAlert;
_menu.CountdownEnd = commsState.ExpectedCountdownEnd;
_menu.UpdateCountdown();
_menu.UpdateAlertLevels(commsState.AlertLevels, CurrentLevel);
_menu.AlertLevelButton.Disabled = !AlertLevelSelectable;
_menu.EmergencyShuttleButton.Disabled = !CanCall;
_menu.AnnounceButton.Disabled = !CanAnnounce;
_menu.BroadcastButton.Disabled = !CanBroadcast;
_menu.UpdateAlertLevels(commsState.AlertLevels, _menu.CurrentLevel);
_menu.AlertLevelButton.Disabled = !_menu.AlertLevelSelectable;
_menu.EmergencyShuttleButton.Disabled = !_menu.CanCall;
_menu.AnnounceButton.Disabled = !_menu.CanAnnounce;
_menu.BroadcastButton.Disabled = !_menu.CanBroadcast;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_menu?.Dispose();
}
}
}

View File

@@ -1,31 +1,40 @@
using Content.Client.UserInterface.Controls;
using System.Threading;
using System.Globalization;
using Content.Client.UserInterface.Controls;
using Content.Shared.CCVar;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
using Timer = Robust.Shared.Timing.Timer;
namespace Content.Client.Communications.UI
{
[GenerateTypedNameReferences]
public sealed partial class CommunicationsConsoleMenu : FancyWindow
{
private CommunicationsConsoleBoundUserInterface Owner { get; set; }
private readonly CancellationTokenSource _timerCancelTokenSource = new();
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _timing = default!;
[Dependency] private readonly ILocalizationManager _loc = default!;
public CommunicationsConsoleMenu(CommunicationsConsoleBoundUserInterface owner)
public bool CanAnnounce;
public bool CanBroadcast;
public bool CanCall;
public bool AlertLevelSelectable;
public bool CountdownStarted;
public string CurrentLevel = string.Empty;
public TimeSpan? CountdownEnd;
public event Action? OnEmergencyLevel;
public event Action<string>? OnAlertLevel;
public event Action<string>? OnAnnounce;
public event Action<string>? OnBroadcast;
public CommunicationsConsoleMenu()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
Owner = owner;
var loc = IoCManager.Resolve<ILocalizationManager>();
MessageInput.Placeholder = new Rope.Leaf(loc.GetString("comms-console-menu-announcement-placeholder"));
MessageInput.Placeholder = new Rope.Leaf(_loc.GetString("comms-console-menu-announcement-placeholder"));
var maxAnnounceLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);
MessageInput.OnTextChanged += (args) =>
@@ -37,33 +46,38 @@ namespace Content.Client.Communications.UI
}
else
{
AnnounceButton.Disabled = !owner.CanAnnounce;
AnnounceButton.Disabled = !CanAnnounce;
AnnounceButton.ToolTip = null;
}
};
AnnounceButton.OnPressed += (_) => Owner.AnnounceButtonPressed(Rope.Collapse(MessageInput.TextRope));
AnnounceButton.Disabled = !owner.CanAnnounce;
AnnounceButton.OnPressed += _ => OnAnnounce?.Invoke(Rope.Collapse(MessageInput.TextRope));
AnnounceButton.Disabled = !CanAnnounce;
BroadcastButton.OnPressed += (_) => Owner.BroadcastButtonPressed(Rope.Collapse(MessageInput.TextRope));
BroadcastButton.Disabled = !owner.CanBroadcast;
BroadcastButton.OnPressed += _ => OnBroadcast?.Invoke(Rope.Collapse(MessageInput.TextRope));
BroadcastButton.Disabled = !CanBroadcast;
AlertLevelButton.OnItemSelected += args =>
{
var metadata = AlertLevelButton.GetItemMetadata(args.Id);
if (metadata != null && metadata is string cast)
{
Owner.AlertLevelSelected(cast);
OnAlertLevel?.Invoke(cast);
}
};
AlertLevelButton.Disabled = !owner.AlertLevelSelectable;
EmergencyShuttleButton.OnPressed += (_) => Owner.EmergencyShuttleButtonPressed();
EmergencyShuttleButton.Disabled = !owner.CanCall;
AlertLevelButton.Disabled = !AlertLevelSelectable;
EmergencyShuttleButton.OnPressed += _ => OnEmergencyLevel?.Invoke();
EmergencyShuttleButton.Disabled = !CanCall;
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
UpdateCountdown();
Timer.SpawnRepeating(1000, UpdateCountdown, _timerCancelTokenSource.Token);
}
// The current alert could make levels unselectable, so we need to ensure that the UI reacts properly.
@@ -105,32 +119,19 @@ namespace Content.Client.Communications.UI
public void UpdateCountdown()
{
if (!Owner.CountdownStarted)
if (!CountdownStarted)
{
CountdownLabel.SetMessage("");
CountdownLabel.SetMessage(string.Empty);
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-call-shuttle");
return;
}
var diff = MathHelper.Max((CountdownEnd - _timing.CurTime) ?? TimeSpan.Zero, TimeSpan.Zero);
EmergencyShuttleButton.Text = Loc.GetString("comms-console-menu-recall-shuttle");
var infoText = Loc.GetString($"comms-console-menu-time-remaining",
("time", Owner.Countdown.ToString()));
("time", diff.TotalSeconds.ToString(CultureInfo.CurrentCulture)));
CountdownLabel.SetMessage(infoText);
}
public override void Close()
{
base.Close();
_timerCancelTokenSource.Cancel();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_timerCancelTokenSource.Cancel();
}
}
}

View File

@@ -1,4 +1,5 @@
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.CustomControls;
namespace Content.Client.Computer
@@ -19,10 +20,8 @@ namespace Content.Client.Computer
{
base.Open();
_window = (TWindow) _dynamicTypeFactory.CreateInstance(typeof(TWindow));
_window = this.CreateWindow<TWindow>();
_window.SetupComputerWindow(this);
_window.OnClose += Close;
_window.OpenCentered();
}
// Alas, this constructor has to be copied to the subclass. :(
@@ -42,16 +41,6 @@ namespace Content.Client.Computer
_window.UpdateState((TState) state);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
{
_window?.ReceiveMessage(message);

View File

@@ -1,5 +1,6 @@
using System.Text.RegularExpressions;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using static Content.Shared.Configurable.ConfigurationComponent;
namespace Content.Client.Configurable.UI
@@ -9,9 +10,6 @@ namespace Content.Client.Configurable.UI
[ViewVariables]
private ConfigurationMenu? _menu;
[ViewVariables]
public Regex? Validation { get; internal set; }
public ConfigurationBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
@@ -19,10 +17,8 @@ namespace Content.Client.Configurable.UI
protected override void Open()
{
base.Open();
_menu = new ConfigurationMenu(this);
_menu.OnClose += Close;
_menu.OpenCentered();
_menu = this.CreateWindow<ConfigurationMenu>();
_menu.OnConfiguration += SendConfiguration;
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -30,9 +26,7 @@ namespace Content.Client.Configurable.UI
base.UpdateState(state);
if (state is not ConfigurationBoundUserInterfaceState configurationState)
{
return;
}
_menu?.Populate(configurationState);
}
@@ -41,9 +35,12 @@ namespace Content.Client.Configurable.UI
{
base.ReceiveMessage(message);
if (_menu == null)
return;
if (message is ValidationUpdateMessage msg)
{
Validation = new Regex(msg.ValidationString, RegexOptions.Compiled);
_menu.Validation = new Regex(msg.ValidationString, RegexOptions.Compiled);
}
}
@@ -51,16 +48,5 @@ namespace Content.Client.Configurable.UI
{
SendMessage(new ConfigurationUpdatedMessage(config));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing && _menu != null)
{
_menu.OnClose -= Close;
_menu.Close();
}
}
}
}

View File

@@ -1,5 +1,6 @@
using System.Collections.Generic;
using System.Numerics;
using System.Text.RegularExpressions;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
@@ -13,23 +14,25 @@ namespace Content.Client.Configurable.UI
{
public sealed class ConfigurationMenu : DefaultWindow
{
public ConfigurationBoundUserInterface Owner { get; }
private readonly BoxContainer _column;
private readonly BoxContainer _row;
private readonly List<(string name, LineEdit input)> _inputs;
public ConfigurationMenu(ConfigurationBoundUserInterface owner)
[ViewVariables]
public Regex? Validation { get; internal set; }
public event Action<Dictionary<string, string>>? OnConfiguration;
public ConfigurationMenu()
{
MinSize = SetSize = new Vector2(300, 250);
Owner = owner;
_inputs = new List<(string name, LineEdit input)>();
Title = Loc.GetString("configuration-menu-device-title");
BoxContainer baseContainer = new BoxContainer
var baseContainer = new BoxContainer
{
Orientation = LayoutOrientation.Vertical,
VerticalExpand = true,
@@ -116,14 +119,13 @@ namespace Content.Client.Configurable.UI
private void OnConfirm(ButtonEventArgs args)
{
var config = GenerateDictionary(_inputs, "Text");
Owner.SendConfiguration(config);
OnConfiguration?.Invoke(config);
Close();
}
private bool Validate(string value)
{
return Owner.Validation == null || Owner.Validation.IsMatch(value);
return Validation?.IsMatch(value) != false;
}
private Dictionary<string, string> GenerateDictionary(IEnumerable<(string name, LineEdit input)> inputs, string propertyName)

View File

@@ -1,5 +1,6 @@
using Content.Shared.Construction.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Construction.UI
{
@@ -17,8 +18,8 @@ namespace Content.Client.Construction.UI
{
base.Open();
_menu = new FlatpackCreatorMenu(Owner);
_menu.OnClose += Close;
_menu = this.CreateWindow<FlatpackCreatorMenu>();
_menu.SetEntity(Owner);
_menu.PackButtonPressed += () =>
{
@@ -27,14 +28,5 @@ namespace Content.Client.Construction.UI
_menu.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}
}

View File

@@ -24,7 +24,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
private readonly FlatpackSystem _flatpack;
private readonly MaterialStorageSystem _materialStorage;
private readonly EntityUid _owner;
private EntityUid _owner;
[ValidatePrototypeId<EntityPrototype>]
public const string NoBoardEffectId = "FlatpackerNoBoardEffect";
@@ -33,7 +33,7 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
public event Action? PackButtonPressed;
public FlatpackCreatorMenu(EntityUid uid)
public FlatpackCreatorMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
@@ -42,14 +42,17 @@ public sealed partial class FlatpackCreatorMenu : FancyWindow
_flatpack = _entityManager.System<FlatpackSystem>();
_materialStorage = _entityManager.System<MaterialStorageSystem>();
_owner = uid;
PackButton.OnPressed += _ => PackButtonPressed?.Invoke();
MaterialStorageControl.SetOwner(uid);
InsertLabel.SetMarkup(Loc.GetString("flatpacker-ui-insert-board"));
}
public void SetEntity(EntityUid uid)
{
_owner = uid;
MaterialStorageControl.SetOwner(uid);
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);

View File

@@ -2,12 +2,15 @@
using Content.Shared.Crayon;
using Content.Shared.Decals;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Crayon.UI
{
public sealed class CrayonBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _protoManager = default!;
[ViewVariables]
private CrayonWindow? _menu;
@@ -18,15 +21,29 @@ namespace Content.Client.Crayon.UI
protected override void Open()
{
base.Open();
_menu = new CrayonWindow(this);
_menu.OnClose += Close;
var prototypeManager = IoCManager.Resolve<IPrototypeManager>();
var crayonDecals = prototypeManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
_menu.Populate(crayonDecals);
_menu = this.CreateWindow<CrayonWindow>();
_menu.OnColorSelected += SelectColor;
_menu.OnSelected += Select;
PopulateCrayons();
_menu.OpenCenteredLeft();
}
private void PopulateCrayons()
{
var crayonDecals = _protoManager.EnumeratePrototypes<DecalPrototype>().Where(x => x.Tags.Contains("crayon"));
_menu?.Populate(crayonDecals);
}
public override void OnProtoReload(PrototypesReloadedEventArgs args)
{
base.OnProtoReload(args);
if (!args.WasModified<DecalPrototype>())
return;
PopulateCrayons();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
@@ -43,16 +60,5 @@ namespace Content.Client.Crayon.UI
{
SendMessage(new CrayonColorMessage(color));
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_menu?.Close();
_menu = null;
}
}
}
}

View File

@@ -18,18 +18,17 @@ namespace Content.Client.Crayon.UI
[GenerateTypedNameReferences]
public sealed partial class CrayonWindow : DefaultWindow
{
public CrayonBoundUserInterface Owner { get; }
private Dictionary<string, Texture>? _decals;
private string? _selected;
private Color _color;
public CrayonWindow(CrayonBoundUserInterface owner)
public event Action<Color>? OnColorSelected;
public event Action<string>? OnSelected;
public CrayonWindow()
{
RobustXamlLoader.Load(this);
Owner = owner;
Search.OnTextChanged += _ => RefreshList();
ColorSelector.OnColorChanged += SelectColor;
}
@@ -38,16 +37,16 @@ namespace Content.Client.Crayon.UI
{
_color = color;
Owner.SelectColor(color);
OnColorSelected?.Invoke(color);
RefreshList();
}
private void RefreshList()
{
// Clear
Grid.RemoveAllChildren();
if (_decals == null) return;
Grid.DisposeAllChildren();
if (_decals == null)
return;
var filter = Search.Text;
foreach (var (decal, tex) in _decals)
@@ -89,8 +88,8 @@ namespace Content.Client.Crayon.UI
{
if (obj.Button.Name == null) return;
Owner.Select(obj.Button.Name);
_selected = obj.Button.Name;
OnSelected?.Invoke(_selected);
RefreshList();
}

View File

@@ -0,0 +1,65 @@
using Content.Shared.DisplacementMap;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Shared.Serialization.Manager;
namespace Content.Client.DisplacementMap;
public sealed class DisplacementMapSystem : EntitySystem
{
[Dependency] private readonly ISerializationManager _serialization = default!;
public bool TryAddDisplacement(DisplacementData data, SpriteComponent sprite, int index, string key, HashSet<string> revealedLayers)
{
if (data.ShaderOverride != null)
sprite.LayerSetShader(index, data.ShaderOverride);
var displacementKey = $"{key}-displacement";
if (!revealedLayers.Add(displacementKey))
{
Log.Warning($"Duplicate key for DISPLACEMENT: {displacementKey}.");
return false;
}
//allows you not to write it every time in the YML
foreach (var pair in data.SizeMaps)
{
pair.Value.CopyToShaderParameters??= new()
{
LayerKey = "dummy",
ParameterTexture = "displacementMap",
ParameterUV = "displacementUV",
};
}
if (!data.SizeMaps.ContainsKey(32))
{
Log.Error($"DISPLACEMENT: {displacementKey} don't have 32x32 default displacement map");
return false;
}
// We choose a displacement map from the possible ones, matching the size with the original layer size.
// If there is no such a map, we use a standard 32 by 32 one
var displacementDataLayer = data.SizeMaps[EyeManager.PixelsPerMeter];
var actualRSI = sprite.LayerGetActualRSI(index);
if (actualRSI is not null)
{
if (actualRSI.Size.X != actualRSI.Size.Y)
Log.Warning($"DISPLACEMENT: {displacementKey} has a resolution that is not 1:1, things can look crooked");
var layerSize = actualRSI.Size.X;
if (data.SizeMaps.ContainsKey(layerSize))
displacementDataLayer = data.SizeMaps[layerSize];
}
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key;
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
revealedLayers.Add(displacementKey);
return true;
}
}

View File

@@ -1,5 +1,6 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using static Content.Shared.Disposal.Components.SharedDisposalRouterComponent;
namespace Content.Client.Disposal.UI
@@ -21,20 +22,16 @@ namespace Content.Client.Disposal.UI
{
base.Open();
_window = new DisposalRouterWindow();
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<DisposalRouterWindow>();
_window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text);
_window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text);
}
private void ButtonPressed(UiAction action, string tag)
{
SendMessage(new UiActionMessage(action, tag));
_window?.Close();
Close();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -48,18 +45,5 @@ namespace Content.Client.Disposal.UI
_window?.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -1,5 +1,6 @@
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using static Content.Shared.Disposal.Components.SharedDisposalTaggerComponent;
namespace Content.Client.Disposal.UI
@@ -21,20 +22,17 @@ namespace Content.Client.Disposal.UI
{
base.Open();
_window = new DisposalTaggerWindow();
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<DisposalTaggerWindow>();
_window.Confirm.OnPressed += _ => ButtonPressed(UiAction.Ok, _window.TagInput.Text);
_window.TagInput.OnTextEntered += args => ButtonPressed(UiAction.Ok, args.Text);
}
private void ButtonPressed(UiAction action, string tag)
{
// TODO: This looks copy-pasted with the other mailing stuff...
SendMessage(new UiActionMessage(action, tag));
_window?.Close();
Close();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -48,18 +46,5 @@ namespace Content.Client.Disposal.UI
_window?.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
}
}
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared.Disposal;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Timing;
namespace Content.Client.Disposal.UI
{
@@ -11,6 +12,8 @@ namespace Content.Client.Disposal.UI
[GenerateTypedNameReferences]
public sealed partial class MailingUnitWindow : DefaultWindow
{
public TimeSpan FullPressure;
public MailingUnitWindow()
{
RobustXamlLoader.Load(this);
@@ -26,6 +29,7 @@ namespace Content.Client.Disposal.UI
Title = Loc.GetString("ui-mailing-unit-window-title", ("tag", state.Tag ?? " "));
UnitState.Text = disposalState.UnitState;
FullPressure = disposalState.FullPressureTime;
var pressureReached = PressureBar.UpdatePressure(disposalState.FullPressureTime);
Power.Pressed = disposalState.Powered;
Engage.Pressed = disposalState.Engaged;
@@ -42,9 +46,10 @@ namespace Content.Client.Disposal.UI
return !disposalState.Powered || pressureReached;
}
public bool UpdatePressure(TimeSpan stateFullPressureTime)
protected override void FrameUpdate(FrameEventArgs args)
{
return PressureBar.UpdatePressure(stateFullPressureTime);
base.FrameUpdate(args);
PressureBar.UpdatePressure(FullPressure);
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Access;
using Content.Shared.Doors.Electronics;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Doors.Electronics;
@@ -18,6 +19,23 @@ public sealed class DoorElectronicsBoundUserInterface : BoundUserInterface
protected override void Open()
{
base.Open();
_window = this.CreateWindow<DoorElectronicsConfigurationMenu>();
_window.OnAccessChanged += UpdateConfiguration;
Reset();
}
public override void OnProtoReload(PrototypesReloadedEventArgs args)
{
base.OnProtoReload(args);
if (!args.WasModified<AccessLevelPrototype>())
return;
Reset();
}
private void Reset()
{
List<ProtoId<AccessLevelPrototype>> accessLevels = new();
foreach (var accessLevel in _prototypeManager.EnumeratePrototypes<AccessLevelPrototype>())
@@ -29,10 +47,7 @@ public sealed class DoorElectronicsBoundUserInterface : BoundUserInterface
}
accessLevels.Sort();
_window = new DoorElectronicsConfigurationMenu(this, accessLevels, _prototypeManager);
_window.OnClose += Close;
_window.OpenCentered();
_window?.Reset(_prototypeManager, accessLevels);
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -44,14 +59,6 @@ public sealed class DoorElectronicsBoundUserInterface : BoundUserInterface
_window?.UpdateState(castState);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
public void UpdateConfiguration(List<ProtoId<AccessLevelPrototype>> newAccessList)
{
SendMessage(new DoorElectronicsUpdateConfigurationMessage(newAccessList));

View File

@@ -15,22 +15,23 @@ namespace Content.Client.Doors.Electronics;
[GenerateTypedNameReferences]
public sealed partial class DoorElectronicsConfigurationMenu : FancyWindow
{
private readonly DoorElectronicsBoundUserInterface _owner;
private AccessLevelControl _buttonsList = new();
private readonly AccessLevelControl _buttonsList = new();
public DoorElectronicsConfigurationMenu(DoorElectronicsBoundUserInterface ui, List<ProtoId<AccessLevelPrototype>> accessLevels, IPrototypeManager prototypeManager)
public event Action<List<ProtoId<AccessLevelPrototype>>>? OnAccessChanged;
public DoorElectronicsConfigurationMenu()
{
RobustXamlLoader.Load(this);
_owner = ui;
_buttonsList.Populate(accessLevels, prototypeManager);
AccessLevelControlContainer.AddChild(_buttonsList);
}
foreach (var (id, button) in _buttonsList.ButtonsList)
public void Reset(IPrototypeManager protoManager, List<ProtoId<AccessLevelPrototype>> accessLevels)
{
_buttonsList.Populate(accessLevels, protoManager);
foreach (var button in _buttonsList.ButtonsList.Values)
{
button.OnPressed += _ => _owner.UpdateConfiguration(
_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
button.OnPressed += _ => OnAccessChanged?.Invoke(_buttonsList.ButtonsList.Where(x => x.Value.Pressed).Select(x => x.Key).ToList());
}
}

View File

@@ -25,24 +25,30 @@ public sealed class FaxVisualsSystem : EntitySystem
if (args.Sprite == null)
return;
if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) && visuals == FaxMachineVisualState.Inserting)
if (_player.HasRunningAnimation(uid, "faxecute"))
return;
if (_appearance.TryGetData(uid, FaxMachineVisuals.VisualState, out FaxMachineVisualState visuals) &&
visuals == FaxMachineVisualState.Inserting)
{
_player.Play(uid, new Animation()
{
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
_player.Play(uid,
new Animation()
{
new AnimationTrackSpriteFlick()
Length = TimeSpan.FromSeconds(2.4),
AnimationTracks =
{
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
new AnimationTrackSpriteFlick()
{
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f),
new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f),
}
}
}
}, "faxecute");
LayerKey = FaxMachineVisuals.VisualState,
KeyFrames =
{
new AnimationTrackSpriteFlick.KeyFrame(component.InsertingState, 0f),
new AnimationTrackSpriteFlick.KeyFrame("icon", 2.4f),
},
},
},
},
"faxecute");
}
}
}

View File

@@ -25,10 +25,7 @@ public sealed class FaxBoundUi : BoundUserInterface
{
base.Open();
_window = new FaxWindow();
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<FaxWindow>();
_window.FileButtonPressed += OnFileButtonPressed;
_window.CopyButtonPressed += OnCopyButtonPressed;
_window.SendButtonPressed += OnSendButtonPressed;
@@ -104,11 +101,4 @@ public sealed class FaxBoundUi : BoundUserInterface
_window.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_window?.Dispose();
}
}

View File

@@ -1,6 +1,7 @@
using Robust.Client.GameObjects;
using Robust.Shared.Timing;
using Content.Shared.Forensics;
using Robust.Client.UserInterface;
namespace Content.Client.Forensics
{
@@ -21,11 +22,9 @@ namespace Content.Client.Forensics
protected override void Open()
{
base.Open();
_window = new ForensicScannerMenu();
_window.OnClose += Close;
_window = this.CreateWindow<ForensicScannerMenu>();
_window.Print.OnPressed += _ => Print();
_window.Clear.OnPressed += _ => Clear();
_window.OpenCentered();
}
private void Print()
@@ -62,6 +61,7 @@ namespace Content.Client.Forensics
_printCooldown = cast.PrintCooldown;
// TODO: Fix this
if (cast.PrintReadyAt > _gameTiming.CurTime)
Timer.Spawn(cast.PrintReadyAt - _gameTiming.CurTime, () =>
{
@@ -71,14 +71,5 @@ namespace Content.Client.Forensics
_window.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
}
}
}

View File

@@ -185,7 +185,7 @@ namespace Content.Client.Gameplay
EntityCoordinates coordinates = default;
EntityUid? entityToClick = null;
if (args.Viewport is IViewportControl vp)
if (args.Viewport is IViewportControl vp && kArgs.PointerLocation.IsValid)
{
var mousePosWorld = vp.PixelToMap(kArgs.PointerLocation.Position);
entityToClick = GetClickedEntity(mousePosWorld);
@@ -194,6 +194,10 @@ namespace Content.Client.Gameplay
grid.MapToGrid(mousePosWorld) :
EntityCoordinates.FromMap(_mapManager, mousePosWorld);
}
else
{
coordinates = EntityCoordinates.Invalid;
}
var message = new ClientFullInputCmdMessage(_timing.CurTick, _timing.TickFraction, funcId)
{

View File

@@ -1,6 +1,7 @@
using Content.Shared.Gateway;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Gateway.UI;
@@ -17,24 +18,13 @@ public sealed class GatewayBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new GatewayWindow(EntMan.GetNetEntity(Owner));
_window = this.CreateWindow<GatewayWindow>();
_window.SetEntity(EntMan.GetNetEntity(Owner));
_window.OpenPortal += destination =>
{
SendMessage(new GatewayOpenPortalMessage(destination));
};
_window.OnClose += Close;
_window?.OpenCentered();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
{
_window?.Dispose();
_window = null;
}
}
protected override void UpdateState(BoundUserInterfaceState state)

View File

@@ -22,7 +22,7 @@ public sealed partial class GatewayWindow : FancyWindow,
public event Action<NetEntity>? OpenPortal;
private List<GatewayDestinationData> _destinations = new();
public readonly NetEntity Owner;
public NetEntity Owner;
private NetEntity? _current;
private TimeSpan _nextReady;
@@ -46,16 +46,20 @@ public sealed partial class GatewayWindow : FancyWindow,
/// </summary>
private bool _isCooldownPending = true;
public GatewayWindow(NetEntity netEntity)
public GatewayWindow()
{
RobustXamlLoader.Load(this);
var dependencies = IoCManager.Instance!;
_timing = dependencies.Resolve<IGameTiming>();
Owner = netEntity;
NextUnlockBar.ForegroundStyleBoxOverride = new StyleBoxFlat(Color.FromHex("#C74EBD"));
}
public void SetEntity(NetEntity entity)
{
}
public void UpdateState(GatewayBoundUserInterfaceState state)
{
_destinations = state.Destinations;

View File

@@ -0,0 +1,29 @@
using Content.Shared.Ghost.Roles;
using Robust.Client.UserInterface;
using Robust.Shared.Prototypes;
namespace Content.Client.Ghost;
public sealed class GhostRoleRadioBoundUserInterface : BoundUserInterface
{
private GhostRoleRadioMenu? _ghostRoleRadioMenu;
public GhostRoleRadioBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
}
protected override void Open()
{
base.Open();
_ghostRoleRadioMenu = this.CreateWindow<GhostRoleRadioMenu>();
_ghostRoleRadioMenu.SetEntity(Owner);
_ghostRoleRadioMenu.SendGhostRoleRadioMessageAction += SendGhostRoleRadioMessage;
}
public void SendGhostRoleRadioMessage(ProtoId<GhostRolePrototype> protoId)
{
SendMessage(new GhostRoleRadioMessage(protoId));
}
}

View File

@@ -0,0 +1,8 @@
<ui:RadialMenu
xmlns:ui="clr-namespace:Content.Client.UserInterface.Controls"
CloseButtonStyleClass="RadialMenuCloseButton"
VerticalExpand="True"
HorizontalExpand="True">
<ui:RadialContainer Name="Main">
</ui:RadialContainer>
</ui:RadialMenu>

View File

@@ -0,0 +1,107 @@
using Content.Client.UserInterface.Controls;
using Content.Shared.Ghost.Roles;
using Content.Shared.Ghost.Roles.Components;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.Prototypes;
using System.Numerics;
namespace Content.Client.Ghost;
public sealed partial class GhostRoleRadioMenu : RadialMenu
{
[Dependency] private readonly EntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
public event Action<ProtoId<GhostRolePrototype>>? SendGhostRoleRadioMessageAction;
public EntityUid Entity { get; set; }
public GhostRoleRadioMenu()
{
IoCManager.InjectDependencies(this);
RobustXamlLoader.Load(this);
}
public void SetEntity(EntityUid uid)
{
Entity = uid;
RefreshUI();
}
private void RefreshUI()
{
// The main control that will contain all of the clickable options
var main = FindControl<RadialContainer>("Main");
// The purpose of this radial UI is for ghost role radios that allow you to select
// more than one potential option, such as with kobolds/lizards.
// This means that it won't show anything if SelectablePrototypes is empty.
if (!_entityManager.TryGetComponent<GhostRoleMobSpawnerComponent>(Entity, out var comp))
return;
foreach (var ghostRoleProtoString in comp.SelectablePrototypes)
{
// For each prototype we find we want to create a button that uses the name of the ghost role
// as the hover tooltip, and the icon is taken from either the ghost role entityprototype
// or the indicated icon entityprototype.
if (!_prototypeManager.TryIndex<GhostRolePrototype>(ghostRoleProtoString, out var ghostRoleProto))
continue;
var button = new GhostRoleRadioMenuButton()
{
StyleClasses = { "RadialMenuButton" },
SetSize = new Vector2(64, 64),
ToolTip = Loc.GetString(ghostRoleProto.Name),
ProtoId = ghostRoleProto.ID,
};
var entProtoView = new EntityPrototypeView()
{
SetSize = new Vector2(48, 48),
VerticalAlignment = VAlignment.Center,
HorizontalAlignment = HAlignment.Center,
Stretch = SpriteView.StretchMode.Fill
};
// pick the icon if it exists, otherwise fallback to the ghost role's entity
if (_prototypeManager.TryIndex(ghostRoleProto.IconPrototype, out var iconProto))
entProtoView.SetPrototype(iconProto);
else
entProtoView.SetPrototype(comp.Prototype);
button.AddChild(entProtoView);
main.AddChild(button);
AddGhostRoleRadioMenuButtonOnClickActions(main);
}
}
private void AddGhostRoleRadioMenuButtonOnClickActions(Control control)
{
var mainControl = control as RadialContainer;
if (mainControl == null)
return;
foreach (var child in mainControl.Children)
{
var castChild = child as GhostRoleRadioMenuButton;
if (castChild == null)
continue;
castChild.OnButtonUp += _ =>
{
SendGhostRoleRadioMessageAction?.Invoke(castChild.ProtoId);
Close();
};
}
}
}
public sealed class GhostRoleRadioMenuButton : RadialMenuTextureButton
{
public ProtoId<GhostRolePrototype> ProtoId { get; set; }
}

View File

@@ -1,6 +1,6 @@
using Content.Shared.Gravity;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Gravity.UI
{
@@ -18,17 +18,8 @@ namespace Content.Client.Gravity.UI
{
base.Open();
_window = new GravityGeneratorWindow(this);
/*
_window.Switch.OnPressed += _ =>
{
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(!IsOn));
};
*/
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<GravityGeneratorWindow>();
_window.SetEntity(Owner);
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -39,14 +30,6 @@ namespace Content.Client.Gravity.UI
_window?.UpdateState(castState);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
public void SetPowerSwitch(bool on)
{
SendMessage(new SharedGravityGeneratorComponent.SwitchGeneratorMessage(on));

View File

@@ -12,22 +12,23 @@ namespace Content.Client.Gravity.UI
{
private readonly ButtonGroup _buttonGroup = new();
private readonly GravityGeneratorBoundUserInterface _owner;
public event Action<bool>? OnPowerSwitch;
public GravityGeneratorWindow(GravityGeneratorBoundUserInterface owner)
public GravityGeneratorWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_owner = owner;
OnButton.Group = _buttonGroup;
OffButton.Group = _buttonGroup;
OnButton.OnPressed += _ => _owner.SetPowerSwitch(true);
OffButton.OnPressed += _ => _owner.SetPowerSwitch(false);
OnButton.OnPressed += _ => OnPowerSwitch?.Invoke(true);
OffButton.OnPressed += _ => OnPowerSwitch?.Invoke(false);
}
EntityView.SetEntity(owner.Owner);
public void SetEntity(EntityUid uid)
{
EntityView.SetEntity(uid);
}
public void UpdateState(SharedGravityGeneratorComponent.GeneratorState state)

View File

@@ -1,5 +1,6 @@
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Content.Client.DisplacementMap;
using Content.Client.Examine;
using Content.Client.Strip;
using Content.Client.Verbs.UI;
@@ -15,7 +16,6 @@ using Robust.Client.UserInterface;
using Robust.Shared.Containers;
using Robust.Shared.GameStates;
using Robust.Shared.Player;
using Robust.Shared.Serialization.Manager;
using Robust.Shared.Timing;
namespace Content.Client.Hands.Systems
@@ -29,7 +29,7 @@ namespace Content.Client.Hands.Systems
[Dependency] private readonly SharedContainerSystem _containerSystem = default!;
[Dependency] private readonly StrippableSystem _stripSys = default!;
[Dependency] private readonly ExamineSystem _examine = default!;
[Dependency] private readonly ISerializationManager _serialization = default!; //CP14
[Dependency] private readonly DisplacementMapSystem _displacement = default!;
public event Action<string, HandLocation>? OnPlayerAddHand;
public event Action<string>? OnPlayerRemoveHand;
@@ -324,8 +324,6 @@ namespace Content.Client.Hands.Systems
return;
}
var displacementData = handComp.Displacements.GetValueOrDefault("Hands"); //CP14 hands displacements
// add the new layers
foreach (var (key, layerData) in ev.Layers)
{
@@ -350,38 +348,9 @@ namespace Content.Client.Hands.Systems
sprite.LayerSetData(index, layerData);
//CP14 Hands displacement maps
if (displacementData != null)
{
if (displacementData.ShaderOverride != null)
sprite.LayerSetShader(index, displacementData.ShaderOverride);
var displacementKey = $"{key}-displacement";
if (!revealedLayers.Add(displacementKey))
{
Log.Warning($"Duplicate key for inhand layers DISPLACEMENT: {displacementKey}.");
continue;
}
var displacementDataLayer = displacementData.Layer;
var actualRSI = sprite.LayerGetActualRSI(index);
if (actualRSI != null)
{
var layerSize = actualRSI.Size;
if (layerSize.X == 48 && displacementData.Layer48 != null)
displacementDataLayer = displacementData.Layer48;
}
var displacementLayer = _serialization.CreateCopy(displacementDataLayer, notNullableOverride: true);
displacementLayer.CopyToShaderParameters!.LayerKey = key;
// Add before main layer for this item.
sprite.AddLayer(displacementLayer, index);
sprite.LayerMapSet(displacementKey, index);
revealedLayers.Add(displacementKey);
}
//CP14 Hands displacement maps - end
//Add displacement maps
if (handComp.HandDisplacement is not null)
_displacement.TryAddDisplacement(handComp.HandDisplacement, sprite, index, key, revealedLayers);
}
RaiseLocalEvent(held, new HeldVisualsUpdatedEvent(uid, revealedLayers), true);

View File

@@ -1,6 +1,6 @@
using Content.Shared.MedicalScanner;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.HealthAnalyzer.UI
{
@@ -17,12 +17,9 @@ namespace Content.Client.HealthAnalyzer.UI
protected override void Open()
{
base.Open();
_window = new HealthAnalyzerWindow
{
Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName,
};
_window.OnClose += Close;
_window.OpenCentered();
_window = this.CreateWindow<HealthAnalyzerWindow>();
_window.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
}
protected override void ReceiveMessage(BoundUserInterfaceMessage message)
@@ -35,17 +32,5 @@ namespace Content.Client.HealthAnalyzer.UI
_window.Populate(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
if (_window != null)
_window.OnClose -= Close;
_window?.Dispose();
}
}
}

View File

@@ -85,8 +85,19 @@ public sealed class HumanoidAppearanceSystem : SharedHumanoidAppearanceSystem
if (protoId == null)
return;
//if (sexMorph)
// protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
//CP14 female bodies support
if (sexMorph)
protoId = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
{
var tempProto = HumanoidVisualLayersExtension.GetSexMorph(key, component.Sex, protoId);
if (_prototypeManager.TryIndex<HumanoidSpeciesSpriteLayer>(tempProto, out _))
{
protoId = tempProto;
}
}
//CP14 female bodies support end
var proto = _prototypeManager.Index<HumanoidSpeciesSpriteLayer>(protoId);
component.BaseLayers[key] = proto;

View File

@@ -1,5 +1,6 @@
using Content.Shared.Humanoid;
using Content.Shared.Humanoid.Markings;
using Robust.Client.UserInterface;
namespace Content.Client.Humanoid;
@@ -20,8 +21,7 @@ public sealed class HumanoidMarkingModifierBoundUserInterface : BoundUserInterfa
{
base.Open();
_window = new();
_window.OnClose += Close;
_window = this.CreateWindow<HumanoidMarkingModifierWindow>();
_window.OnMarkingAdded += SendMarkingSet;
_window.OnMarkingRemoved += SendMarkingSet;
_window.OnMarkingColorChange += SendMarkingSetNoResend;

View File

@@ -11,7 +11,9 @@ public sealed partial class BandMenu : DefaultWindow
{
private readonly InstrumentBoundUserInterface _owner;
public BandMenu(InstrumentBoundUserInterface owner) : base()
public EntityUid? Master;
public BandMenu(InstrumentBoundUserInterface owner)
{
RobustXamlLoader.Load(this);
@@ -40,7 +42,7 @@ public sealed partial class BandMenu : DefaultWindow
{
var uid = entManager.GetEntity(nent);
var item = BandList.AddItem(name, null, true, uid);
item.Selected = _owner.Instrument?.Master == uid;
item.Selected = Master == uid;
}
}
}

View File

@@ -51,7 +51,7 @@ public sealed partial class ChannelsMenu : DefaultWindow
}
}
public void Populate()
public void Populate(InstrumentComponent? instrument)
{
ChannelList.Clear();
@@ -60,7 +60,8 @@ public sealed partial class ChannelsMenu : DefaultWindow
var item = ChannelList.AddItem(_owner.Loc.GetString("instrument-component-channel-name",
("number", i)), null, true, i);
item.Selected = !_owner.Instrument?.FilteredChannels[i] ?? false;
item.Selected = !instrument?.FilteredChannels[i] ?? false;
}
}
}

View File

@@ -24,8 +24,6 @@ namespace Content.Client.Instruments.UI
[ViewVariables] private BandMenu? _bandMenu;
[ViewVariables] private ChannelsMenu? _channelsMenu;
[ViewVariables] public InstrumentComponent? Instrument { get; private set; }
public InstrumentBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
IoCManager.InjectDependencies(this);
@@ -43,14 +41,20 @@ namespace Content.Client.Instruments.UI
protected override void Open()
{
if (!EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument))
return;
_instrumentMenu = this.CreateWindow<InstrumentMenu>();
_instrumentMenu.Title = EntMan.GetComponent<MetaDataComponent>(Owner).EntityName;
Instrument = instrument;
_instrumentMenu = new InstrumentMenu(this);
_instrumentMenu.OnClose += Close;
_instrumentMenu.OnOpenBand += OpenBandMenu;
_instrumentMenu.OnOpenChannels += OpenChannelsMenu;
_instrumentMenu.OnCloseChannels += CloseChannelsMenu;
_instrumentMenu.OnCloseBands += CloseBandMenu;
_instrumentMenu.OpenCentered();
_instrumentMenu.SetMIDI(MidiManager.IsAvailable);
if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument))
{
_instrumentMenu.SetInstrument((Owner, instrument));
}
}
protected override void Dispose(bool disposing)
@@ -58,7 +62,12 @@ namespace Content.Client.Instruments.UI
base.Dispose(disposing);
if (!disposing)
return;
_instrumentMenu?.Dispose();
if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument))
{
_instrumentMenu?.RemoveInstrument(instrument);
}
_bandMenu?.Dispose();
_channelsMenu?.Dispose();
}
@@ -72,6 +81,11 @@ namespace Content.Client.Instruments.UI
{
_bandMenu ??= new BandMenu(this);
if (EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument))
{
_bandMenu.Master = instrument.Master;
}
// Refresh cache...
RefreshBands();
@@ -87,7 +101,9 @@ namespace Content.Client.Instruments.UI
public void OpenChannelsMenu()
{
_channelsMenu ??= new ChannelsMenu(this);
_channelsMenu.Populate();
EntMan.TryGetComponent(Owner, out InstrumentComponent? instrument);
_channelsMenu.Populate(instrument);
_channelsMenu.OpenCenteredRight();
}

View File

@@ -1,7 +1,10 @@
using System.IO;
using System.Numerics;
using System.Threading.Tasks;
using Content.Client.Interactable;
using Content.Shared.ActionBlocker;
using Robust.Client.AutoGenerated;
using Robust.Client.Player;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
@@ -16,33 +19,23 @@ namespace Content.Client.Instruments.UI
[GenerateTypedNameReferences]
public sealed partial class InstrumentMenu : DefaultWindow
{
private readonly InstrumentBoundUserInterface _owner;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IFileDialogManager _dialogs = default!;
[Dependency] private readonly IPlayerManager _player = default!;
private bool _isMidiFileDialogueWindowOpen;
public InstrumentMenu(InstrumentBoundUserInterface owner)
public event Action? OnOpenBand;
public event Action? OnOpenChannels;
public event Action? OnCloseBands;
public event Action? OnCloseChannels;
public EntityUid Entity;
public InstrumentMenu()
{
RobustXamlLoader.Load(this);
_owner = owner;
if (_owner.Instrument != null)
{
_owner.Instrument.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded;
Title = _owner.Entities.GetComponent<MetaDataComponent>(_owner.Owner).EntityName;
LoopButton.Disabled = !_owner.Instrument.IsMidiOpen;
LoopButton.Pressed = _owner.Instrument.LoopMidi;
ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive;
StopButton.Disabled = !_owner.Instrument.IsMidiOpen;
PlaybackSlider.MouseFilter = _owner.Instrument.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore;
}
if (!_owner.MidiManager.IsAvailable)
{
UnavailableOverlay.Visible = true;
// We return early as to not give the buttons behavior.
return;
}
IoCManager.InjectDependencies(this);
InputButton.OnToggled += MidiInputButtonOnOnToggled;
BandButton.OnPressed += BandButtonOnPressed;
@@ -57,12 +50,34 @@ namespace Content.Client.Instruments.UI
MinSize = SetSize = new Vector2(400, 150);
}
public void SetInstrument(Entity<InstrumentComponent> entity)
{
Entity = entity;
var component = entity.Comp;
component.OnMidiPlaybackEnded += InstrumentOnMidiPlaybackEnded;
LoopButton.Disabled = !component.IsMidiOpen;
LoopButton.Pressed = component.LoopMidi;
ChannelsButton.Disabled = !component.IsRendererAlive;
StopButton.Disabled = !component.IsMidiOpen;
PlaybackSlider.MouseFilter = component.IsMidiOpen ? MouseFilterMode.Pass : MouseFilterMode.Ignore;
}
public void RemoveInstrument(InstrumentComponent component)
{
component.OnMidiPlaybackEnded -= InstrumentOnMidiPlaybackEnded;
}
public void SetMIDI(bool available)
{
UnavailableOverlay.Visible = !available;
}
private void BandButtonOnPressed(ButtonEventArgs obj)
{
if (!PlayCheck())
return;
_owner.OpenBandMenu();
OnOpenBand?.Invoke();
}
private void BandButtonOnToggled(ButtonToggledEventArgs obj)
@@ -70,12 +85,15 @@ namespace Content.Client.Instruments.UI
if (obj.Pressed)
return;
_owner.Instruments.SetMaster(_owner.Owner, null);
if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument))
{
_entManager.System<InstrumentSystem>().SetMaster(Entity, instrument.Master);
}
}
private void ChannelsButtonOnPressed(ButtonEventArgs obj)
{
_owner.OpenChannelsMenu();
OnOpenChannels?.Invoke();
}
private void InstrumentOnMidiPlaybackEnded()
@@ -85,8 +103,10 @@ namespace Content.Client.Instruments.UI
public void MidiPlaybackSetButtonsDisabled(bool disabled)
{
if(disabled)
_owner.CloseChannelsMenu();
if (disabled)
{
OnCloseChannels?.Invoke();
}
LoopButton.Disabled = disabled;
StopButton.Disabled = disabled;
@@ -100,7 +120,7 @@ namespace Content.Client.Instruments.UI
if (_isMidiFileDialogueWindowOpen)
return;
_owner.CloseBandMenu();
OnCloseBands?.Invoke();
var filters = new FileDialogFilters(new FileDialogFilters.Group("mid", "midi"));
@@ -108,7 +128,7 @@ namespace Content.Client.Instruments.UI
// or focus the previously-opened window.
_isMidiFileDialogueWindowOpen = true;
await using var file = await _owner.FileDialogManager.OpenFile(filters);
await using var file = await _dialogs.OpenFile(filters);
_isMidiFileDialogueWindowOpen = false;
@@ -129,9 +149,18 @@ namespace Content.Client.Instruments.UI
await file.CopyToAsync(memStream);
if (_owner.Instrument is not {} instrument
|| !_owner.Instruments.OpenMidi(_owner.Owner, memStream.GetBuffer().AsSpan(0, (int) memStream.Length), instrument))
if (!_entManager.TryGetComponent<InstrumentComponent>(Entity, out var instrument))
{
return;
}
if (!_entManager.System<InstrumentSystem>()
.OpenMidi(Entity,
memStream.GetBuffer().AsSpan(0, (int) memStream.Length),
instrument))
{
return;
}
MidiPlaybackSetButtonsDisabled(false);
if (InputButton.Pressed)
@@ -140,7 +169,7 @@ namespace Content.Client.Instruments.UI
private void MidiInputButtonOnOnToggled(ButtonToggledEventArgs obj)
{
_owner.CloseBandMenu();
OnCloseBands?.Invoke();
if (obj.Pressed)
{
@@ -148,109 +177,99 @@ namespace Content.Client.Instruments.UI
return;
MidiStopButtonOnPressed(null);
if(_owner.Instrument is {} instrument)
_owner.Instruments.OpenInput(_owner.Owner, instrument);
if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument))
_entManager.System<InstrumentSystem>().OpenInput(Entity, instrument);
}
else if (_owner.Instrument is { } instrument)
else
{
_owner.Instruments.CloseInput(_owner.Owner, false, instrument);
_owner.CloseChannelsMenu();
_entManager.System<InstrumentSystem>().CloseInput(Entity, false);
OnCloseChannels?.Invoke();
}
}
private bool PlayCheck()
{
// TODO all of these checks should also be done server-side.
var instrumentEnt = _owner.Owner;
var instrument = _owner.Instrument;
if (instrument == null)
if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument))
return false;
var localEntity = _owner.PlayerManager.LocalEntity;
var localEntity = _player.LocalEntity;
// If we don't have a player or controlled entity, we return.
if (localEntity == null)
return false;
// By default, allow an instrument to play itself and skip all other checks
if (localEntity == instrumentEnt)
if (localEntity == Entity)
return true;
var container = _owner.Entities.System<SharedContainerSystem>();
var container = _entManager.System<SharedContainerSystem>();
// If we're a handheld instrument, we might be in a container. Get it just in case.
container.TryGetContainingContainer(instrumentEnt, out var conMan);
container.TryGetContainingContainer(Entity, out var conMan);
// If the instrument is handheld and we're not holding it, we return.
if ((instrument.Handheld && (conMan == null || conMan.Owner != localEntity)))
if (instrument.Handheld && (conMan == null || conMan.Owner != localEntity))
return false;
if (!_owner.ActionBlocker.CanInteract(localEntity.Value, instrumentEnt))
if (!_entManager.System<ActionBlockerSystem>().CanInteract(localEntity.Value, Entity))
return false;
// We check that we're in range unobstructed just in case.
return _owner.Interactions.InRangeUnobstructed(localEntity.Value, instrumentEnt);
return _entManager.System<InteractionSystem>().InRangeUnobstructed(localEntity.Value, Entity);
}
private void MidiStopButtonOnPressed(ButtonEventArgs? obj)
{
MidiPlaybackSetButtonsDisabled(true);
if (_owner.Instrument is not {} instrument)
return;
_owner.Instruments.CloseMidi(_owner.Owner, false, instrument);
_owner.CloseChannelsMenu();
_entManager.System<InstrumentSystem>().CloseMidi(Entity, false);
OnCloseChannels?.Invoke();
}
private void MidiLoopButtonOnOnToggled(ButtonToggledEventArgs obj)
{
if (_owner.Instrument == null)
return;
var instrument = _entManager.System<InstrumentSystem>();
_owner.Instrument.LoopMidi = obj.Pressed;
_owner.Instruments.UpdateRenderer(_owner.Owner, _owner.Instrument);
if (_entManager.TryGetComponent(Entity, out InstrumentComponent? instrumentComp))
{
instrumentComp.LoopMidi = obj.Pressed;
}
instrument.UpdateRenderer(Entity);
}
private void PlaybackSliderSeek(Range _)
{
// Do not seek while still grabbing.
if (PlaybackSlider.Grabbed || _owner.Instrument is not {} instrument)
if (PlaybackSlider.Grabbed)
return;
_owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument);
_entManager.System<InstrumentSystem>().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value));
}
private void PlaybackSliderKeyUp(GUIBoundKeyEventArgs args)
{
if (args.Function != EngineKeyFunctions.UIClick || _owner.Instrument is not {} instrument)
if (args.Function != EngineKeyFunctions.UIClick)
return;
_owner.Instruments.SetPlayerTick(_owner.Owner, (int)Math.Ceiling(PlaybackSlider.Value), instrument);
}
public override void Close()
{
base.Close();
_owner.CloseBandMenu();
_owner.CloseChannelsMenu();
_entManager.System<InstrumentSystem>().SetPlayerTick(Entity, (int)Math.Ceiling(PlaybackSlider.Value));
}
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if (_owner.Instrument == null)
if (!_entManager.TryGetComponent(Entity, out InstrumentComponent? instrument))
return;
var hasMaster = _owner.Instrument.Master != null;
var hasMaster = instrument.Master != null;
BandButton.ToggleMode = hasMaster;
BandButton.Pressed = hasMaster;
BandButton.Disabled = _owner.Instrument.IsMidiOpen || _owner.Instrument.IsInputOpen;
ChannelsButton.Disabled = !_owner.Instrument.IsRendererAlive;
BandButton.Disabled = instrument.IsMidiOpen || instrument.IsInputOpen;
ChannelsButton.Disabled = !instrument.IsRendererAlive;
if (!_owner.Instrument.IsMidiOpen)
if (!instrument.IsMidiOpen)
{
PlaybackSlider.MaxValue = 1;
PlaybackSlider.SetValueWithoutEvent(0);
@@ -260,8 +279,8 @@ namespace Content.Client.Instruments.UI
if (PlaybackSlider.Grabbed)
return;
PlaybackSlider.MaxValue = _owner.Instrument.PlayerTotalTick;
PlaybackSlider.SetValueWithoutEvent(_owner.Instrument.PlayerTick);
PlaybackSlider.MaxValue = instrument.PlayerTotalTick;
PlaybackSlider.SetValueWithoutEvent(instrument.PlayerTick);
}
}
}

View File

@@ -41,7 +41,7 @@ namespace Content.Client.Inventory
public const string HiddenPocketEntityId = "StrippingHiddenEntity";
[ViewVariables]
private readonly StrippingMenu? _strippingMenu;
private StrippingMenu? _strippingMenu;
[ViewVariables]
private readonly EntityUid _virtualHiddenEntity;
@@ -51,33 +51,30 @@ namespace Content.Client.Inventory
_examine = EntMan.System<ExamineSystem>();
_inv = EntMan.System<InventorySystem>();
_cuffable = EntMan.System<SharedCuffableSystem>();
// TODO update name when identity changes
var title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan)));
_strippingMenu = new StrippingMenu(title, this);
_strippingMenu.OnClose += Close;
// TODO use global entity
// BUIs are opened and closed while applying comp sates, so spawning entities here is probably not the best idea.
_virtualHiddenEntity = EntMan.SpawnEntity(HiddenPocketEntityId, MapCoordinates.Nullspace);
}
protected override void Open()
{
base.Open();
_strippingMenu = this.CreateWindow<StrippingMenu>();
_strippingMenu.OnDirty += UpdateMenu;
_strippingMenu.Title = Loc.GetString("strippable-bound-user-interface-stripping-menu-title", ("ownerName", Identity.Name(Owner, EntMan)));
_strippingMenu?.OpenCenteredLeft();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
EntMan.DeleteEntity(_virtualHiddenEntity);
if (!disposing)
return;
_strippingMenu?.Dispose();
if (_strippingMenu != null)
_strippingMenu.OnDirty -= UpdateMenu;
EntMan.DeleteEntity(_virtualHiddenEntity);
base.Dispose(disposing);
}
public void DirtyMenu()

View File

@@ -12,42 +12,34 @@ namespace Content.Client.Kitchen.UI
[GenerateTypedNameReferences]
public sealed partial class GrinderMenu : FancyWindow
{
private readonly IEntityManager _entityManager;
private readonly IPrototypeManager _prototypeManager;
private readonly ReagentGrinderBoundUserInterface _owner;
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly Dictionary<int, EntityUid> _chamberVisualContents = new();
public GrinderMenu(ReagentGrinderBoundUserInterface owner, IEntityManager entityManager, IPrototypeManager prototypeManager)
public event Action? OnToggleAuto;
public event Action? OnGrind;
public event Action? OnJuice;
public event Action? OnEjectAll;
public event Action? OnEjectBeaker;
public event Action<EntityUid>? OnEjectChamber;
public GrinderMenu()
{
RobustXamlLoader.Load(this);
_entityManager = entityManager;
_prototypeManager = prototypeManager;
_owner = owner;
AutoModeButton.OnPressed += owner.ToggleAutoMode;
GrindButton.OnPressed += owner.StartGrinding;
JuiceButton.OnPressed += owner.StartJuicing;
ChamberContentBox.EjectButton.OnPressed += owner.EjectAll;
BeakerContentBox.EjectButton.OnPressed += owner.EjectBeaker;
IoCManager.InjectDependencies(this);
AutoModeButton.OnPressed += _ => OnToggleAuto?.Invoke();
GrindButton.OnPressed += _ => OnGrind?.Invoke();
JuiceButton.OnPressed += _ => OnJuice?.Invoke();
ChamberContentBox.EjectButton.OnPressed += _ => OnEjectAll?.Invoke();
BeakerContentBox.EjectButton.OnPressed += _ => OnEjectBeaker?.Invoke();
ChamberContentBox.BoxContents.OnItemSelected += OnChamberBoxContentsItemSelected;
BeakerContentBox.BoxContents.SelectMode = ItemList.ItemListSelectMode.None;
}
private void OnChamberBoxContentsItemSelected(ItemList.ItemListSelectedEventArgs args)
{
_owner.EjectChamberContent(_chamberVisualContents[args.ItemIndex]);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
_chamberVisualContents.Clear();
GrindButton.OnPressed -= _owner.StartGrinding;
JuiceButton.OnPressed -= _owner.StartJuicing;
ChamberContentBox.EjectButton.OnPressed -= _owner.EjectAll;
BeakerContentBox.EjectButton.OnPressed -= _owner.EjectBeaker;
ChamberContentBox.BoxContents.OnItemSelected -= OnChamberBoxContentsItemSelected;
OnEjectChamber?.Invoke(_chamberVisualContents[args.ItemIndex]);
}
public void UpdateState(ReagentGrinderInterfaceState state)

View File

@@ -3,6 +3,7 @@ using Content.Shared.Kitchen.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.Graphics;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Timing;
@@ -19,28 +20,15 @@ namespace Content.Client.Kitchen.UI
[ViewVariables]
private readonly Dictionary<int, ReagentQuantity> _reagents = new();
[Dependency] private readonly IGameTiming _gameTiming = default!;
public MicrowaveUpdateUserInterfaceState currentState = default!;
private IEntityManager _entManager;
public MicrowaveBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
_entManager = IoCManager.Resolve<IEntityManager>();
}
public TimeSpan GetCurrentTime()
{
return _gameTiming.CurTime;
}
protected override void Open()
{
base.Open();
_menu = new MicrowaveMenu(this);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu = this.CreateWindow<MicrowaveMenu>();
_menu.StartButton.OnPressed += _ => SendPredictedMessage(new MicrowaveStartCookMessage());
_menu.EjectButton.OnPressed += _ => SendPredictedMessage(new MicrowaveEjectMessage());
_menu.IngredientsList.OnItemSelected += args =>
@@ -74,38 +62,23 @@ namespace Content.Client.Kitchen.UI
};
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
{
return;
}
_solids.Clear();
_menu?.Dispose();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);
if (state is not MicrowaveUpdateUserInterfaceState cState)
if (state is not MicrowaveUpdateUserInterfaceState cState || _menu == null)
{
return;
}
_menu.IsBusy = cState.IsMicrowaveBusy;
_menu.CurrentCooktimeEnd = cState.CurrentCookTimeEnd;
_menu?.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0);
currentState = cState;
_menu.ToggleBusyDisableOverlayPanel(cState.IsMicrowaveBusy || cState.ContainedSolids.Length == 0);
// TODO move this to a component state and ensure the net ids.
RefreshContentsDisplay(_entManager.GetEntityArray(cState.ContainedSolids));
if (_menu == null) return;
RefreshContentsDisplay(EntMan.GetEntityArray(cState.ContainedSolids));
//Set the cook time info label
var cookTime = cState.ActiveButtonIndex == 0
var cookTime = cState.ActiveButtonIndex == 0
? Loc.GetString("microwave-menu-instant-button")
: cState.CurrentCookTime.ToString();

View File

@@ -9,22 +9,21 @@ namespace Content.Client.Kitchen.UI
[GenerateTypedNameReferences]
public sealed partial class MicrowaveMenu : FancyWindow
{
public sealed class MicrowaveCookTimeButton : Button
{
public uint CookTime;
}
[Dependency] private readonly IGameTiming _timing = default!;
public event Action<BaseButton.ButtonEventArgs, int>? OnCookTimeSelected;
public ButtonGroup CookTimeButtonGroup { get; }
private readonly MicrowaveBoundUserInterface _owner;
public MicrowaveMenu(MicrowaveBoundUserInterface owner)
public bool IsBusy;
public TimeSpan CurrentCooktimeEnd;
public MicrowaveMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
CookTimeButtonGroup = new ButtonGroup();
InstantCookButton.Group = CookTimeButtonGroup;
_owner = owner;
InstantCookButton.OnPressed += args =>
{
OnCookTimeSelected?.Invoke(args, 0);
@@ -65,14 +64,20 @@ namespace Content.Client.Kitchen.UI
protected override void FrameUpdate(FrameEventArgs args)
{
base.FrameUpdate(args);
if(!_owner.currentState.IsMicrowaveBusy)
if (!IsBusy)
return;
if(_owner.currentState.CurrentCookTimeEnd > _owner.GetCurrentTime())
if (CurrentCooktimeEnd > _timing.CurTime)
{
CookTimeInfoLabel.Text = Loc.GetString("microwave-bound-user-interface-cook-time-label",
("time",_owner.currentState.CurrentCookTimeEnd.Subtract(_owner.GetCurrentTime()).Seconds));
("time", CurrentCooktimeEnd.Subtract(_timing.CurTime).Seconds));
}
}
public sealed class MicrowaveCookTimeButton : Button
{
public uint CookTime;
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Containers.ItemSlots;
using Content.Shared.Kitchen;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Shared.Prototypes;
@@ -8,8 +9,6 @@ namespace Content.Client.Kitchen.UI
{
public sealed class ReagentGrinderBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
[ViewVariables]
private GrinderMenu? _menu;
@@ -21,20 +20,13 @@ namespace Content.Client.Kitchen.UI
{
base.Open();
_menu = new GrinderMenu(this, EntMan, _prototypeManager);
_menu.OpenCentered();
_menu.OnClose += Close;
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
{
return;
}
_menu?.Dispose();
_menu = this.CreateWindow<GrinderMenu>();
_menu.OnToggleAuto += ToggleAutoMode;
_menu.OnGrind += StartGrinding;
_menu.OnJuice += StartJuicing;
_menu.OnEjectAll += EjectAll;
_menu.OnEjectBeaker += EjectBeaker;
_menu.OnEjectChamber += EjectChamberContent;
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -52,27 +44,27 @@ namespace Content.Client.Kitchen.UI
_menu?.HandleMessage(message);
}
public void ToggleAutoMode(BaseButton.ButtonEventArgs args)
public void ToggleAutoMode()
{
SendMessage(new ReagentGrinderToggleAutoModeMessage());
}
public void StartGrinding(BaseButton.ButtonEventArgs? _ = null)
public void StartGrinding()
{
SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Grind));
}
public void StartJuicing(BaseButton.ButtonEventArgs? _ = null)
public void StartJuicing()
{
SendMessage(new ReagentGrinderStartMessage(GrinderProgram.Juice));
}
public void EjectAll(BaseButton.ButtonEventArgs? _ = null)
public void EjectAll()
{
SendMessage(new ReagentGrinderEjectChamberAllMessage());
}
public void EjectBeaker(BaseButton.ButtonEventArgs? _ = null)
public void EjectBeaker()
{
SendMessage(new ItemSlotButtonPressedEvent(SharedReagentGrinder.BeakerSlotId));
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Labels;
using Content.Shared.Labels.Components;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Labels.UI
{
@@ -23,13 +24,8 @@ namespace Content.Client.Labels.UI
{
base.Open();
_window = new HandLabelerWindow();
if (State != null)
UpdateState(State);
_window = this.CreateWindow<HandLabelerWindow>();
_window.OpenCentered();
_window.OnClose += Close;
_window.OnLabelChanged += OnLabelChanged;
Reload();
}
@@ -51,13 +47,5 @@ namespace Content.Client.Labels.UI
_window.SetCurrentLabel(component.AssignedLabel);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}
}

View File

@@ -1,6 +1,7 @@
using Content.Shared.Lathe;
using Content.Shared.Research.Components;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
namespace Content.Client.Lathe.UI
{
@@ -17,9 +18,9 @@ namespace Content.Client.Lathe.UI
{
base.Open();
_menu = new LatheMenu(this);
_menu.OnClose += Close;
_menu = this.CreateWindow<LatheMenu>();
_menu.SetEntity(Owner);
_menu.OpenCenteredRight();
_menu.OnServerListButtonPressed += _ =>
{
@@ -30,8 +31,6 @@ namespace Content.Client.Lathe.UI
{
SendMessage(new LatheQueueRecipeMessage(recipe, amount));
};
_menu.OpenCenteredRight();
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -50,13 +49,5 @@ namespace Content.Client.Lathe.UI
break;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}
}

View File

@@ -1,3 +1,4 @@
using System.Buffers;
using System.Linq;
using System.Text;
using Content.Client.Materials;
@@ -22,7 +23,6 @@ public sealed partial class LatheMenu : DefaultWindow
[Dependency] private readonly IEntityManager _entityManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private EntityUid _owner;
private readonly SpriteSystem _spriteSystem;
private readonly LatheSystem _lathe;
private readonly MaterialStorageSystem _materialStorage;
@@ -36,9 +36,10 @@ public sealed partial class LatheMenu : DefaultWindow
public ProtoId<LatheCategoryPrototype>? CurrentCategory;
public LatheMenu(LatheBoundUserInterface owner)
public EntityUid Entity;
public LatheMenu()
{
_owner = owner.Owner;
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
@@ -46,8 +47,6 @@ public sealed partial class LatheMenu : DefaultWindow
_lathe = _entityManager.System<LatheSystem>();
_materialStorage = _entityManager.System<MaterialStorageSystem>();
Title = _entityManager.GetComponent<MetaDataComponent>(owner.Owner).EntityName;
SearchBar.OnTextChanged += _ =>
{
PopulateRecipes();
@@ -60,8 +59,13 @@ public sealed partial class LatheMenu : DefaultWindow
FilterOption.OnItemSelected += OnItemSelected;
ServerListButton.OnPressed += a => OnServerListButtonPressed?.Invoke(a);
}
if (_entityManager.TryGetComponent<LatheComponent>(owner.Owner, out var latheComponent))
public void SetEntity(EntityUid uid)
{
Entity = uid;
if (_entityManager.TryGetComponent<LatheComponent>(Entity, out var latheComponent))
{
if (!latheComponent.DynamicRecipes.Any())
{
@@ -69,7 +73,7 @@ public sealed partial class LatheMenu : DefaultWindow
}
}
MaterialsList.SetOwner(owner.Owner);
MaterialsList.SetOwner(Entity);
}
/// <summary>
@@ -102,13 +106,15 @@ public sealed partial class LatheMenu : DefaultWindow
var sortedRecipesToShow = recipesToShow.OrderBy(p => p.Name);
RecipeList.Children.Clear();
_entityManager.TryGetComponent(Entity, out LatheComponent? lathe);
foreach (var prototype in sortedRecipesToShow)
{
EntityPrototype? recipeProto = null;
if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto) && entityProto != null)
if (_prototypeManager.TryIndex(prototype.Result, out EntityPrototype? entityProto))
recipeProto = entityProto;
var canProduce = _lathe.CanProduce(_owner, prototype, quantity);
var canProduce = _lathe.CanProduce(Entity, prototype, quantity, component: lathe);
var control = new RecipeControl(prototype, () => GenerateTooltipText(prototype), canProduce, recipeProto);
control.OnButtonPressed += s =>
@@ -124,19 +130,20 @@ public sealed partial class LatheMenu : DefaultWindow
private string GenerateTooltipText(LatheRecipePrototype prototype)
{
StringBuilder sb = new();
var multiplier = _entityManager.GetComponent<LatheComponent>(Entity).MaterialUseMultiplier;
foreach (var (id, amount) in prototype.RequiredMaterials)
{
if (!_prototypeManager.TryIndex<MaterialPrototype>(id, out var proto))
continue;
var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, _entityManager.GetComponent<LatheComponent>(_owner).MaterialUseMultiplier);
var adjustedAmount = SharedLatheSystem.AdjustMaterial(amount, prototype.ApplyMaterialDiscount, multiplier);
var sheetVolume = _materialStorage.GetSheetVolume(proto);
var unit = Loc.GetString(proto.Unit);
var sheets = adjustedAmount / (float) sheetVolume;
var availableAmount = _materialStorage.GetMaterialAmount(_owner, id);
var availableAmount = _materialStorage.GetMaterialAmount(Entity, id);
var missingAmount = Math.Max(0, adjustedAmount - availableAmount);
var missingSheets = missingAmount / (float) sheetVolume;

View File

@@ -1,5 +1,6 @@
using Content.Shared.MachineLinking;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Shared.Timing;
namespace Content.Client.MachineLinking.UI;
@@ -19,19 +20,14 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new SignalTimerWindow(this);
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<SignalTimerWindow>();
_window.OnStartTimer += StartTimer;
_window.OnCurrentTextChanged += OnTextChanged;
_window.OnCurrentDelayMinutesChanged += OnDelayChanged;
_window.OnCurrentDelaySecondsChanged += OnDelayChanged;
}
public void OnStartTimer()
public void StartTimer()
{
SendMessage(new SignalTimerStartMessage());
}
@@ -48,11 +44,6 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
SendMessage(new SignalTimerDelayChangedMessage(_window.GetDelay()));
}
public TimeSpan GetCurrentTime()
{
return _gameTiming.CurTime;
}
/// <summary>
/// Update the UI state based on server-sent info
/// </summary>
@@ -72,11 +63,4 @@ public sealed class SignalTimerBoundUserInterface : BoundUserInterface
_window.SetTimerStarted(cast.TimerStarted);
_window.SetHasAccess(cast.HasAccess);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_window?.Dispose();
}
}

View File

@@ -9,42 +9,44 @@ namespace Content.Client.MachineLinking.UI;
[GenerateTypedNameReferences]
public sealed partial class SignalTimerWindow : DefaultWindow
{
[Dependency] private readonly IGameTiming _timing = default!;
private const int MaxTextLength = 5;
public event Action<string>? OnCurrentTextChanged;
public event Action<string>? OnCurrentDelayMinutesChanged;
public event Action<string>? OnCurrentDelaySecondsChanged;
private readonly SignalTimerBoundUserInterface _owner;
private TimeSpan? _triggerTime;
private bool _timerStarted;
public SignalTimerWindow(SignalTimerBoundUserInterface owner)
public event Action? OnStartTimer;
public SignalTimerWindow()
{
RobustXamlLoader.Load(this);
_owner = owner;
IoCManager.InjectDependencies(this);
CurrentTextEdit.OnTextChanged += e => OnCurrentTextChange(e.Text);
CurrentDelayEditMinutes.OnTextChanged += e => OnCurrentDelayMinutesChange(e.Text);
CurrentDelayEditSeconds.OnTextChanged += e => OnCurrentDelaySecondsChange(e.Text);
StartTimer.OnPressed += _ => OnStartTimer();
StartTimer.OnPressed += _ => StartTimerWeh();
}
public void OnStartTimer()
private void StartTimerWeh()
{
if (!_timerStarted)
{
_timerStarted = true;
_triggerTime = _owner.GetCurrentTime() + GetDelay();
_triggerTime = _timing.CurTime + GetDelay();
}
else
{
SetTimerStarted(false);
}
_owner.OnStartTimer();
OnStartTimer?.Invoke();
}
protected override void FrameUpdate(FrameEventArgs args)
@@ -54,9 +56,9 @@ public sealed partial class SignalTimerWindow : DefaultWindow
if (!_timerStarted || _triggerTime == null)
return;
if (_owner.GetCurrentTime() < _triggerTime.Value)
if (_timing.CurTime < _triggerTime.Value)
{
StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _owner.GetCurrentTime());
StartTimer.Text = TextScreenSystem.TimeToString(_triggerTime.Value - _timing.CurTime);
}
else
{

View File

@@ -1,6 +1,7 @@
using Content.Shared.Humanoid.Markings;
using Content.Shared.MagicMirror;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.MagicMirror;
@@ -17,7 +18,7 @@ public sealed class MagicMirrorBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new();
_window = this.CreateWindow<MagicMirrorWindow>();
_window.OnHairSelected += tuple => SelectHair(MagicMirrorCategory.Hair, tuple.id, tuple.slot);
_window.OnHairColorChanged += args => ChangeColor(MagicMirrorCategory.Hair, args.marking, args.slot);
@@ -29,9 +30,6 @@ public sealed class MagicMirrorBoundUserInterface : BoundUserInterface
args => ChangeColor(MagicMirrorCategory.FacialHair, args.marking, args.slot);
_window.OnFacialHairSlotAdded += delegate () { AddSlot(MagicMirrorCategory.FacialHair); };
_window.OnFacialHairSlotRemoved += args => RemoveSlot(MagicMirrorCategory.FacialHair, args);
_window.OnClose += Close;
_window.OpenCentered();
}
private void SelectHair(MagicMirrorCategory category, string marking, int slot)
@@ -65,14 +63,5 @@ public sealed class MagicMirrorBoundUserInterface : BoundUserInterface
_window.UpdateState(data);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_window?.Dispose();
}
}

View File

@@ -1,6 +1,7 @@
using JetBrains.Annotations;
using Content.Shared.MassMedia.Systems;
using Content.Shared.MassMedia.Components;
using Robust.Client.UserInterface;
using Robust.Shared.Timing;
using Robust.Shared.Utility;
@@ -9,8 +10,6 @@ namespace Content.Client.MassMedia.Ui;
[UsedImplicitly]
public sealed class NewsWriterBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IGameTiming _gameTiming = default!;
[ViewVariables]
private NewsWriterMenu? _menu;
@@ -21,10 +20,7 @@ public sealed class NewsWriterBoundUserInterface : BoundUserInterface
protected override void Open()
{
_menu = new NewsWriterMenu(_gameTiming);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu = this.CreateWindow<NewsWriterMenu>();
_menu.ArticleEditorPanel.PublishButtonPressed += OnPublishButtonPressed;
_menu.DeleteButtonPressed += OnDeleteButtonPressed;
@@ -32,16 +28,6 @@ public sealed class NewsWriterBoundUserInterface : BoundUserInterface
SendMessage(new NewsWriterArticlesRequestMessage());
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
_menu?.Dispose();
}
protected override void UpdateState(BoundUserInterfaceState state)
{
base.UpdateState(state);

View File

@@ -10,17 +10,17 @@ namespace Content.Client.MassMedia.Ui;
[GenerateTypedNameReferences]
public sealed partial class NewsWriterMenu : FancyWindow
{
private readonly IGameTiming _gameTiming;
[Dependency] private readonly IGameTiming _gameTiming = default!;
private TimeSpan? _nextPublish;
public event Action<int>? DeleteButtonPressed;
public NewsWriterMenu(IGameTiming gameTiming)
public NewsWriterMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_gameTiming = gameTiming;
ContentsContainer.RectClipContent = false;
// Customize scrollbar width and margin. This is not possible in xaml

View File

@@ -3,6 +3,7 @@ using Content.Shared.Mech;
using Content.Shared.Mech.Components;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Mech.Ui;
@@ -20,9 +21,8 @@ public sealed class MechBoundUserInterface : BoundUserInterface
{
base.Open();
_menu = new(Owner);
_menu.OnClose += Close;
_menu = this.CreateWindow<MechMenu>();
_menu.SetEntity(Owner);
_menu.OpenCenteredLeft();
_menu.OnRemoveButtonPressed += uid =>
@@ -60,16 +60,6 @@ public sealed class MechBoundUserInterface : BoundUserInterface
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
}
public UIFragment? GetEquipmentUi(EntityUid? uid)
{
var component = EntMan.GetComponentOrNull<UIFragmentComponent>(uid);

View File

@@ -12,18 +12,20 @@ public sealed partial class MechMenu : FancyWindow
{
[Dependency] private readonly IEntityManager _ent = default!;
private readonly EntityUid _mech;
private EntityUid _mech;
public event Action<EntityUid>? OnRemoveButtonPressed;
public MechMenu(EntityUid mech)
public MechMenu()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
}
_mech = mech;
MechView.SetEntity(mech);
public void SetEntity(EntityUid uid)
{
MechView.SetEntity(uid);
_mech = uid;
}
public void UpdateMechStats()

View File

@@ -1,4 +1,5 @@
using Content.Shared.Medical.CrewMonitoring;
using Robust.Client.UserInterface;
namespace Content.Client.Medical.CrewMonitoring;
@@ -14,7 +15,7 @@ public sealed class CrewMonitoringBoundUserInterface : BoundUserInterface
protected override void Open()
{
EntityUid? gridUid = null;
string stationName = string.Empty;
var stationName = string.Empty;
if (EntMan.TryGetComponent<TransformComponent>(Owner, out var xform))
{
@@ -26,10 +27,8 @@ public sealed class CrewMonitoringBoundUserInterface : BoundUserInterface
}
}
_menu = new CrewMonitoringWindow(stationName, gridUid);
_menu.OpenCentered();
_menu.OnClose += Close;
_menu = this.CreateWindow<CrewMonitoringWindow>();
_menu.Set(stationName, gridUid);
}
protected override void UpdateState(BoundUserInterfaceState state)
@@ -44,13 +43,4 @@ public sealed class CrewMonitoringBoundUserInterface : BoundUserInterface
break;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
}

View File

@@ -23,22 +23,27 @@ namespace Content.Client.Medical.CrewMonitoring;
[GenerateTypedNameReferences]
public sealed partial class CrewMonitoringWindow : FancyWindow
{
private readonly IEntityManager _entManager;
private readonly IPrototypeManager _prototypeManager;
[Dependency] private readonly IEntityManager _entManager = default!;
[Dependency] private readonly IPrototypeManager _prototypeManager = default!;
private readonly SpriteSystem _spriteSystem;
private NetEntity? _trackedEntity;
private bool _tryToScrollToListFocus;
private Texture? _blipTexture;
public CrewMonitoringWindow(string stationName, EntityUid? mapUid)
public CrewMonitoringWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
_entManager = IoCManager.Resolve<IEntityManager>();
_prototypeManager = IoCManager.Resolve<IPrototypeManager>();
_spriteSystem = _entManager.System<SpriteSystem>();
NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
}
public void Set(string stationName, EntityUid? mapUid)
{
_blipTexture = _spriteSystem.Frame0(new SpriteSpecifier.Texture(new ResPath("/Textures/Interface/NavMap/beveled_circle.png")));
if (_entManager.TryGetComponent<TransformComponent>(mapUid, out var xform))
@@ -49,8 +54,6 @@ public sealed partial class CrewMonitoringWindow : FancyWindow
StationName.AddStyleClass("LabelBig");
StationName.Text = stationName;
NavMap.TrackedEntitySelectedAction += SetTrackedEntityFromNavMap;
NavMap.ForceNavMapUpdate();
}

View File

@@ -1,6 +1,7 @@
using Content.Client.NetworkConfigurator.Systems;
using Content.Shared.DeviceNetwork;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.NetworkConfigurator;
@@ -35,14 +36,12 @@ public sealed class NetworkConfiguratorBoundUserInterface : BoundUserInterface
switch (UiKey)
{
case NetworkConfiguratorUiKey.List:
_listMenu = new NetworkConfiguratorListMenu(this);
_listMenu.OnClose += Close;
_listMenu = this.CreateWindow<NetworkConfiguratorListMenu>();
_listMenu.ClearButton.OnPressed += _ => OnClearButtonPressed();
_listMenu.OpenCenteredRight();
_listMenu.OnRemoveAddress += OnRemoveButtonPressed;
break;
case NetworkConfiguratorUiKey.Configure:
_configurationMenu = new NetworkConfiguratorConfigurationMenu();
_configurationMenu.OnClose += Close;
_configurationMenu = this.CreateWindow<NetworkConfiguratorConfigurationMenu>();
_configurationMenu.Set.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Set);
_configurationMenu.Add.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Add);
//_configurationMenu.Edit.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Edit);
@@ -50,12 +49,24 @@ public sealed class NetworkConfiguratorBoundUserInterface : BoundUserInterface
_configurationMenu.Copy.OnPressed += _ => OnConfigButtonPressed(NetworkConfiguratorButtonKey.Copy);
_configurationMenu.Show.OnPressed += OnShowPressed;
_configurationMenu.Show.Pressed = _netConfig.ConfiguredListIsTracked(Owner);
_configurationMenu.OpenCentered();
_configurationMenu.OnRemoveAddress += OnRemoveButtonPressed;
break;
case NetworkConfiguratorUiKey.Link:
_linkMenu = new NetworkConfiguratorLinkMenu(this);
_linkMenu.OnClose += Close;
_linkMenu.OpenCentered();
_linkMenu = this.CreateWindow<NetworkConfiguratorLinkMenu>();
_linkMenu.OnLinkDefaults += args =>
{
SendMessage(new NetworkConfiguratorLinksSaveMessage(args));
};
_linkMenu.OnToggleLink += (left, right) =>
{
SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right));
};
_linkMenu.OnClearLinks += () =>
{
SendMessage(new NetworkConfiguratorClearLinksMessage());
};
break;
}
}
@@ -83,16 +94,6 @@ public sealed class NetworkConfiguratorBoundUserInterface : BoundUserInterface
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing) return;
_linkMenu?.Dispose();
_listMenu?.Dispose();
_configurationMenu?.Dispose();
}
private void OnClearButtonPressed()
{
SendMessage(new NetworkConfiguratorClearDevicesMessage());

View File

@@ -9,17 +9,23 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorConfigurationMenu : FancyWindow
{
public event Action<string>? OnRemoveAddress;
public NetworkConfiguratorConfigurationMenu()
{
RobustXamlLoader.Load(this);
Clear.StyleClasses.Add(StyleBase.ButtonOpenLeft);
Clear.StyleClasses.Add(StyleNano.StyleClassButtonColorRed);
DeviceList.OnRemoveAddress += args =>
{
OnRemoveAddress?.Invoke(args);
};
}
public void UpdateState(DeviceListUserInterfaceState state)
{
DeviceList.UpdateState(null, state.DeviceList);
DeviceList.UpdateState(state.DeviceList, false);
Count.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count));
}

View File

@@ -7,17 +7,19 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorDeviceList : ScrollContainer
{
public void UpdateState(NetworkConfiguratorBoundUserInterface? ui, HashSet<(string address, string name)> devices)
public event Action<string>? OnRemoveAddress;
public void UpdateState(HashSet<(string address, string name)> devices, bool ui)
{
DeviceList.RemoveAllChildren();
foreach (var device in devices)
{
DeviceList.AddChild(BuildDeviceListRow(ui, device));
DeviceList.AddChild(BuildDeviceListRow(device, ui));
}
}
private static BoxContainer BuildDeviceListRow(NetworkConfiguratorBoundUserInterface? ui, (string address, string name) savedDevice)
private BoxContainer BuildDeviceListRow((string address, string name) savedDevice, bool ui)
{
var row = new BoxContainer()
{
@@ -48,10 +50,10 @@ public sealed partial class NetworkConfiguratorDeviceList : ScrollContainer
row.AddChild(name);
row.AddChild(address);
if (ui != null)
if (ui)
{
row.AddChild(removeButton);
removeButton.OnPressed += _ => ui.OnRemoveButtonPressed(savedDevice.address);
removeButton.OnPressed += _ => OnRemoveAddress?.Invoke(savedDevice.address);
}
return row;

View File

@@ -18,20 +18,20 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
private readonly LinksRender _links;
private readonly List<SourcePortPrototype> _sources = new();
private readonly List<SinkPortPrototype> _sinks = new();
private readonly NetworkConfiguratorBoundUserInterface _userInterface;
private (ButtonPosition position, string id, int index)? _selectedButton;
private List<(string left, string right)>? _defaults;
public NetworkConfiguratorLinkMenu(NetworkConfiguratorBoundUserInterface userInterface)
public event Action? OnClearLinks;
public event Action<string, string>? OnToggleLink;
public event Action<List<(string left, string right)>>? OnLinkDefaults;
public NetworkConfiguratorLinkMenu()
{
_userInterface = userInterface;
RobustXamlLoader.Load(this);
var footerStyleBox = new StyleBoxFlat()
@@ -52,7 +52,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
ButtonOk.OnPressed += _ => Close();
ButtonLinkDefault.OnPressed += _ => LinkDefaults();
ButtonClear.OnPressed += _ => _userInterface.SendMessage(new NetworkConfiguratorClearLinksMessage());
ButtonClear.OnPressed += _ => OnClearLinks?.Invoke();
}
public void UpdateState(DeviceLinkUserInterfaceState linkState)
@@ -98,7 +98,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
if (_defaults == default)
return;
_userInterface.SendMessage(new NetworkConfiguratorLinksSaveMessage(_defaults));
OnLinkDefaults?.Invoke(_defaults);
}
private Button CreateButton(ButtonPosition position, string name, string description, string id, int index)
@@ -138,7 +138,7 @@ public sealed partial class NetworkConfiguratorLinkMenu : FancyWindow
var left = _selectedButton.Value.position == ButtonPosition.Left ? _selectedButton.Value.id : id;
var right = _selectedButton.Value.position == ButtonPosition.Left ? id : _selectedButton.Value.id;
_userInterface.SendMessage(new NetworkConfiguratorToggleLinkMessage(left, right));
OnToggleLink?.Invoke(left, right);
args.Button.Pressed = false;

View File

@@ -9,17 +9,20 @@ namespace Content.Client.NetworkConfigurator;
[GenerateTypedNameReferences]
public sealed partial class NetworkConfiguratorListMenu : FancyWindow
{
private readonly NetworkConfiguratorBoundUserInterface _ui;
public NetworkConfiguratorListMenu(NetworkConfiguratorBoundUserInterface ui)
public event Action<string>? OnRemoveAddress;
public NetworkConfiguratorListMenu()
{
RobustXamlLoader.Load(this);
_ui = ui;
DeviceList.OnRemoveAddress += args =>
{
OnRemoveAddress?.Invoke(args);
};
}
public void UpdateState(NetworkConfiguratorUserInterfaceState state)
{
DeviceCountLabel.Text = Loc.GetString("network-configurator-ui-count-label", ("count", state.DeviceList.Count));
DeviceList.UpdateState(_ui, state.DeviceList);
DeviceList.UpdateState(state.DeviceList, true);
}
}

View File

@@ -2,6 +2,7 @@ using Content.Shared.Containers.ItemSlots;
using Content.Shared.Nuke;
using JetBrains.Annotations;
using Robust.Client.GameObjects;
using Robust.Client.UserInterface;
namespace Content.Client.Nuke
{
@@ -11,15 +12,13 @@ namespace Content.Client.Nuke
[ViewVariables]
private NukeMenu? _menu;
public NukeBoundUserInterface([NotNull] EntityUid owner, [NotNull] Enum uiKey) : base(owner, uiKey)
public NukeBoundUserInterface(EntityUid owner, Enum uiKey) : base(owner, uiKey)
{
}
protected override void Open()
{
_menu = new NukeMenu();
_menu.OpenCentered();
_menu.OnClose += Close;
_menu = this.CreateWindow<NukeMenu>();
_menu.OnKeypadButtonPressed += i =>
{
@@ -62,15 +61,5 @@ namespace Content.Client.Nuke
break;
}
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Close();
_menu?.Dispose();
}
}
}

View File

@@ -2,6 +2,7 @@
using Content.Shared.Chat;
using Content.Shared.NukeOps;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Shared.Configuration;
using Robust.Shared.Timing;
@@ -11,8 +12,6 @@ namespace Content.Client.NukeOps;
public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
{
[Dependency] private readonly IConfigurationManager _cfg = default!;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
[ViewVariables]
private WarDeclaratorWindow? _window;
@@ -23,13 +22,7 @@ public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
{
base.Open();
_window = new WarDeclaratorWindow(_gameTiming, _localizationManager);
if (State != null)
UpdateState(State);
_window.OpenCentered();
_window.OnClose += Close;
_window = this.CreateWindow<WarDeclaratorWindow>();
_window.OnActivated += OnWarDeclaratorActivated;
}
@@ -42,13 +35,6 @@ public sealed class WarDeclaratorBoundUserInterface : BoundUserInterface
_window?.UpdateState(cast);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (disposing)
_window?.Dispose();
}
private void OnWarDeclaratorActivated(string message)
{
var maxLength = _cfg.GetCVar(CCVars.ChatMaxAnnouncementLength);

View File

@@ -11,7 +11,8 @@ namespace Content.Client.NukeOps;
[GenerateTypedNameReferences]
public sealed partial class WarDeclaratorWindow : FancyWindow
{
private readonly IGameTiming _gameTiming;
[Dependency] private readonly IGameTiming _gameTiming = default!;
[Dependency] private readonly ILocalizationManager _localizationManager = default!;
public event Action<string>? OnActivated;
@@ -19,15 +20,14 @@ public sealed partial class WarDeclaratorWindow : FancyWindow
private TimeSpan _shuttleDisabledTime;
private WarConditionStatus _status;
public WarDeclaratorWindow(IGameTiming gameTiming, ILocalizationManager localizationManager)
public WarDeclaratorWindow()
{
RobustXamlLoader.Load(this);
_gameTiming = gameTiming;
IoCManager.InjectDependencies(this);
WarButton.OnPressed += (_) => OnActivated?.Invoke(Rope.Collapse(MessageEdit.TextRope));
MessageEdit.Placeholder = new Rope.Leaf(localizationManager.GetString("war-declarator-message-placeholder"));
MessageEdit.Placeholder = new Rope.Leaf(_localizationManager.GetString("war-declarator-message-placeholder"));
}
protected override void FrameUpdate(FrameEventArgs args)

View File

@@ -24,14 +24,13 @@ namespace Content.Client.PDA
if (_menu == null)
CreateMenu();
_menu?.OpenCenteredLeft();
}
private void CreateMenu()
{
_menu = new PdaMenu();
_menu.OnClose += Close;
_menu = this.CreateWindow<PdaMenu>();
_menu.OpenCenteredLeft();
_menu.FlashLightToggleButton.OnToggled += _ =>
{
SendMessage(new PdaToggleFlashlightMessage());
@@ -96,7 +95,6 @@ namespace Content.Client.PDA
_menu?.UpdateState(updateState);
}
protected override void AttachCartridgeUI(Control cartridgeUIFragment, string? title)
{
_menu?.ProgramView.AddChild(cartridgeUIFragment);
@@ -118,15 +116,6 @@ namespace Content.Client.PDA
_menu?.UpdateAvailablePrograms(programs);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (!disposing)
return;
_menu?.Dispose();
}
private PdaBorderColorComponent? GetBorderColorComponent()
{
return EntMan.GetComponentOrNull<PdaBorderColorComponent>(Owner);

View File

@@ -1,6 +1,7 @@
using Content.Shared.PDA;
using Content.Shared.PDA.Ringer;
using JetBrains.Annotations;
using Robust.Client.UserInterface;
using Robust.Shared.Timing;
namespace Content.Client.PDA.Ringer
@@ -18,9 +19,8 @@ namespace Content.Client.PDA.Ringer
protected override void Open()
{
base.Open();
_menu = new RingtoneMenu();
_menu = this.CreateWindow<RingtoneMenu>();
_menu.OpenToLeft();
_menu.OnClose += Close;
_menu.TestRingerButton.OnPressed += _ =>
{

Some files were not shown because too many files have changed in this diff Show More