341 lines
11 KiB
C#
341 lines
11 KiB
C#
using Content.Client.Computer;
|
|
using Content.Client.UserInterface.Controls;
|
|
using Content.Shared.Shuttles.BUIStates;
|
|
using Content.Shared.Shuttles.Components;
|
|
using Content.Shared.Shuttles.Systems;
|
|
using Robust.Client.AutoGenerated;
|
|
using Robust.Client.Graphics;
|
|
using Robust.Client.UserInterface;
|
|
using Robust.Client.UserInterface.Controls;
|
|
using Robust.Client.UserInterface.XAML;
|
|
using Robust.Shared.Map;
|
|
using Robust.Shared.Physics.Components;
|
|
using Robust.Shared.Timing;
|
|
using Robust.Shared.Utility;
|
|
|
|
namespace Content.Client.Shuttles.UI;
|
|
|
|
[GenerateTypedNameReferences]
|
|
public sealed partial class ShuttleConsoleWindow : FancyWindow,
|
|
IComputerWindow<ShuttleConsoleBoundInterfaceState>
|
|
{
|
|
private readonly IEntityManager _entManager;
|
|
private readonly IGameTiming _timing;
|
|
|
|
private EntityUid? _shuttleEntity;
|
|
|
|
/// <summary>
|
|
/// Currently selected dock button for camera.
|
|
/// </summary>
|
|
private BaseButton? _selectedDock;
|
|
|
|
/// <summary>
|
|
/// Stored by grid entityid then by states
|
|
/// </summary>
|
|
private readonly Dictionary<NetEntity, List<DockingInterfaceState>> _docks = new();
|
|
|
|
private readonly Dictionary<BaseButton, NetEntity> _destinations = new();
|
|
|
|
/// <summary>
|
|
/// Next FTL state change.
|
|
/// </summary>
|
|
public TimeSpan FTLTime;
|
|
|
|
public Action<NetEntity>? UndockPressed;
|
|
public Action<NetEntity>? StartAutodockPressed;
|
|
public Action<NetEntity>? StopAutodockPressed;
|
|
public Action<NetEntity>? DestinationPressed;
|
|
|
|
public ShuttleConsoleWindow()
|
|
{
|
|
RobustXamlLoader.Load(this);
|
|
_entManager = IoCManager.Resolve<IEntityManager>();
|
|
_timing = IoCManager.Resolve<IGameTiming>();
|
|
|
|
WorldRangeChange(RadarScreen.WorldRange);
|
|
RadarScreen.WorldRangeChanged += WorldRangeChange;
|
|
|
|
IFFToggle.OnToggled += OnIFFTogglePressed;
|
|
IFFToggle.Pressed = RadarScreen.ShowIFF;
|
|
|
|
DockToggle.OnToggled += OnDockTogglePressed;
|
|
DockToggle.Pressed = RadarScreen.ShowDocks;
|
|
|
|
UndockButton.OnPressed += OnUndockPressed;
|
|
}
|
|
|
|
private void WorldRangeChange(float value)
|
|
{
|
|
RadarRange.Text = $"{value:0}";
|
|
}
|
|
|
|
private void OnIFFTogglePressed(BaseButton.ButtonEventArgs args)
|
|
{
|
|
RadarScreen.ShowIFF ^= true;
|
|
args.Button.Pressed = RadarScreen.ShowIFF;
|
|
}
|
|
|
|
private void OnDockTogglePressed(BaseButton.ButtonEventArgs args)
|
|
{
|
|
RadarScreen.ShowDocks ^= true;
|
|
args.Button.Pressed = RadarScreen.ShowDocks;
|
|
}
|
|
|
|
private void OnUndockPressed(BaseButton.ButtonEventArgs args)
|
|
{
|
|
if (DockingScreen.ViewedDock == null) return;
|
|
UndockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
|
}
|
|
|
|
public void SetMatrix(EntityCoordinates? coordinates, Angle? angle)
|
|
{
|
|
_shuttleEntity = coordinates?.EntityId;
|
|
RadarScreen.SetMatrix(coordinates, angle);
|
|
}
|
|
|
|
public void UpdateState(ShuttleConsoleBoundInterfaceState scc)
|
|
{
|
|
UpdateDocks(scc.Docks);
|
|
UpdateFTL(scc.Destinations, scc.FTLState, scc.FTLTime);
|
|
RadarScreen.UpdateState(scc);
|
|
MaxRadarRange.Text = $"{scc.MaxRange:0}";
|
|
}
|
|
|
|
private void UpdateFTL(List<(NetEntity Entity, string Destination, bool Enabled)> destinations, FTLState state, TimeSpan time)
|
|
{
|
|
HyperspaceDestinations.DisposeAllChildren();
|
|
_destinations.Clear();
|
|
|
|
if (destinations.Count == 0)
|
|
{
|
|
HyperspaceDestinations.AddChild(new Label()
|
|
{
|
|
Text = Loc.GetString("shuttle-console-hyperspace-none"),
|
|
HorizontalAlignment = HAlignment.Center,
|
|
});
|
|
}
|
|
else
|
|
{
|
|
destinations.Sort((x, y) => string.Compare(x.Destination, y.Destination, StringComparison.Ordinal));
|
|
|
|
foreach (var destination in destinations)
|
|
{
|
|
var button = new Button()
|
|
{
|
|
Disabled = !destination.Enabled,
|
|
Text = destination.Destination,
|
|
};
|
|
|
|
_destinations[button] = destination.Entity;
|
|
button.OnPressed += OnHyperspacePressed;
|
|
HyperspaceDestinations.AddChild(button);
|
|
}
|
|
}
|
|
|
|
string stateText;
|
|
|
|
switch (state)
|
|
{
|
|
case Shared.Shuttles.Systems.FTLState.Available:
|
|
stateText = Loc.GetString("shuttle-console-ftl-available");
|
|
break;
|
|
case Shared.Shuttles.Systems.FTLState.Starting:
|
|
stateText = Loc.GetString("shuttle-console-ftl-starting");
|
|
break;
|
|
case Shared.Shuttles.Systems.FTLState.Travelling:
|
|
stateText = Loc.GetString("shuttle-console-ftl-travelling");
|
|
break;
|
|
case Shared.Shuttles.Systems.FTLState.Cooldown:
|
|
stateText = Loc.GetString("shuttle-console-ftl-cooldown");
|
|
break;
|
|
case Shared.Shuttles.Systems.FTLState.Arriving:
|
|
stateText = Loc.GetString("shuttle-console-ftl-arriving");
|
|
break;
|
|
default:
|
|
throw new ArgumentOutOfRangeException(nameof(state), state, null);
|
|
}
|
|
|
|
FTLState.Text = stateText;
|
|
// Add a buffer due to lag or whatever
|
|
time += TimeSpan.FromSeconds(0.3);
|
|
FTLTime = time;
|
|
FTLTimer.Text = GetFTLText();
|
|
}
|
|
|
|
private string GetFTLText()
|
|
{
|
|
return $"{Math.Max(0, (FTLTime - _timing.CurTime).TotalSeconds):0.0}";
|
|
}
|
|
|
|
private void OnHyperspacePressed(BaseButton.ButtonEventArgs obj)
|
|
{
|
|
var ent = _destinations[obj.Button];
|
|
DestinationPressed?.Invoke(ent);
|
|
}
|
|
|
|
#region Docking
|
|
|
|
private void UpdateDocks(List<DockingInterfaceState> docks)
|
|
{
|
|
// TODO: We should check for changes so any existing highlighted doesn't delete.
|
|
// We also need to make up some pseudonumber as well for these.
|
|
_docks.Clear();
|
|
|
|
foreach (var dock in docks)
|
|
{
|
|
var grid = _docks.GetOrNew(dock.Coordinates.NetEntity);
|
|
grid.Add(dock);
|
|
}
|
|
|
|
DockPorts.DisposeAllChildren();
|
|
DockingScreen.Docks = _docks;
|
|
var shuttleNetEntity = _entManager.GetNetEntity(_shuttleEntity);
|
|
|
|
if (shuttleNetEntity != null && _docks.TryGetValue(shuttleNetEntity.Value, out var gridDocks))
|
|
{
|
|
var index = 1;
|
|
|
|
foreach (var state in gridDocks)
|
|
{
|
|
var pressed = state.Entity == DockingScreen.ViewedDock;
|
|
|
|
string suffix;
|
|
|
|
if (state.Connected)
|
|
{
|
|
suffix = Loc.GetString("shuttle-console-docked", ("index", index));
|
|
}
|
|
else
|
|
{
|
|
suffix = $"{index}";
|
|
}
|
|
|
|
var button = new Button()
|
|
{
|
|
Text = Loc.GetString("shuttle-console-dock-button", ("suffix", suffix)),
|
|
ToggleMode = true,
|
|
Pressed = pressed,
|
|
Margin = new Thickness(0f, 1f),
|
|
};
|
|
|
|
if (pressed)
|
|
{
|
|
_selectedDock = button;
|
|
}
|
|
|
|
button.OnMouseEntered += args => OnDockMouseEntered(args, state);
|
|
button.OnMouseExited += args => OnDockMouseExited(args, state);
|
|
button.OnToggled += args => OnDockToggled(args, state);
|
|
DockPorts.AddChild(button);
|
|
index++;
|
|
}
|
|
}
|
|
}
|
|
|
|
private void OnDockMouseEntered(GUIMouseHoverEventArgs obj, DockingInterfaceState state)
|
|
{
|
|
RadarScreen.HighlightedDock = state.Entity;
|
|
}
|
|
|
|
private void OnDockMouseExited(GUIMouseHoverEventArgs obj, DockingInterfaceState state)
|
|
{
|
|
RadarScreen.HighlightedDock = null;
|
|
}
|
|
|
|
/// <summary>
|
|
/// Shows a docking camera instead of radar screen.
|
|
/// </summary>
|
|
private void OnDockToggled(BaseButton.ButtonEventArgs obj, DockingInterfaceState state)
|
|
{
|
|
if (_selectedDock != null)
|
|
{
|
|
// If it got untoggled via other means then we'll stop viewing the old dock.
|
|
if (DockingScreen.ViewedDock != null && DockingScreen.ViewedDock != state.Entity)
|
|
{
|
|
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
|
}
|
|
|
|
_selectedDock.Pressed = false;
|
|
_selectedDock = null;
|
|
}
|
|
|
|
if (!obj.Button.Pressed)
|
|
{
|
|
if (DockingScreen.ViewedDock != null)
|
|
{
|
|
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
|
DockingScreen.ViewedDock = null;
|
|
}
|
|
|
|
UndockButton.Disabled = true;
|
|
DockingScreen.Visible = false;
|
|
RadarScreen.Visible = true;
|
|
}
|
|
else
|
|
{
|
|
if (_shuttleEntity != null)
|
|
{
|
|
DockingScreen.Coordinates = _entManager.GetCoordinates(state.Coordinates);
|
|
DockingScreen.Angle = state.Angle;
|
|
}
|
|
else
|
|
{
|
|
DockingScreen.Coordinates = null;
|
|
DockingScreen.Angle = null;
|
|
}
|
|
|
|
UndockButton.Disabled = false;
|
|
RadarScreen.Visible = false;
|
|
DockingScreen.Visible = true;
|
|
DockingScreen.ViewedDock = state.Entity;
|
|
StartAutodockPressed?.Invoke(state.Entity);
|
|
DockingScreen.GridEntity = _shuttleEntity;
|
|
_selectedDock = obj.Button;
|
|
}
|
|
}
|
|
|
|
public override void Close()
|
|
{
|
|
base.Close();
|
|
if (DockingScreen.ViewedDock != null)
|
|
{
|
|
StopAutodockPressed?.Invoke(DockingScreen.ViewedDock.Value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
|
|
protected override void Draw(DrawingHandleScreen handle)
|
|
{
|
|
base.Draw(handle);
|
|
|
|
if (!_entManager.TryGetComponent<PhysicsComponent>(_shuttleEntity, out var gridBody) ||
|
|
!_entManager.TryGetComponent<TransformComponent>(_shuttleEntity, out var gridXform))
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (_entManager.TryGetComponent<MetaDataComponent>(_shuttleEntity, out var metadata) && metadata.EntityPaused)
|
|
{
|
|
FTLTime += _timing.FrameTime;
|
|
}
|
|
|
|
FTLTimer.Text = GetFTLText();
|
|
|
|
var (_, worldRot, worldMatrix) = gridXform.GetWorldPositionRotationMatrix();
|
|
var worldPos = worldMatrix.Transform(gridBody.LocalCenter);
|
|
|
|
// Get the positive reduced angle.
|
|
var displayRot = -worldRot.Reduced();
|
|
|
|
GridPosition.Text = $"{worldPos.X:0.0}, {worldPos.Y:0.0}";
|
|
GridOrientation.Text = $"{displayRot.Degrees:0.0}";
|
|
|
|
var gridVelocity = gridBody.LinearVelocity;
|
|
gridVelocity = displayRot.RotateVec(gridVelocity);
|
|
// Get linear velocity relative to the console entity
|
|
GridLinearVelocity.Text = $"{gridVelocity.X:0.0}, {gridVelocity.Y:0.0}";
|
|
GridAngularVelocity.Text = $"{-gridBody.AngularVelocity:0.0}";
|
|
}
|
|
}
|