Files
ss14-wega/Content.Client/_Wega/ModularSuit/Ui/ModularSuitWindow.xaml.cs
T
2026-06-01 23:58:02 +03:00

387 lines
14 KiB
C#

using System.Numerics;
using Content.Client.Stylesheets;
using Content.Shared.Modular.Suit;
using Robust.Client.AutoGenerated;
using Robust.Client.Graphics;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.CustomControls;
using Robust.Client.UserInterface.XAML;
namespace Content.Client._Wega.ModularSuit.Ui;
[GenerateTypedNameReferences]
public sealed partial class ModularSuitWindow : BaseWindow
{
[Dependency] private IEntityManager _entMan = default!;
private Dictionary<NetEntity, ModuleControl> _moduleControls = new();
private Dictionary<SuitPartType, PartControl> _partControls = new();
public event Action<bool>? OnToggleActive;
public event Action<NetEntity, bool>? OnToggleModule;
public ModularSuitWindow()
{
RobustXamlLoader.Load(this);
IoCManager.InjectDependencies(this);
CloseButton.OnPressed += _ => Close();
ActivateButton.OnToggled += OnActivateToggled;
SetupTabs();
}
private void OnActivateToggled(BaseButton.ButtonToggledEventArgs args)
{
OnToggleActive?.Invoke(args.Pressed);
UpdateTheme(args.Pressed);
}
private void SetupTabs()
{
Tabs.SetTabTitle(0, Loc.GetString("modsuit-tab-modules"));
Tabs.SetTabTitle(1, Loc.GetString("modsuit-tab-parts"));
}
public void UpdateState(ModularSuitBoundUserInterfaceState state)
{
WearerNameLabel.Text = !string.IsNullOrEmpty(state.WearerName)
? state.WearerName : Loc.GetString("modsuit-ui-not-worn");
if (state.HasCore)
{
CoreChargeBar.Value = state.CoreCharge;
CoreChargeBar.MaxValue = state.MaxCoreCharge;
CoreChargeLabel.Text = $"{state.CoreCharge:F0}/{state.MaxCoreCharge:F0}";
}
else
{
CoreChargeBar.Value = 0;
CoreChargeLabel.Text = Loc.GetString("modsuit-ui-no-core");
}
var powerDrawW = state.TotalPowerDraw;
if (powerDrawW > 0 && powerDrawW < 0.01f)
PowerDrawLabel.Text = Loc.GetString("modsuit-ui-power-draw-value", ("power", "<0.01"));
else
PowerDrawLabel.Text = state.InfinityCore
? Loc.GetString("modsuit-ui-power-draw-error")
: Loc.GetString("modsuit-ui-power-draw-value", ("power", Math.Round(powerDrawW, 2)));
if (state.HasBattery && !state.InfinityCore)
{
var batteryPercent = state.BatteryCharge / state.MaxBatteryCharge * 100;
BatteryChargeBar.Value = batteryPercent;
BatteryChargeBar.MaxValue = 100;
BatteryChargeBar.Visible = true;
BatteryChargeLabel.Text = $"{state.BatteryCharge:F0}/{state.MaxBatteryCharge:F0}";
BatteryChargeLabel.Visible = true;
BatteryStatusLabel.Visible = false;
if (powerDrawW > 0)
{
var coreRemainingSec = state.CoreCharge / powerDrawW;
var batteryRemainingSec = state.BatteryCharge / powerDrawW;
var totalRemainingSec = coreRemainingSec + batteryRemainingSec;
if (totalRemainingSec < 60)
{
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-critical", ("seconds", (int)totalRemainingSec));
}
else if (totalRemainingSec < 3600)
{
var minutes = (int)(totalRemainingSec / 60);
var seconds = (int)(totalRemainingSec % 60);
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-minutes", ("minutes", minutes), ("seconds", seconds));
}
else
{
var hours = (int)(totalRemainingSec / 3600);
var minutes = (int)((totalRemainingSec % 3600) / 60);
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-hours", ("hours", hours), ("minutes", minutes));
}
}
else
{
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-infinite");
}
}
else if (state.InfinityCore)
{
BatteryChargeBar.Visible = false;
BatteryChargeLabel.Visible = false;
BatteryStatusLabel.Text = Loc.GetString("modsuit-ui-infinity-core");
BatteryStatusLabel.FontColorOverride = Color.FromHex("#f04c4c");
BatteryStatusLabel.Visible = true;
PowerDrawLabel.Text = Loc.GetString("modsuit-ui-power-draw-error");
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-infinite");
}
else
{
BatteryChargeBar.Visible = false;
BatteryChargeLabel.Visible = false;
BatteryStatusLabel.Text = Loc.GetString("modsuit-ui-no-battery");
BatteryStatusLabel.FontColorOverride = Color.FromHex("#ffaa33");
BatteryStatusLabel.Visible = true;
if (powerDrawW > 0 && state.CoreCharge > 0)
{
var remainingSec = state.CoreCharge / powerDrawW;
if (remainingSec < 60)
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-critical", ("seconds", (int)remainingSec));
else if (remainingSec < 3600)
{
var minutes = (int)(remainingSec / 60);
var seconds = (int)(remainingSec % 60);
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-minutes", ("minutes", minutes), ("seconds", seconds))
+ $" {Loc.GetString("modsuit-ui-time-core")}";
}
else
{
var hours = (int)(remainingSec / 3600);
var minutes = (int)((remainingSec % 3600) / 60);
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-hours", ("hours", hours), ("minutes", minutes))
+ $" {Loc.GetString("modsuit-ui-time-core")}";
}
}
else if (state.CoreCharge <= 0)
{
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-depleted");
}
else
{
RemainingTimeLabel.Text = Loc.GetString("modsuit-ui-time-infinite");
}
}
ActivateButton.Pressed = state.Active;
ActivateButton.Text = state.Active
? Loc.GetString("modsuit-ui-deactivate")
: Loc.GetString("modsuit-ui-activate");
ActivateButton.Disabled = !state.HasCore || state.CoreCharge <= 0;
UpdateTheme(state.Active);
UpdateModules(state.Modules);
UpdateParts(state.Parts);
}
private void UpdateTheme(bool active)
{
var color = active ? Color.FromHex("#4cc9f0") : Color.FromHex("#a8a8a8");
ContentsContainer.Modulate = color.WithAlpha(0.9f);
}
private void UpdateModules(List<SuitModuleEntry> modules)
{
ModulesCountLabel.Text = modules.Count.ToString();
ModulesContainer.Children.Clear();
_moduleControls.Clear();
if (modules.Count == 0)
{
var emptyLabel = new Label
{
Text = Loc.GetString("modsuit-ui-no-modules"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
FontColorOverride = Color.FromHex("#8ecae6"),
Margin = new Thickness(0, 20)
};
ModulesContainer.AddChild(emptyLabel);
return;
}
foreach (var module in modules)
{
var control = new ModuleControl(module, _entMan);
control.OnToggle += active => OnToggleModule?.Invoke(module.ModuleUid, active);
ModulesContainer.AddChild(control);
_moduleControls[module.ModuleUid] = control;
}
}
private void UpdateParts(List<SuitPartEntry> parts)
{
PartsCountLabel.Text = parts.Count.ToString();
PartsContainer.Children.Clear();
_partControls.Clear();
if (parts.Count == 0)
{
var emptyLabel = new Label
{
Text = Loc.GetString("modsuit-ui-no-parts"),
HorizontalAlignment = HAlignment.Center,
VerticalAlignment = VAlignment.Center,
FontColorOverride = Color.FromHex("#8ecae6"),
Margin = new Thickness(0, 20)
};
PartsContainer.AddChild(emptyLabel);
return;
}
foreach (var part in parts)
{
var control = new PartControl(part, _entMan);
PartsContainer.AddChild(control);
_partControls[part.PartType] = control;
}
}
protected override DragMode GetDragModeFor(Vector2 relativeMousePos) => DragMode.Move;
}
public sealed class ModuleControl : PanelContainer
{
private readonly CheckBox? _toggleButton;
public event Action<bool>? OnToggle;
public ModuleControl(SuitModuleEntry module, IEntityManager entMan)
{
HorizontalExpand = true;
MinHeight = 48;
Margin = new Thickness(0, 2);
PanelOverride = new StyleBoxFlat
{
BackgroundColor = Color.FromHex("#1e2b3c"),
BorderColor = module.IsPermanent
? Color.FromHex("#f04c4c")
: (module.IsActive || !module.CanBeDisabled
? Color.FromHex("#4cc9f0")
: Color.FromHex("#3a4a5a")),
BorderThickness = new Thickness(1),
ContentMarginBottomOverride = 4,
ContentMarginLeftOverride = 6,
ContentMarginRightOverride = 6,
ContentMarginTopOverride = 4
};
var container = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
VerticalAlignment = VAlignment.Center
};
var view = new SpriteView
{
OverrideDirection = Direction.South,
Scale = new Vector2(2, 2),
MinSize = new Vector2(32, 32),
Margin = new Thickness(0, 0, 8, 0),
VerticalAlignment = VAlignment.Center
};
view.SetEntity(entMan.GetEntity(module.ModuleUid));
container.AddChild(view);
var infoContainer = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Vertical,
HorizontalExpand = true,
SeparationOverride = 2
};
var nameLabel = new Label
{
Text = $"{module.Name} #{module.ModuleId}",
FontColorOverride = module.IsActive ? Color.FromHex("#ffffff") : Color.FromHex("#a8a8a8"),
HorizontalExpand = true
};
infoContainer.AddChild(nameLabel);
var powerText = module.PowerUsage > 0
? Loc.GetString("modsuit-ui-power-usage", ("power", Math.Round(module.PowerUsage, 3)))
: Loc.GetString("modsuit-ui-no-power-usage");
if (module.PowerInstanceUsage > 0)
{
powerText += $"\n{Loc.GetString("modsuit-ui-power-instance-usage", ("power", Math.Round(module.PowerInstanceUsage, 3)))}";
}
var powerLabel = new Label
{
Text = powerText,
FontColorOverride = Color.FromHex("#aaccff"),
HorizontalExpand = true
};
powerLabel.AddStyleClass(StyleClass.LabelSubText);
infoContainer.AddChild(powerLabel);
container.AddChild(infoContainer);
if (module.CanBeDisabled)
{
_toggleButton = new CheckBox
{
Pressed = module.IsActive,
MinSize = new Vector2(40, 0),
VerticalAlignment = VAlignment.Center,
Margin = new Thickness(8, 0, 0, 0)
};
_toggleButton.OnToggled += args => OnToggle?.Invoke(args.Pressed);
container.AddChild(_toggleButton);
}
AddChild(container);
}
}
public sealed class PartControl : PanelContainer
{
public PartControl(SuitPartEntry part, IEntityManager entMan)
{
HorizontalExpand = true;
MinHeight = 48;
Margin = new Thickness(0, 2);
PanelOverride = new StyleBoxFlat
{
BackgroundColor = Color.FromHex("#1e2b3c"),
BorderColor = Color.FromHex("#ffaa33"),
BorderThickness = new Thickness(1),
ContentMarginBottomOverride = 4,
ContentMarginLeftOverride = 6,
ContentMarginRightOverride = 6,
ContentMarginTopOverride = 4
};
var container = new BoxContainer
{
Orientation = BoxContainer.LayoutOrientation.Horizontal,
HorizontalExpand = true,
VerticalAlignment = VAlignment.Center
};
var view = new SpriteView
{
OverrideDirection = Direction.South,
Scale = new Vector2(2, 2),
MinSize = new Vector2(32, 32),
Margin = new Thickness(0, 0, 8, 0),
VerticalAlignment = VAlignment.Center
};
view.SetEntity(entMan.GetEntity(part.PartUid));
container.AddChild(view);
var partName = Loc.GetString($"modsuit-part-{part.PartType.ToString().ToLower()}");
var nameLabel = new Label
{
Text = partName,
FontColorOverride = Color.FromHex("#ffffff"),
HorizontalExpand = true,
VerticalAlignment = VAlignment.Center
};
container.AddChild(nameLabel);
AddChild(container);
}
}