From e9a8302a016b1e64d74b869489483aa5db5ccbf6 Mon Sep 17 00:00:00 2001 From: Jonathan McCaffrey Date: Sat, 3 Oct 2026 03:23:21 +0000 Subject: [PATCH] =?UTF-8?q?AI:=20Loadout=20page=20=E2=80=94=20ZeroSpace/Ze?= =?UTF-8?q?roSpace.Web/Pages/Loadout.razor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ZeroSpace/ZeroSpace.Web/Pages/Loadout.razor | 383 ++++++++++++++++++++ 1 file changed, 383 insertions(+) create mode 100644 ZeroSpace/ZeroSpace.Web/Pages/Loadout.razor diff --git a/ZeroSpace/ZeroSpace.Web/Pages/Loadout.razor b/ZeroSpace/ZeroSpace.Web/Pages/Loadout.razor new file mode 100644 index 0000000..cce4617 --- /dev/null +++ b/ZeroSpace/ZeroSpace.Web/Pages/Loadout.razor @@ -0,0 +1,383 @@ +@page "/loadout" + +Loadout + +
+

Loadout

+
+ Hero: + @foreach (var hero in Heroes) + { + + } +
+
+
+ +
+
+ + +

Faction Powers

+
+ @foreach (var item in FactionPowers) + { +
+ @if (item.ImageUrl is not null) + { + @item.Name + } + else + { + + } + @if (_showDetails) + { +
+
@item.Name
+ @if (item.LimitedToMerc is not null) + { + @item.LimitedToMerc + } +
    + @foreach (var level in item.Levels) + { +
  • @level
  • + } +
+
+ } +
+ } +
+ +

General Items

+
+ @foreach (var item in GeneralItemsList) + { +
+ @if (item.ImageUrl is not null) + { + @item.Name + } + else + { + + } + @if (_showDetails) + { +
+
@item.Name
+ @if (item.LimitedToMerc is not null) + { + @item.LimitedToMerc + } +
    + @foreach (var level in item.Levels) + { +
  • @level
  • + } +
+
+ } +
+ } +
+ +

Master Items

+
+ @foreach (var item in MasterItems) + { +
+ @if (item.ImageUrl is not null) + { + @item.Name + } + else + { + + } + @if (_showDetails) + { +
+
@item.Name
+
    + @foreach (var level in item.Levels) + { +
  • @level
  • + } +
+
+ } +
+ } +
+
+ +
+ @if (_mercError is not null) + { + + } + +

Faction Powers pick up to 4

+
+ @for (var i = 0; i < _factionSlots.Length; i++) + { + var index = i; +
+ @if (_factionSlots[index] is { } slotted) + { + + @if (slotted.ImageUrl is not null) + { + + } + else + { + + } + @slotted.Name + } + else + { + Drop here + } +
+ } +
+ +

General Items pick up to 3

+
+ @for (var i = 0; i < _generalSlots.Length; i++) + { + var index = i; +
+ @if (_generalSlots[index] is { } slotted) + { + + @if (slotted.ImageUrl is not null) + { + + } + else + { + + } + @slotted.Name + } + else + { + Drop here + } +
+ } +
+ +

Master Items pick up to 2

+
+ @for (var i = 0; i < _masterySlots.Length; i++) + { + var index = i; +
+ @if (_masterySlots[index] is { } slotted) + { + + @if (slotted.ImageUrl is not null) + { + + } + else + { + + } + @slotted.Name + } + else + { + Drop here + } +
+ } +
+
+
+ +@code { + private sealed record PoolItem( + string Kind, + string Id, + string Name, + IReadOnlyList Levels, + string? LimitedTo, + string? LimitedToMerc, + string? ImageUrl); + + private static readonly string[] Heroes = ["Vynthra", "Prefect Aster"]; + + private string _hero = Heroes[0]; + private bool _showDetails = true; + private PoolItem? _drag; + + private List _allFactionPowers = []; + private List _allGeneralItems = []; + private List _allMasterItems = []; + + private PoolItem?[] _factionSlots = new PoolItem?[4]; + private PoolItem?[] _generalSlots = new PoolItem?[3]; + private PoolItem?[] _masterySlots = new PoolItem?[2]; + + private readonly HashSet _mercConflicts = []; + private string? _mercError; + + private IEnumerable FactionPowers => + _allFactionPowers.Where(item => item.LimitedTo is null || item.LimitedTo == _hero); + + private IEnumerable GeneralItemsList => _allGeneralItems; + + private IEnumerable MasterItems => _allMasterItems; + + protected override void OnInitialized() + { + _allFactionPowers = FactionPowerItems.All + .Select(item => new PoolItem( + "faction", + item.Id, + item.Name, + item.Levels, + item.LimitedTo, + item.LimitedToMerc, + item.ImageFileName is null ? null : $"images/faction-power-items/{Uri.EscapeDataString(item.ImageFileName)}")) + .ToList(); + + _allGeneralItems = GeneralItems.All + .Select(item => new PoolItem( + "general", + item.Id, + item.Name, + item.Levels, + LimitedTo: null, + item.LimitedToMerc, + item.ImageFileName is null ? null : $"images/general-items/{Uri.EscapeDataString(item.ImageFileName)}")) + .ToList(); + + _allMasterItems = PlanetaryMasteryItems.All + .Select(item => new PoolItem( + "mastery", + item.Id, + item.Name, + item.Levels, + LimitedTo: null, + LimitedToMerc: null, + item.ImageFileName is null ? null : $"images/planetary-mastery-items/{Uri.EscapeDataString(item.ImageFileName)}")) + .ToList(); + } + + private void SelectHero(string hero) + { + if (_hero == hero) + { + return; + } + + _hero = hero; + + // Faction powers are hero-locked: unequip any that belong to another hero. + for (var i = 0; i < _factionSlots.Length; i++) + { + var slotted = _factionSlots[i]; + if (slotted?.LimitedTo is not null && slotted.LimitedTo != _hero) + { + _factionSlots[i] = null; + } + } + + ValidateMercs(); + } + + private void DropFaction(int index) => DropInto(_factionSlots, "faction", index); + private void DropGeneral(int index) => DropInto(_generalSlots, "general", index); + private void DropMastery(int index) => DropInto(_masterySlots, "mastery", index); + + private void DropInto(PoolItem?[] slots, string kind, int index) + { + var dragged = _drag; + _drag = null; + if (dragged is null || dragged.Kind != kind) + { + return; + } + + if (slots.Contains(dragged) || slots[index] is not null) + { + return; + } + + slots[index] = dragged; + ValidateMercs(); + } + + private void RemoveFaction(int index) => RemoveFrom(_factionSlots, index); + private void RemoveGeneral(int index) => RemoveFrom(_generalSlots, index); + private void RemoveMastery(int index) => RemoveFrom(_masterySlots, index); + + private void RemoveFrom(PoolItem?[] slots, int index) + { + slots[index] = null; + ValidateMercs(); + } + + private bool IsConflict(PoolItem? item) => item is not null && _mercConflicts.Contains(item); + + private IEnumerable SlottedItems() => + _factionSlots.Concat(_generalSlots).Concat(_masterySlots).Where(static item => item is not null)!; + + private void ValidateMercs() + { + var mercs = SlottedItems() + .Where(static item => item.LimitedToMerc is not null) + .Select(static item => item.LimitedToMerc!) + .Distinct(StringComparer.OrdinalIgnoreCase) + .ToList(); + + _mercConflicts.Clear(); + if (mercs.Count > 1) + { + foreach (var item in SlottedItems().Where(static item => item.LimitedToMerc is not null)) + { + _mercConflicts.Add(item); + } + + _mercError = "Two items cannot be from different mercs."; + } + else + { + _mercError = null; + } + } +}